Expose diving hyper parameters#1364
Conversation
…udo_costs, worker and diving_heuristics. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
📝 WalkthroughWalkthroughThis PR centralizes MIP diving hyperparameters into a templated ChangesDiving Heuristic Parameters
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp (1)
8-8: ⚡ Quick winUse a macro guard here instead of only
#pragma once.The new C++ header does not follow the repository header-guard convention. Please add a normal
#defineguard and keep#pragma onceonly if you want it as a secondary optimization.As per coding guidelines, "Use
#defineguards on C++ headers".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp` at line 8, The header currently only has `#pragma once`; add a standard include guard macro around the file to follow project convention: introduce a unique macro like CPP_INCLUDE_CUOPT_LINEAR_PROGRAMMING_MIP_DIVING_HYPER_PARAMS_HPP (or similar uppercase, path-based name) with `#ifndef ... `#define` ...` at the top and a matching `#endif` at the bottom of diving_hyper_params.hpp, keeping `#pragma once` if you want it as a secondary optimization; ensure the macro name is unique and consistent with other headers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpp/src/branch_and_bound/branch_and_bound.cpp`:
- Around line 1758-1760: The code unconditionally sets
diving_settings.guided_diving = 1 before calling
worker->calculate_num_diving_workers(...), overwriting the caller's intended
mode; change this to preserve and reuse the original mode by assigning
diving_settings.guided_diving = settings_.diving_settings.guided_diving (so
guided_diving keeps -1 for automatic or 1 for enabled) before invoking
worker->calculate_num_diving_workers.
In `@cpp/src/branch_and_bound/diving_heuristics.hpp`:
- Around line 42-43: The declaration of is_search_strategy_enabled in
diving_heuristics.hpp uses the type mip_diving_hyper_params_t but the header
doesn't directly include the header that defines that type; make the header
self-contained by adding an `#include` for the header that introduces
mip_diving_hyper_params_t (the file that defines the mip_diving_hyper_params_t
type) to diving_heuristics.hpp so the declaration compiles without relying on
transitive includes.
In `@cpp/src/math_optimization/solver_settings.cu`:
- Around line 118-119: The registration passes
&mip_settings.diving_params.iteration_limit_factor (declared as double in
diving_hyper_params.hpp) into a parameter_info_t<f_t> (used by
solver_settings_t<int, float>), causing a double* vs float* mismatch; fix by
changing the type of iteration_limit_factor in diving_hyper_params.hpp to f_t so
it matches parameter_info_t<f_t>, or alternatively add a specialized
registration path that accepts a double-typed parameter (i.e., a
parameter_info_t<double> entry) for
CUOPT_MIP_HYPER_DIVING_ITERATION_LIMIT_FACTOR and ensure solver_settings
registration logic handles that specialization.
---
Nitpick comments:
In `@cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp`:
- Line 8: The header currently only has `#pragma once`; add a standard include
guard macro around the file to follow project convention: introduce a unique
macro like CPP_INCLUDE_CUOPT_LINEAR_PROGRAMMING_MIP_DIVING_HYPER_PARAMS_HPP (or
similar uppercase, path-based name) with `#ifndef ... `#define` ...` at the top
and a matching `#endif` at the bottom of diving_hyper_params.hpp, keeping
`#pragma once` if you want it as a secondary optimization; ensure the macro name
is unique and consistent with other headers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 877a2203-2924-4ddf-bcb2-d88a2e40efd0
📒 Files selected for processing (11)
cpp/include/cuopt/linear_programming/constants.hcpp/include/cuopt/linear_programming/mip/diving_hyper_params.hppcpp/include/cuopt/linear_programming/mip/solver_settings.hppcpp/src/branch_and_bound/branch_and_bound.cppcpp/src/branch_and_bound/diving_heuristics.cppcpp/src/branch_and_bound/diving_heuristics.hppcpp/src/branch_and_bound/pseudo_costs.hppcpp/src/branch_and_bound/worker.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/math_optimization/solver_settings.cucpp/src/mip_heuristics/solver.cu
…derabbit comments. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
cpp/src/branch_and_bound/branch_and_bound.cpp (1)
1755-1761:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPreserve the original guided-diving mode when re-enabling.
Line 1758 hardcodes
diving_settings.guided_diving = 1, but the original setting might have been-1(automatic) rather than1(enabled). Restoring the original value fromsettings_.diving_settings.guided_divingpreserves the caller's intended mode.Suggested fix
- diving_settings.guided_diving = 1; + diving_settings.guided_diving = settings_.diving_settings.guided_diving;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/src/branch_and_bound/branch_and_bound.cpp` around lines 1755 - 1761, The code currently forces diving_settings.guided_diving = 1 when re-enabling guided diving; instead restore the original mode from settings_.diving_settings.guided_diving so automatic (-1) vs enabled (1) is preserved. Update the block that checks diving_worker_pool_.size() and settings_.diving_settings.guided_diving to assign diving_settings.guided_diving = settings_.diving_settings.guided_diving (not literal 1) before calling worker->calculate_num_diving_workers(bfs_worker_pool_.size(), diving_worker_pool_.size(), diving_settings), keeping the has_solver_space_incumbent() check unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@cpp/src/branch_and_bound/branch_and_bound.cpp`:
- Around line 1755-1761: The code currently forces diving_settings.guided_diving
= 1 when re-enabling guided diving; instead restore the original mode from
settings_.diving_settings.guided_diving so automatic (-1) vs enabled (1) is
preserved. Update the block that checks diving_worker_pool_.size() and
settings_.diving_settings.guided_diving to assign diving_settings.guided_diving
= settings_.diving_settings.guided_diving (not literal 1) before calling
worker->calculate_num_diving_workers(bfs_worker_pool_.size(),
diving_worker_pool_.size(), diving_settings), keeping the
has_solver_space_incumbent() check unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 69c1430e-729e-4b5e-ab18-aa8abd5151ec
📒 Files selected for processing (10)
cpp/include/cuopt/linear_programming/constants.hcpp/include/cuopt/linear_programming/mip/diving_hyper_params.hppcpp/include/cuopt/linear_programming/mip/heuristics_hyper_params.hppcpp/include/cuopt/linear_programming/mip/solver_settings.hppcpp/src/branch_and_bound/branch_and_bound.cppcpp/src/branch_and_bound/diving_heuristics.hppcpp/src/branch_and_bound/worker.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/math_optimization/solver_settings.cucpp/tests/mip/heuristics_hyper_params_test.cu
✅ Files skipped from review due to trivial changes (1)
- cpp/src/math_optimization/solver_settings.cu
🚧 Files skipped from review as they are similar to previous changes (5)
- cpp/src/branch_and_bound/diving_heuristics.hpp
- cpp/include/cuopt/linear_programming/mip/solver_settings.hpp
- cpp/include/cuopt/linear_programming/constants.h
- cpp/src/dual_simplex/simplex_solver_settings.hpp
- cpp/src/branch_and_bound/worker.hpp
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp (2)
22-26: ⚡ Quick winAdd per-member documentation for heuristic enable flags.
The tri-state semantics (-1 automatic, 0 disabled, 1 enabled) are documented only in a single-line comment. For a public API, consider adding inline documentation for each flag explaining what "automatic" mode does for that specific heuristic.
📝 Example documentation pattern
- // -1 automatic, 0 disabled, 1 enabled - i_t line_search_diving = -1; + /// Enable line-search diving heuristic: -1 (automatic, enabled based on problem characteristics), 0 (disabled), 1 (enabled). + i_t line_search_diving = -1;As per coding guidelines, public C++ headers should document algorithm parameters clearly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp` around lines 22 - 26, Add inline Doxygen-style comments for each public member (line_search_diving, pseudocost_diving, guided_diving, coefficient_diving) that state the tri-state semantics (-1 = automatic, 0 = disabled, 1 = enabled) and briefly explain what "automatic" chooses for that specific heuristic (e.g., select based on problem size/LP relaxation info, use historical pseudocosts, enable guided branching when strong inference exists, or pick coefficient-based rules respectively). Place these short comments immediately above each member declaration in diving_hyper_params.hpp so the public API documents behavior per-flag.
12-21: ⚡ Quick winDocument template parameters.
The template parameters
i_tandf_tare not documented. Consider adding@tparamtags to clarify expected types and constraints (e.g.,i_tmust be a signed integer type to support the -1 automatic mode).📝 Suggested documentation enhancement
/** * `@brief` Tuning knobs for the dual-simplex diving heuristics used in MIP B&B. * + * `@tparam` i_t Signed integer type for counts, limits, and tri-state flags. + * `@tparam` f_t Floating-point type for scaling factors. + * * Used directly as simplex_solver_settings_t::diving_settings and copied intoAs per coding guidelines, public C++ headers should document parameters and types for API clarity.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp` around lines 12 - 21, Add Doxygen `@tparam` documentation for the template parameters on the mip_diving_hyper_params_t template: document i_t as the integer index/size type (must be a signed integer type because -1 is used for "automatic" mode) and document f_t as the floating-point type used for numeric thresholds/weights (e.g., double/float). Place the `@tparam` entries in the existing comment block immediately above the template<typename i_t, typename f_t> struct mip_diving_hyper_params_t so the API docs clearly state the expected types and any constraints.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hpp`:
- Around line 22-26: Add inline Doxygen-style comments for each public member
(line_search_diving, pseudocost_diving, guided_diving, coefficient_diving) that
state the tri-state semantics (-1 = automatic, 0 = disabled, 1 = enabled) and
briefly explain what "automatic" chooses for that specific heuristic (e.g.,
select based on problem size/LP relaxation info, use historical pseudocosts,
enable guided branching when strong inference exists, or pick coefficient-based
rules respectively). Place these short comments immediately above each member
declaration in diving_hyper_params.hpp so the public API documents behavior
per-flag.
- Around line 12-21: Add Doxygen `@tparam` documentation for the template
parameters on the mip_diving_hyper_params_t template: document i_t as the
integer index/size type (must be a signed integer type because -1 is used for
"automatic" mode) and document f_t as the floating-point type used for numeric
thresholds/weights (e.g., double/float). Place the `@tparam` entries in the
existing comment block immediately above the template<typename i_t, typename
f_t> struct mip_diving_hyper_params_t so the API docs clearly state the expected
types and any constraints.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: c64e4a8f-3405-47c1-a6e9-11eff3ac628b
📒 Files selected for processing (2)
cpp/include/cuopt/linear_programming/mip/diving_hyper_params.hppcpp/src/branch_and_bound/diving_heuristics.hpp
🚧 Files skipped from review as they are similar to previous changes (1)
- cpp/src/branch_and_bound/diving_heuristics.hpp
|
/merge |
Implemented Farkas [1] and vector length [Section 9.2.6, 2] diving heuristics. It includes #1364. Farkas diving is designed to move the current LP relaxation in direction to a valid Farkas proof. It pushes all variables towards the so-called pseudo solution, in which each variable assumes the best bound with respect to its objective coefficient as the solution value. Generally, this is very optimistic and most of the time, it will violate the constraints of the problem. Yet, if this finds a feasible solution, then it is expected to be very good. Vector length diving is tailored for set partitioning and set covering. It chooses a rounding that coverst the largest number of constraints with the smallest objective value deterioration. ## Benchmark Results MIPLIB2017, 10min, GH200 ### All ``` ================================================================================ main-2026-06-01 (1) vs new-diving-heuristics (2) ================================================================================ ------------------------------------------------------------------------------------------------------------------------------ | | Run 1 | Run 2 | Abs. Diff. | Rel. Diff. (%) | ------------------------------------------------------------------------------------------------------------------------------ | Imported 240 240 +0 --- | | Feasible 226 227 +1 --- | | Optimal 83 84 +1 --- | | Solutions with <0.1% primal gap 134 139 +5 --- | | Nodes explored (mean) 1.329e+07 1.295e+07 -3.335e+05 -2.51 | | Nodes explored (shifted geomean) 1.426e+04 1.372e+04 -539.2 -3.78 | | Relative MIP gap (mean) 0.2893 0.2854 -0.003857 -1.33 | | Relative MIP gap (shifted geomean) 0.09705 0.09449 -0.002568 -2.65 | | Solve time (mean) 426.6 428.7 +2.022 +0.474 | | Solve time (shifted geomean) 202.4 207.1 +4.726 +2.33 | | Primal gap (mean) 11.31 10.89 -0.4276 -3.78 | | Primal gap (shifted geomean) 0.5319 0.4957 -0.03619 -6.8 | | Primal integral (mean) 32.45 31.21 -1.242 -3.83 | | Primal integral (shifted geomean) 6.582 6.147 -0.4357 -6.62 | ------------------------------------------------------------------------------------------------------------------------------ ``` ### Vector length diving ``` ================================================================================ main-2026-06-01 (1) vs vector-length-diving (2) ================================================================================ ------------------------------------------------------------------------------------------------------------------------------ | | Run 1 | Run 2 | Abs. Diff. | Rel. Diff. (%) | ------------------------------------------------------------------------------------------------------------------------------ | Imported 240 240 +0 --- | | Feasible 226 228 +2 --- | | Optimal 83 84 +1 --- | | Solutions with <0.1% primal gap 134 136 +2 --- | | Nodes explored (mean) 1.329e+07 1.285e+07 -4.331e+05 -3.26 | | Nodes explored (shifted geomean) 1.426e+04 1.312e+04 -1134 -7.95 | | Relative MIP gap (mean) 0.2893 0.3086 +0.01929 +6.67 | | Relative MIP gap (shifted geomean) 0.09705 0.09751 +0.000458 +0.472 | | Solve time (mean) 426.6 421.3 -5.318 -1.25 | | Solve time (shifted geomean) 202.4 195.7 -6.75 -3.33 | | Primal gap (mean) 11.31 10.47 -0.8411 -7.43 | | Primal gap (shifted geomean) 0.5319 0.5132 -0.01875 -3.53 | | Primal integral (mean) 32.45 33.07 +0.6235 +1.92 | | Primal integral (shifted geomean) 6.582 6.62 +0.03761 +0.571 | ------------------------------------------------------------------------------------------------------------------------------ ``` ### Farkas diving ``` ================================================================================ main-2026-06-01 (1) vs farkas-diving (2) ================================================================================ ------------------------------------------------------------------------------------------------------------------------------ | | Run 1 | Run 2 | Abs. Diff. | Rel. Diff. (%) | ------------------------------------------------------------------------------------------------------------------------------ | Imported 240 240 +0 --- | | Feasible 226 228 +2 --- | | Optimal 83 84 +1 --- | | Solutions with <0.1% primal gap 134 132 -2 --- | | Nodes explored (mean) 1.329e+07 1.322e+07 -6.36e+04 -0.479 | | Nodes explored (shifted geomean) 1.426e+04 1.436e+04 +107.1 +0.751 | | Relative MIP gap (mean) 0.2893 0.291 +0.001754 +0.606 | | Relative MIP gap (shifted geomean) 0.09705 0.09512 -0.001935 -1.99 | | Solve time (mean) 426.6 429.4 +2.721 +0.638 | | Solve time (shifted geomean) 202.4 205.5 +3.1 +1.53 | | Primal gap (mean) 11.31 10.46 -0.8573 -7.58 | | Primal gap (shifted geomean) 0.5319 0.5099 -0.02204 -4.14 | | Primal integral (mean) 32.45 33.11 +0.6652 +2.05 | | Primal integral (shifted geomean) 6.582 6.342 -0.2408 -3.66 | ------------------------------------------------------------------------------------------------------------------------------ ``` ## References [1] J. Witzig and A. Gleixner, “Conflict-Driven Heuristics for Mixed Integer Programming,” Feb. 07, 2019, arXiv: arXiv:1902.02615. doi: [10.48550/arXiv.1902.02615](https://doi.org/10.48550/arXiv.1902.02615). [2] T. Achterberg, “Constraint Integer Programming,” PhD, Technischen Universität Berlin, Berlin, 2007. doi: [10.14279/depositonce-1634](https://doi.org/10.14279/depositonce-1634). Authors: - Nicolas L. Guidotti (https://github.com/nguidotti) Approvers: - Akif ÇÖRDÜK (https://github.com/akifcorduk) - Chris Maes (https://github.com/chris-maes) URL: #1401
Similar to #993, this PR exposes the diving hyper parameters to
cuopt_cliand to the public API in order to be easier to tune. They are hidden by default incuopt_cli.Checklist