-
Notifications
You must be signed in to change notification settings - Fork 112
Master-Worker Framework for B&B #754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
… on the objective pseudcost estimate.
… on the objective pseudcost estimate.
…iteration and node limit to the diving threads.
|
Awesome work getting this pushed so soon Nicolas :) |
📝 WalkthroughWalkthroughIntroduces a multi-worker, per-type branch-and-bound architecture with worker pool and node-queue, adds diving heuristics, makes basis repair and refactor bounds-aware, changes bounds-strengthening API, extends pseudo-costs API, and updates numerous call sites and settings to support concurrent diving strategies and revised LP/node handling. Changes
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
cpp/src/utilities/omp_helpers.hpp (1)
45-62: Makeoperator T()const to align withload() const(avoids const-read compilation failures).
Right now,const omp_atomic_t<T>can callload()but cannot use implicit conversion (Line 45), which is a surprising footgun given the change at Line 56.Proposed fix
- operator T() { return load(); } + operator T() const { return load(); }cpp/src/dual_simplex/pseudo_costs.cpp (1)
256-317: Potential out-of-bounds access whenfractionalis empty.Static analysis flagged line 314: if
fractionalis empty, the loop on lines 303-309 never executes, leavingselect = -1. The subsequent accessscore[select]would be undefined behavior.🐛 Suggested guard for empty input
template <typename i_t, typename f_t> i_t pseudo_costs_t<i_t, f_t>::variable_selection(const std::vector<i_t>& fractional, const std::vector<f_t>& solution, logger_t& log) { std::lock_guard<omp_mutex_t> lock(mutex); const i_t num_fractional = fractional.size(); + if (num_fractional == 0) { + log.debug("No fractional variables for pseudocost branching\n"); + return -1; + } std::vector<f_t> pseudo_cost_up(num_fractional);cpp/src/dual_simplex/branch_and_bound.cpp (3)
518-543: Avoid callingget_lower_bound()while holdingmutex_upper_(lock-ordering risk).
add_feasible_solution()holdsmutex_upper_and callsreport(... get_lower_bound() ...), whereget_lower_bound()locksnode_queue. If any other path ever locksnode_queuethen tries to lockmutex_upper_, you have a deadlock hazard. Safer: update upper bound under lock, then compute/report outside.
545-605: Fix Martin's criteria to compute distances from current solution, not root solution bounds.In the
martin_criteriafunction, the bounds should be computed fromval(the current node solution), notroot_val(the root LP solution). The current implementation usesfloor(root_val)andceil(root_val)for bounds, but distances asval - down_valandup_val - val. This causes incorrect rounding preference when the current solution drifts from the root solution by more than 1.Replace lines 552-553:
const f_t down_val = std::floor(val); const f_t up_val = std::ceil(val);This aligns with all other rounding distance calculations in the codebase (pseudo_costs.cpp, diving_heuristics.cpp), which correctly compute fractional distances as
solution - floor(solution)andceil(solution) - solution.
607-792: Type mismatch in iteration-limit assignment: floating-point to integral conversion without precision guardrail.Line 633 computes
max_iter - stats.total_lp_iters(bothf_t) and assigns tolp_settings.iteration_limit(typei_t). Additionally,total_lp_itersis stored asomp_atomic_t<f_t>(line 41, bnb_worker.hpp), which is semantically unusual for iteration counts.The check at line 634 guards against negative results but does not account for floating-point truncation during the
f_t→i_timplicit conversion. Consider:
- Either store
total_lp_itersasi_t(the natural type for iteration counts), or- Explicitly cast and validate the truncated result before assignment (e.g., ensure the converted value matches the floating-point value within an acceptable tolerance).
The per-worker iteration budget is correctly synchronized via atomic updates (line 697).
cpp/src/dual_simplex/branch_and_bound.hpp (1)
10-22: Delete copy and move semantics forbranch_and_bound_tto prevent unsafe mutex/atomic sharing.The class contains
omp_mutex_tmembers (mutex_upper_,mutex_repair_) and atomic state (upper_bound_,solver_status_, etc.) that manage critical parallel resources. Whileomp_mutex_tandomp_atomic_tare properly default-constructible, they require unique ownership. Without explicit deletion of copy/move operations, shallow copies would cause:
- Multiple instances sharing the same underlying
omp_lock_t- Double-destruction of locks when copies are destroyed
- Race conditions and undefined behavior in multi-threaded contexts
Add to the class definition:
branch_and_bound_t(const branch_and_bound_t&) = delete; branch_and_bound_t& operator=(const branch_and_bound_t&) = delete; branch_and_bound_t(branch_and_bound_t&&) = delete; branch_and_bound_t& operator=(branch_and_bound_t&&) = delete;cpp/src/dual_simplex/phase2.cpp (1)
621-651: Fix inconsistent primal infeasibility bookkeeping (mixing "sum" and "sum of squares").
compute_initial_primal_infeasibilities()returnsprimal_inf_squared(sum of squared infeasibilities) but outputs via referenceprimal_infas the sum of unsquared infeasibilities. Later,update_single_primal_infeasibility()at line 2851 receivesprimal_infeasibility(unsquared) but treats it as a squared sum by performingprimal_inf += (new_val - old_val)where bothnew_valandold_valare squared values. This corruptsprimal_infeasibility, which is then used for pricing decisions, termination checks, and recompute conditions.In contrast,
update_primal_infeasibilities()(lines 2828, 2840) correctly receivesprimal_infeasibility_squaredand handles squared values throughout.One way to fix (track both consistently)
-void update_single_primal_infeasibility(..., f_t& primal_inf) +void update_single_primal_infeasibility(..., f_t& primal_inf, f_t& primal_inf_squared) { const f_t old_val = squared_infeasibilities[j]; + const f_t old_infeas = old_val > 0 ? std::sqrt(old_val) : 0.0; @@ const f_t new_val = infeas * infeas; if (infeas > primal_tol) { - primal_inf = std::max(0.0, primal_inf + (new_val - old_val)); + primal_inf_squared = std::max(0.0, primal_inf_squared + (new_val - old_val)); + primal_inf = std::max(0.0, primal_inf + (infeas - old_infeas)); @@ squared_infeasibilities[j] = new_val; } else { if (old_val != 0.0) { - primal_inf = std::max(0.0, primal_inf - old_val); + primal_inf_squared = std::max(0.0, primal_inf_squared - old_val); + primal_inf = std::max(0.0, primal_inf - old_infeas); squared_infeasibilities[j] = 0.0; } } }Then pass both refs through call sites (line 2851 and any others).
Also applies to: 653-692, 2365-2373, 2815-2860
🤖 Fix all issues with AI agents
In @cpp/src/dual_simplex/bnb_worker.hpp:
- Around line 15-225: The loop in bnb_get_num_workers_round_robin can divide by
zero because m = worker_types.size() - 1 may be 0 when only EXPLORATION is
enabled; fix by computing m and if m==0 skip the diving-worker distribution loop
(or set diving_workers=0) so the for-loop that uses (diving_workers / m) is not
executed, ensuring max_num_workers remains valid (keep EXPLORATION assignment as
is and only distribute diving_workers when worker_types.size() > 1).
- Around line 15-225: The header is missing direct includes for std::array and
std::lock_guard; add #include <array> and #include <mutex> at the top of the
file so symbols used throughout compile cleanly. Locate the top includes near
the existing <deque> and <vector> and add these two includes; this will fix
usages of std::array in bnb_get_num_workers_round_robin and std::lock_guard in
bnb_worker_pool_t methods (get_idle_worker, pop_idle_worker,
get_and_pop_idle_worker, return_worker_to_pool).
In @cpp/src/dual_simplex/branch_and_bound.cpp:
- Around line 1231-1234: The loop exit condition only checks
active_workers_per_type[0], missing other worker types; update the while
condition so it considers any active worker by checking the sum or any nonzero
entry of active_workers_per_type (e.g., replace "active_workers_per_type[0] > 0"
with a test that sums the vector or uses std::any_of), keeping the existing
checks on solver_status_, abs_gap vs settings_.absolute_mip_gap_tol, rel_gap vs
settings_.relative_mip_gap_tol, and node_queue.best_first_queue_size() to ensure
the loop continues while any worker type is active or nodes remain.
- Around line 271-292: In report(...) fix two UB sources: ensure integer prints
use a fixed signed width by casting exploration_stats_.nodes_explored and
exploration_stats_.nodes_unexplored to a known signed integer type (e.g., long
long) and switch the printf specifiers accordingly (use %lld or equivalent), and
guard the division compute of iter_node by checking nodes_explored != 0 before
doing iter_node = exploration_stats_.total_lp_iters / nodes_explored (set
iter_node to 0 or a safe sentinel when nodes_explored is 0). Reference: function
branch_and_bound_t::report, variables nodes_explored, nodes_unexplored,
iter_node, and exploration_stats_.total_lp_iters.
- Around line 1217-1363: The OpenMP affinity clause and taskyield behavior used
around the pragmas that launch tasks for plunge_with and dive_with can be
unsupported or incomplete on some libgomp/libomp versions; update the code to
either (a) compile-conditionally omit the affinity clause and/or taskyield
semantics when building with known-broken GCC/libgomp versions (detect via
predefined macros or a CMake feature test for OpenMP 5.0 affinity/taskyield
support), or (b) add a clear runtime/build-time check and fallback (keep the
current std::this_thread::sleep_for fallback) and document the limitation for
GCC users; reference the pragmas using the affinity(worker) lines that wrap
plunge_with(worker) and dive_with(worker) and the sleep fallback around
launched_any_task to implement the conditional removal/fallback and add the
documented note.
In @cpp/src/dual_simplex/branch_and_bound.hpp:
- Around line 150-172: The comment for min_node_queue_size_ is unclear and has a
typo; update the comment on the member variable min_node_queue_size_ to fix
grammar and explicitly state that this threshold both determines when the
ramp-up phase is considered complete and controls where newly generated child
nodes are placed (if queue size < min_node_queue_size_ children are pushed to
the global node_queue, otherwise they are pushed onto the local DFS stack).
Ensure the revised comment replaces the “Minimum number of node… less than than”
text and mentions the two responsibilities (ramp-up completion and child
placement).
In @cpp/src/dual_simplex/diving_heuristics.cpp:
- Around line 199-227: calculate_variable_locks is reading constraint row
indices (nz_row from lp_problem.A.i[k]) but then uses lp_problem.upper/lower
(which are variable bounds) causing wrong semantics; fix by either (A) extending
lp_problem_t to include constraint bounds (e.g., row_lower and row_upper) and
replace accesses to lp_problem.upper[nz_row]/lp_problem.lower[nz_row] with
lp_problem.row_upper[nz_row]/lp_problem.row_lower[nz_row] inside
calculate_variable_locks, or (B) if constraint bounds are not available by
design, rewrite the locking logic in calculate_variable_locks to rely only on
available constraint data (e.g., rhs or sign-only logic from lp_problem.A.x and
rhs) and remove any indexing into variable bounds using nz_row; update all call
sites and tests to reflect the new lp_problem_t fields or the refactored logic
accordingly.
- Around line 1-10: The translation unit uses std::tuple<i_t, i_t> but does not
include <tuple>, so add the missing include: insert #include <tuple> at the top
of cpp/src/dual_simplex/diving_heuristics.cpp (near the other includes) so that
the use of std::tuple<i_t, i_t> (around the tuple usage at line ~200) is
properly declared; no other changes are required (OpenMP mutex usage with
std::lock_guard<omp_mutex_t> can remain as-is).
In @cpp/src/dual_simplex/node_queue.hpp:
- Around line 8-61: This header is missing direct standard includes and misuses
std::forward; add the proper headers (<optional>, <memory>, <utility>, <mutex>)
at the top so symbols like std::optional, std::shared_ptr, std::make_shared,
std::lock_guard, std::forward and std::exchange are declared, and fix the
emplace template to call std::forward<Args>(args)... instead of
std::forward<Args&&>(args)...; update heap_t::emplace and add the includes so
the header builds in non-unity/modular builds.
🧹 Nitpick comments (3)
cpp/src/dual_simplex/basis_solves.cpp (1)
663-671: LGTM! Bounds-aware variable status assignment.The logic correctly assigns the status for replaced nonbasic variables:
- Free variables (both bounds infinite) →
NONBASIC_FREE- Lower-bounded →
NONBASIC_LOWER(preferred when both bounds exist)- Upper-bounded only →
NONBASIC_UPPERThe
assert(1 == 0)serves as a defensive guard for an unreachable case.As per coding guidelines, validate correct initialization of variable bounds. Consider using a more descriptive assertion message or
assert(false && "Unreachable: variable must have at least one bound or be free").♻️ Optional: More descriptive assertion
} else { - assert(1 == 0); + assert(false && "Unreachable: variable must have at least one bound or be free"); }cpp/src/dual_simplex/presolve.cpp (1)
623-634: Note: Dead code due to compile-time constant.Line 623 sets
run_bounds_strengtheningtofalse, and line 624 usesif constexpr, making this entire block unreachable at compile time. If bounds strengthening is intended to be disabled, consider removing the code or documenting why it's preserved.The implementation itself is correct: initializing all entries in bounds_changed to
trueis appropriate for presolve where all bounds should be checked, and the new API is used correctly.cpp/src/dual_simplex/diving_heuristics.hpp (1)
10-48: Reduce header coupling: drop unused includes / include what you use.
diving_heuristics.hppdeclares APIs but includes heavy solver headers (basis_updates.hpp,bounds_strengthening.hpp). Consider replacing with minimal includes (or forward declarations) so this header doesn’t force large recompiles. Based on learnings, reduce tight coupling between solver components.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/diving_queue.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/mip/diversity/lns/rins.cucpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/solver.cucpp/src/utilities/omp_helpers.hpp
💤 Files with no reviewable changes (1)
- cpp/src/dual_simplex/diving_queue.hpp
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{cu,cuh,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh,cpp,hpp,h}: Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Check that hard-coded GPU de...
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/mip/diversity/lns/rins.cucpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
**/*.{h,hpp,py}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Verify C API does not break ABI stability (no struct layout changes, field reordering); maintain backward compatibility in Python and server APIs with deprecation warnings
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/utilities/omp_helpers.hppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cpp,hpp,h}: Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Validate input sanitization to prevent buffer overflows and resource exhaustion attacks; avoid unsafe deserialization of problem files
Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/utilities/omp_helpers.hppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
**/*.{cu,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/utilities/omp_helpers.hppcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/mip/diversity/lns/rins.cucpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
**/*.{cu,cuh}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh}: Every CUDA kernel launch and memory operation must have error checking with CUDA_CHECK or equivalent verification
Avoid reinventing functionality already available in Thrust, CCCL, or RMM libraries; prefer standard library utilities over custom implementations
Files:
cpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/solver.cucpp/src/mip/diversity/lns/rins.cu
**/*.cu
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.cu: Verify race conditions and correctness of GPU kernel shared memory, atomics, and warp-level operations
Detect inefficient GPU kernel launches with low occupancy or poor memory access patterns; optimize for coalesced memory access and minimize warp divergence in hot paths
Files:
cpp/src/mip/solver.cucpp/src/mip/diversity/lns/rins.cu
🧠 Learnings (26)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/mip/diversity/lns/rins.cucpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/mip/diversity/lns/rins.cucpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check that hard-coded GPU device IDs and resource limits are made configurable; abstract multi-backend support for different CUDA versions
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/mip/diversity/lns/rins.cucpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cpp,hpp,h} : Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify error propagation from CUDA to user-facing APIs is complete; ensure CUDA errors are caught and mapped to meaningful user error codes
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.cu : Verify race conditions and correctness of GPU kernel shared memory, atomics, and warp-level operations
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/primal.cppcpp/src/utilities/omp_helpers.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Add tests for algorithm phase transitions: verify correct initialization of bounds and state when transitioning from presolve to simplex to diving to crossover
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/diving_heuristics.hppcpp/src/mip/solver.cucpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*benchmark*.{cpp,cu,py} : Include performance benchmarks and regression detection for GPU operations; verify near real-time performance on million-variable problems
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Ensure test isolation: prevent GPU state, cached memory, and global variables from leaking between test cases; verify each test independently initializes its environment
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh} : Avoid reinventing functionality already available in Thrust, CCCL, or RMM libraries; prefer standard library utilities over custom implementations
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/diving_heuristics.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Test with free variables, singleton problems, and extreme problem dimensions near resource limits to validate edge case handling
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
Applied to files:
cpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/mip/solver.cucpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/mip/diversity/lns/rins.cucpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Applied to files:
cpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-12-04T20:09:09.264Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 602
File: cpp/src/linear_programming/solve.cu:732-742
Timestamp: 2025-12-04T20:09:09.264Z
Learning: In cpp/src/linear_programming/solve.cu, the barrier solver does not currently return INFEASIBLE or UNBOUNDED status. It only returns OPTIMAL, TIME_LIMIT, NUMERICAL_ISSUES, or CONCURRENT_LIMIT.
Applied to files:
cpp/src/dual_simplex/diving_heuristics.hppcpp/src/mip/solver.cucpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/phase2.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cpp,hpp,h} : Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Applied to files:
cpp/src/mip/solver.cucpp/src/dual_simplex/pseudo_costs.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Applied to files:
cpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bounds_strengthening.cpp
📚 Learning: 2025-12-04T04:11:12.640Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 500
File: cpp/src/dual_simplex/scaling.cpp:68-76
Timestamp: 2025-12-04T04:11:12.640Z
Learning: In the cuOPT dual simplex solver, CSR/CSC matrices (including the quadratic objective matrix Q) are required to have valid dimensions and indices by construction. Runtime bounds checking in performance-critical paths like matrix scaling is avoided to prevent slowdowns. Validation is performed via debug-only check_matrix() calls wrapped in #ifdef CHECK_MATRIX.
Applied to files:
cpp/src/dual_simplex/presolve.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-10-22T14:25:22.899Z
Learnt from: aliceb-nv
Repo: NVIDIA/cuopt PR: 527
File: cpp/src/mip/diversity/lns/rins.cu:167-175
Timestamp: 2025-10-22T14:25:22.899Z
Learning: In MIP (Mixed Integer Programming) problems in the cuOPT codebase, `n_integer_vars == 0` is impossible by definition—MIP problems must have at least one integer variable. If there are no integer variables, it would be a pure Linear Programming (LP) problem, not a MIP problem.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
🧬 Code graph analysis (9)
cpp/src/dual_simplex/basis_updates.hpp (1)
cpp/src/dual_simplex/presolve.cpp (3)
lower(240-240)upper(85-85)upper(241-241)
cpp/src/dual_simplex/diving_heuristics.hpp (1)
cpp/src/dual_simplex/pseudo_costs.hpp (3)
fractional(46-48)fractional(50-53)fractional(55-56)
cpp/src/dual_simplex/basis_updates.cpp (3)
cpp/src/dual_simplex/basis_solves.cpp (3)
basis_repair(614-675)basis_repair(614-622)basis_repair(860-868)cpp/src/dual_simplex/basis_solves.hpp (1)
basis_repair(43-51)cpp/src/dual_simplex/basis_updates.hpp (1)
A(374-380)
cpp/src/dual_simplex/crossover.cpp (2)
cpp/src/dual_simplex/basis_solves.cpp (3)
basis_repair(614-675)basis_repair(614-622)basis_repair(860-868)cpp/src/dual_simplex/basis_solves.hpp (1)
basis_repair(43-51)
cpp/src/dual_simplex/basis_solves.cpp (1)
cpp/src/dual_simplex/presolve.cpp (3)
lower(240-240)upper(85-85)upper(241-241)
cpp/src/dual_simplex/node_queue.hpp (3)
cpp/src/dual_simplex/branch_and_bound.hpp (2)
node_ptr(201-206)node_ptr(209-213)cpp/src/dual_simplex/pseudo_costs.hpp (1)
node_ptr(31-31)cpp/src/dual_simplex/mip_node.hpp (2)
node_ptr(277-283)node_ptr(277-277)
cpp/src/dual_simplex/pseudo_costs.cpp (1)
cpp/src/dual_simplex/pseudo_costs.hpp (4)
num_initialized_down(41-44)fractional(46-48)fractional(50-53)fractional(55-56)
cpp/src/dual_simplex/logger.hpp (1)
cpp/src/dual_simplex/simplex_solver_settings.hpp (2)
log_filename(101-101)log_filename(101-101)
cpp/src/dual_simplex/diving_heuristics.cpp (2)
cpp/src/dual_simplex/pseudo_costs.hpp (4)
fractional(46-48)fractional(50-53)fractional(55-56)num_initialized_down(41-44)cpp/src/dual_simplex/simplex_solver_settings.hpp (2)
log(100-100)log(102-102)
🪛 Cppcheck (2.19.0)
cpp/src/dual_simplex/pseudo_costs.cpp
[warning] 314-314: Array index -1 is out of bounds.
(negativeContainerIndex)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.10, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.12, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.11, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.12, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.13, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.13, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.11, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.10, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-sh-client / 13.1.0, 3.10, amd64, rockylinux8
- GitHub Check: checks / check-style
🔇 Additional comments (31)
cpp/src/utilities/omp_helpers.hpp (1)
3-4: SPDX header update looks fine.cpp/src/dual_simplex/simplex_solver_settings.hpp (2)
23-36: LGTM! Clean settings structure for diving heuristics.The new
diving_heuristics_settings_tstruct provides a well-organized configuration for diving parameters. The default values are sensible: diving is enabled by default, with reasonable iteration limits and backtracking depth.One minor observation: the
num_diving_workers = -1sentinel value is immediately overwritten by the constructor logic (Line 96), so this default is effectively unused but could aid debugging if construction is bypassed.
88-97: No action required. The thread worker allocation logic is sound.The values
num_bfs_workersandnum_diving_workersrepresent the maximum number of active workers in a task queue, not thread counts. The actual threading is controlled exclusively by#pragma omp parallel num_threads(settings_.num_threads)at line 1221 of branch_and_bound.cpp, which creates a parallel region with exactlynum_threadsthreads. Workers are dispatched as OpenMP tasks (not threads) and scheduled by the runtime on available threads. On single-threaded configurations (num_threads=1), task execution automatically serializes—there is no over-subscription.Likely an incorrect or invalid review comment.
cpp/src/dual_simplex/basis_updates.hpp (1)
374-380: LGTM! Signature extension for bounds-aware refactorization.Adding
lowerandupperbounds torefactor_basisenables proper variable status assignment during basis repair, which is essential for correctly handling free variables vs. bounded variables when replacing deficient basis columns.cpp/src/dual_simplex/pseudo_costs.hpp (1)
50-53: LGTM! New objective estimate method for improved node selection.The
obj_estimatemethod provides pseudo-cost-based objective estimates for nodes, which is useful for best-estimate node selection strategies in the B&B framework.cpp/src/dual_simplex/mip_node.hpp (2)
48-48: LGTM! Objective estimate propagation through node hierarchy.The
objective_estimatefield is correctly:
- Initialized to infinity in root/default constructors
- Inherited from parent during child node construction
- Copied in
detach_copy()for node serializationThis enables best-estimate search strategies in the B&B framework.
Also applies to: 63-63, 85-85, 245-245
230-241: Detach copy correctly includes new field.The
detach_copy()method properly copies all node fields including the newobjective_estimate, maintaining consistency when nodes are detached from the tree.cpp/src/dual_simplex/basis_solves.cpp (1)
860-868: Explicit instantiation updated correctly.The template instantiation for
basis_repairis properly updated to include the newlowerandupperbound parameters.cpp/src/mip/diversity/recombiners/sub_mip.cuh (1)
106-117: LGTM! Updated to new worker-based configuration.The configuration properly:
- Uses
num_bfs_workersinstead of the oldnum_bfs_threads- Restricts diving to guided diving only (appropriate for sub-MIP where exploration budget is limited)
- Updates the
solution_callbacklambda to the new two-parameter signature(solution, objective)The comment at lines 108-109 clearly documents the intent to expand diving heuristic usage in the future.
cpp/src/dual_simplex/CMakeLists.txt (1)
13-13: LGTM! New source files properly added to the build.The new
bnb_worker.cppanddiving_heuristics.cppfiles are correctly integrated into the CMakeLists.txt at lines 13 and 35 respectively, and both files exist in the codebase.cpp/src/dual_simplex/logger.hpp (2)
33-43: LGTM! Good API enhancement for file mode control.The addition of the
modeparameter toenable_log_to_fileandset_log_fileprovides flexibility for append mode logging while maintaining backward compatibility via the default"w"argument.
46-51: Good fix: proper state reset inclose_log_file.Explicitly resetting
log_filetonullptrandlog_to_filetofalseprevents stale state issues if logging is re-enabled later.cpp/src/dual_simplex/primal.cpp (1)
301-309: LGTM! Bounds correctly threaded through basis repair.The updated
basis_repaircall now passeslp.lowerandlp.upper, aligning with the new signature inbasis_solves.hpp. This enables bound-aware basis repair during primal phase 2.cpp/src/mip/solver.cu (1)
177-181: Verify worker allocation for low thread counts.When
num_threads=1, this calculatesnum_bfs_workers=1andnum_diving_workers=1(due tomax(1, 1-1)), resulting in 2 workers for 1 thread. Similarly fornum_threads=2or3.If this is intentional oversubscription, consider adding a comment. Otherwise, you may want to adjust the logic:
🔧 Suggested adjustment if workers shouldn't exceed threads
i_t num_threads = branch_and_bound_settings.num_threads; - i_t num_bfs_workers = std::max(1, num_threads / 4); - i_t num_diving_workers = std::max(1, num_threads - num_bfs_workers); + i_t num_bfs_workers = std::max(1, num_threads / 4); + i_t num_diving_workers = std::max(0, num_threads - num_bfs_workers); + // Ensure at least one diving worker if threads allow + if (num_diving_workers == 0 && num_threads > 1) num_diving_workers = 1;cpp/src/dual_simplex/basis_solves.hpp (1)
42-51: LGTM! Clean API extension for bound-aware basis repair.The new
lowerandupperparameters enable the basis repair algorithm to consider variable bounds during repair decisions. The const reference parameters are appropriate for read-only access.cpp/src/dual_simplex/pseudo_costs.cpp (2)
202-202: LGTM! RAII lock pattern improves exception safety.Using
std::lock_guardinstead of manual lock/unlock ensures the mutex is released even if an exception occurs.
319-362: LGTM! Newobj_estimatefunction is well-structured.The function correctly:
- Uses RAII locking for thread safety
- Computes per-variable pseudocost contributions with proper fallback to averages
- Returns an estimate based on minimum of down/up costs (conservative estimate)
cpp/src/mip/diversity/lns/rins.cu (1)
259-270: LGTM! Conservative diving configuration for RINS sub-MIP.The settings appropriately restrict RINS sub-problems to use only guided diving (by disabling line search, coefficient, and pseudocost diving). The comment on lines 263-264 documents the intent to expand this in the future.
cpp/src/dual_simplex/bounds_strengthening.cpp (3)
57-69: LGTM! Constructor initialization order corrected.Moving
A(problem.A)to the front of the initializer list is correct sinceAis a member and may be needed before other members. The initialization now follows declaration order.
91-117: LGTM! Selective constraint processing based on changed bounds.The new
bounds_changedparameter enables efficient incremental bound strengthening by only processing constraints affected by modified variables. This optimization avoids redundant work when only a subset of bounds change.
156-165: LGTM! Debug-level logging for infeasibility diagnostics.Changing infeasibility reporting from
printftolog.debugis appropriate since this information is diagnostic and should not pollute normal output.cpp/src/dual_simplex/bounds_strengthening.hpp (1)
23-26: LGTM: Clean API externalization.The bounds_changed parameter is now passed explicitly rather than managed internally, improving modularity and aligning with the broader refactor to thread bounds information through the dual simplex operations.
cpp/src/dual_simplex/bnb_worker.cpp (3)
15-32: LGTM: Constructor properly initializes worker state.The constructor correctly initializes all members including the bounds_changed vector with the appropriate size.
49-52: LGTM: Correct bounds_changed handling.The bounds_changed vector is properly reset before being populated by get_variable_bounds, then passed to bounds_strengthening. This follows the correct pattern for tracking which bounds were modified.
Based on learnings, correct initialization of variable bounds is validated before bounds strengthening.
59-74: LGTM: Consistent bounds handling across both code paths.Both branches (recompute_bounds and update_branched_variable_bounds) correctly reset bounds_changed before populating it, then perform bounds strengthening. The pattern is consistent with init_diving.
cpp/src/dual_simplex/crossover.cpp (3)
788-796: LGTM: basis_repair call updated correctly.The call now passes lp.lower and lp.upper bounds before the deficient/slacks_needed parameters, consistent with the updated signature in basis_solves.hpp.
1142-1150: LGTM: Consistent with other basis_repair updates.This call site is updated identically to the first occurrence, maintaining consistency across the file.
1341-1349: LGTM: All three basis_repair call sites updated consistently.The third call site follows the same pattern as the previous two, ensuring uniform propagation of bounds information throughout the crossover algorithm.
cpp/src/dual_simplex/basis_updates.cpp (2)
2046-2053: LGTM: refactor_basis signature extended for bounds-aware repair.The addition of lower and upper bound parameters enables the repair logic to make informed decisions about variable statuses when replacing deficient columns, consistent with the API changes in basis_solves.hpp.
2071-2072: LGTM: basis_repair call updated correctly.The call now passes lower and upper bounds, matching the updated signature and enabling correct vstatus assignment during basis repair.
Based on learnings, this change ensures correct initialization of variable bounds during the transition between algorithm phases.
cpp/src/dual_simplex/branch_and_bound.cpp (1)
240-247: Lower-bound aggregation looks good; ensure lower_bound_ceiling_ is initialized everywhere.Taking the min across
lower_bound_ceiling_, the best-first heap bound, and active exploration workers’ bounds is a solid way to keep progress monotone under numerical issues.
| settings_.log.printf( | ||
| " | Explored | Unexplored | Objective | Bound | Depth | Iter/Node | Gap " | ||
| " | Explored | Unexplored | Objective | Bound | Depth | Iter/Node | Gap " | ||
| "| Time |\n"); | ||
|
|
||
| exploration_stats_.nodes_explored = 0; | ||
| exploration_stats_.nodes_unexplored = 2; | ||
| exploration_stats_.nodes_since_last_log = 0; | ||
| exploration_stats_.last_log = tic(); | ||
| active_subtrees_ = 0; | ||
| min_diving_queue_size_ = 4 * settings_.num_diving_threads; | ||
| solver_status_ = mip_exploration_status_t::RUNNING; | ||
| lower_bound_ceiling_ = inf; | ||
| should_report_ = true; | ||
|
|
||
| #pragma omp parallel num_threads(settings_.num_threads) | ||
| { | ||
| #pragma omp master | ||
| { | ||
| auto down_child = search_tree_.root.get_down_child(); | ||
| auto up_child = search_tree_.root.get_up_child(); | ||
| i_t initial_size = 2 * settings_.num_threads; | ||
| f_t lower_bound = get_lower_bound(); | ||
| f_t abs_gap = upper_bound_ - lower_bound; | ||
| f_t rel_gap = user_relative_gap(original_lp_, upper_bound_.load(), lower_bound); | ||
| i_t last_node_depth = 0; | ||
| f_t last_log = 0.0; | ||
|
|
||
| while (solver_status_ == mip_exploration_status_t::RUNNING && | ||
| abs_gap > settings_.absolute_mip_gap_tol && rel_gap > settings_.relative_mip_gap_tol && | ||
| (active_workers_per_type[0] > 0 || node_queue.best_first_queue_size() > 0)) { | ||
| bool launched_any_task = false; | ||
| lower_bound = get_lower_bound(); | ||
| abs_gap = upper_bound_ - lower_bound; | ||
| rel_gap = user_relative_gap(original_lp_, upper_bound_.load(), lower_bound); | ||
|
|
||
| repair_heuristic_solutions(); | ||
|
|
||
| if (!is_ramp_up_finished) { | ||
| if (node_queue.best_first_queue_size() >= min_node_queue_size_) { | ||
| if (!std::isfinite(upper_bound_)) { diving_settings.disable_guided_diving = true; } | ||
| max_num_workers_per_type = | ||
| bnb_get_num_workers_round_robin(settings_.num_threads, diving_settings); | ||
| worker_types = bnb_get_worker_types(diving_settings); | ||
| is_ramp_up_finished = true; | ||
|
|
||
| #ifdef CUOPT_LOG_DEBUG | ||
| settings_.log.debug( | ||
| "Ramp-up phase is finished. num active workers = %d, heap size = %d\n", | ||
| active_workers_per_type[EXPLORATION], | ||
| node_queue.best_first_queue_size()); | ||
|
|
||
| for (auto type : worker_types) { | ||
| settings_.log.debug("%s: max num of workers = %d", | ||
| feasible_solution_symbol(type), | ||
| max_num_workers_per_type[type]); | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| #pragma omp task | ||
| exploration_ramp_up(down_child, &search_tree_, Arow, initial_size); | ||
| // If the guided diving was disabled previously due to the lack of an incumbent solution, | ||
| // re-enable as soon as a new incumbent is found. | ||
| if (settings_.diving_settings.disable_guided_diving != | ||
| diving_settings.disable_guided_diving) { | ||
| if (std::isfinite(upper_bound_)) { | ||
| diving_settings.disable_guided_diving = settings_.diving_settings.disable_guided_diving; | ||
| max_num_workers_per_type = | ||
| bnb_get_num_workers_round_robin(settings_.num_threads, diving_settings); | ||
| worker_types = bnb_get_worker_types(diving_settings); | ||
|
|
||
| #ifdef CUOPT_LOG_DEBUG | ||
| for (auto type : worker_types) { | ||
| settings_.log.debug("%s: max num of workers = %d", | ||
| feasible_solution_symbol(type), | ||
| max_num_workers_per_type[type]); | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| #pragma omp task | ||
| exploration_ramp_up(up_child, &search_tree_, Arow, initial_size); | ||
| } | ||
| f_t now = toc(exploration_stats_.start_time); | ||
| f_t time_since_last_log = last_log == 0 ? 1.0 : toc(last_log); | ||
|
|
||
| if (((nodes_since_last_log_ >= 1000 || abs_gap < 10 * settings_.absolute_mip_gap_tol) && | ||
| time_since_last_log >= 1) || | ||
| (time_since_last_log > 30) || now > settings_.time_limit) { | ||
| i_t depth = | ||
| node_queue.best_first_queue_size() > 0 ? node_queue.bfs_top()->depth : last_node_depth; | ||
| report(" ", upper_bound_, lower_bound, depth); | ||
| last_log = tic(); | ||
| nodes_since_last_log_ = 0; | ||
| } | ||
|
|
||
| #pragma omp barrier | ||
| if (now > settings_.time_limit) { | ||
| solver_status_ = mip_exploration_status_t::TIME_LIMIT; | ||
| break; | ||
| } | ||
|
|
||
| #pragma omp master | ||
| { | ||
| for (i_t i = 0; i < settings_.num_bfs_threads; i++) { | ||
| #pragma omp task | ||
| best_first_thread(i, search_tree_, Arow); | ||
| } | ||
| for (auto type : worker_types) { | ||
| if (active_workers_per_type[type] >= max_num_workers_per_type[type]) { continue; } | ||
|
|
||
| // Get an idle worker. | ||
| bnb_worker_t<i_t, f_t>* worker = worker_pool_.get_idle_worker(); | ||
| if (worker == nullptr) { break; } | ||
|
|
||
| if (type == EXPLORATION) { | ||
| // If there any node left in the heap, we pop the top node and explore it. | ||
| std::optional<mip_node_t<i_t, f_t>*> start_node = node_queue.pop_best_first(); | ||
|
|
||
| if (!start_node.has_value()) { continue; } | ||
| if (upper_bound_ < start_node.value()->lower_bound) { | ||
| // This node was put on the heap earlier but its lower bound is now greater than the | ||
| // current upper bound | ||
| search_tree_.graphviz_node( | ||
| settings_.log, start_node.value(), "cutoff", start_node.value()->lower_bound); | ||
| search_tree_.update(start_node.value(), node_status_t::FATHOMED); | ||
| continue; | ||
| } | ||
|
|
||
| // Remove the worker from the idle list. | ||
| worker_pool_.pop_idle_worker(); | ||
| worker->init_best_first(start_node.value(), original_lp_); | ||
| last_node_depth = start_node.value()->depth; | ||
| active_workers_per_type[type]++; | ||
| nodes_since_last_log_++; | ||
| launched_any_task = true; | ||
|
|
||
| #pragma omp task affinity(worker) | ||
| plunge_with(worker); | ||
|
|
||
| for (i_t i = 0; i < settings_.num_diving_threads; i++) { | ||
| #pragma omp task | ||
| diving_thread(Arow); | ||
| } else { | ||
| std::optional<mip_node_t<i_t, f_t>*> start_node = node_queue.pop_diving(); | ||
|
|
||
| if (!start_node.has_value()) { continue; } | ||
| if (upper_bound_ < start_node.value()->lower_bound || | ||
| start_node.value()->depth < diving_settings.min_node_depth) { | ||
| continue; | ||
| } | ||
|
|
||
| bool is_feasible = | ||
| worker->init_diving(start_node.value(), type, original_lp_, settings_); | ||
| if (!is_feasible) { continue; } | ||
|
|
||
| // Remove the worker from the idle list. | ||
| worker_pool_.pop_idle_worker(); | ||
| active_workers_per_type[type]++; | ||
| launched_any_task = true; | ||
|
|
||
| #pragma omp task affinity(worker) | ||
| dive_with(worker); | ||
| } | ||
| } | ||
|
|
||
| // If no new task was launched in this iteration, suspend temporarily the | ||
| // execution of the master. As of 8/Jan/2026, GCC does not | ||
| // implement taskyield, but LLVM does. | ||
| if (!launched_any_task) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
GCC libgomp OpenMP task affinity support versions
💡 Result:
Summary — task-affinity support in libgomp / GCC
- The "affinity" clause for tasks is part of OpenMP 5.0 (the standard; examples showing task affinity appear in the OpenMP 5.0 examples). [1]
- GCC/libgomp received patches to add support for the affinity clause (patch activity visible in the gcc-patches list in 2021). [2]
- Practically, older GCC releases (e.g., GCC 11) had only a stub/no-op for task-affinity; reports and community answers note the feature was newly added/limited and not fully effective in earlier releases. [3]
- libgomp documentation and source history show ongoing work in later GCC series (GCC 12+ and beyond) to implement OpenMP-5 features; behavior and completeness of task-affinity depend on the exact GCC/libgomp release and may be partial or a hint-only implementation. Check the libgomp manual and GCC release notes for the specific GCC version you plan to use. [4]
If you want, tell me which GCC version(s) you care about (e.g., 11, 12, 13, 14, 15) and I’ll check the libgomp source/docs/release notes for exact implementation status and any known limitations.
Sources:
[1] OpenMP 5.0 examples — Task Affinity. (passlab.github.io)
[2] GCC patch discussion adding affinity clause (May 2021). (gcc.gnu.org)
[3] StackOverflow discussion about compiler support (notes stub in GCC 11.2). (stackoverflow.com)
[4] GNU libgomp / GCC OpenMP implementation status and manual. (gcc.gnu.org)
Citations:
- 1: https://passlab.github.io/Examples/contents/Chap_affinity/2_Task_Affinity.html?utm_source=openai
- 2: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/571468.html?utm_source=openai
- 3: https://stackoverflow.com/questions/70963677/does-any-c-c-compiler-support-openmps-task-affinity-clauses-yet?utm_source=openai
- 4: https://gcc.gnu.org/onlinedocs/libgomp/?utm_source=openai
🌐 Web query:
GCC libgomp OpenMP taskyield pragma support
💡 Result:
Yes — GCC's libgomp supports the OpenMP taskyield pragma. The OpenMP spec defines #pragma omp taskyield, and libgomp exports GOMP_taskyield (and the compiler builtins include GOMP_TASKYIELD). [1][2][3]
Sources:
- OpenMP taskyield construct (spec). [1]
- libgomp symbol map showing GOMP_taskyield. [2]
- GCC builtins listing GOMP_TASKYIELD. [3]
🌐 Web query:
OpenMP taskyield directive implementation status GCC LLVM 2025 2026
💡 Result:
Short answer — as of Jan 9, 2026:
- OpenMP defines taskyield (spec reference). [1]
- GCC: the front end/parsing for #pragma omp taskyield is present (parsing/finish hooks added), but libgomp’s taskyield is effectively a stub / not fully implemented (GCC is listed as XFAIL in tests). In practice GCC accepts the directive but does not perform real task-yield scheduling behavior. [2][3]
- LLVM/Clang (libomp): tests and sources show an active taskyield test in the LLVM OpenMP runtime; LLVM’s libomp implements the behavior tested (the LLVM test marks GCC as XFAIL because GCC’s runtime is the stub). So LLVM has working taskyield support while GCC’s runtime support is incomplete. [3][4]
Sources:
- OpenMP spec — taskyield construct. [1]
- GCC commit/messages showing parser/front-end hooks for taskyield (c_finish_omp_taskyield). [2]
- LLVM OpenMP runtime test and comments (taskyield test; notes that “Current GOMP interface implements taskyield as stub” and XFAIL: gcc). [3]
- OpenMP project status blog (implementation notes for compilers). [4]
OpenMP task affinity(...) and taskyield support is compiler/runtime-dependent and may be incomplete.
The code uses #pragma omp task affinity(worker) with a sleep fallback for taskyield. As of January 2026:
- GCC's libgomp accepts
#pragma omp taskyieldsyntax but implements it as a stub without actual task-yield scheduling behavior (GCC is marked XFAIL in test suites). - LLVM/Clang's libomp does implement working
taskyieldbehavior. - The
affinityclause (OpenMP 5.0) is supported in GCC 12+, but implementation is incomplete in older versions (GCC 11 and earlier have stub implementations).
Ensure the target compiler and libgomp/libomp versions provide functional implementations, or document this limitation for users building with GCC.
🤖 Prompt for AI Agents
In @cpp/src/dual_simplex/branch_and_bound.cpp around lines 1217 - 1363, The
OpenMP affinity clause and taskyield behavior used around the pragmas that
launch tasks for plunge_with and dive_with can be unsupported or incomplete on
some libgomp/libomp versions; update the code to either (a)
compile-conditionally omit the affinity clause and/or taskyield semantics when
building with known-broken GCC/libgomp versions (detect via predefined macros or
a CMake feature test for OpenMP 5.0 affinity/taskyield support), or (b) add a
clear runtime/build-time check and fallback (keep the current
std::this_thread::sleep_for fallback) and document the limitation for GCC users;
reference the pragmas using the affinity(worker) lines that wrap
plunge_with(worker) and dive_with(worker) and the sleep fallback around
launched_any_task to implement the conditional removal/fallback and add the
documented note.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
cpp/src/dual_simplex/bounds_strengthening.hpp (1)
23-26: Clarify whetherbounds_changedis an input mask or an output report (currentconst&implies input).
As-is, the name reads like an output (“these bounds were changed”), butconst std::vector<bool>&can only be consumed. Please align naming/docs with the intended semantics and ensure callers pass the correct index space (original vs presolve/folded) and correct length to avoid mismatched indexing. Based on learnings, this is a common correctness footgun around phase transitions and index mappings.Proposed header-only clarification (no behavior change)
- bool bounds_strengthening(std::vector<f_t>& lower_bounds, - std::vector<f_t>& upper_bounds, - const std::vector<bool>& bounds_changed, - const simplex_solver_settings_t<i_t, f_t>& settings); + // `bounds_changed_mask` is an input hint/mask in the *same index space* as `lower_bounds/upper_bounds` + // (typically number of columns/variables). It is used to skip work on unaffected constraints/vars. + bool bounds_strengthening(std::vector<f_t>& lower_bounds, + std::vector<f_t>& upper_bounds, + const std::vector<bool>& bounds_changed_mask, + const simplex_solver_settings_t<i_t, f_t>& settings);
- Please confirm
bounds_strengthening.cpp(and all call sites) enforce/assumebounds_changed*.size() == lower_bounds.size() == upper_bounds.size()(orproblem.num_cols) and that the mask is in the correct problem context/indexing.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hppcpp/src/dual_simplex/presolve.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
- cpp/src/dual_simplex/presolve.cpp
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{cu,cuh,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh,cpp,hpp,h}: Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Check that hard-coded GPU de...
Files:
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hpp
**/*.{cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cpp,hpp,h}: Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Validate input sanitization to prevent buffer overflows and resource exhaustion attacks; avoid unsafe deserialization of problem files
Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Files:
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hpp
**/*.{cu,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Files:
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hpp
**/*.{h,hpp,py}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Verify C API does not break ABI stability (no struct layout changes, field reordering); maintain backward compatibility in Python and server APIs with deprecation warnings
Files:
cpp/src/dual_simplex/bounds_strengthening.hpp
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Applied to files:
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Applied to files:
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Add tests for algorithm phase transitions: verify correct initialization of bounds and state when transitioning from presolve to simplex to diving to crossover
Applied to files:
cpp/src/dual_simplex/bnb_worker.cppcpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-12-04T20:09:09.264Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 602
File: cpp/src/linear_programming/solve.cu:732-742
Timestamp: 2025-12-04T20:09:09.264Z
Learning: In cpp/src/linear_programming/solve.cu, the barrier solver does not currently return INFEASIBLE or UNBOUNDED status. It only returns OPTIMAL, TIME_LIMIT, NUMERICAL_ISSUES, or CONCURRENT_LIMIT.
Applied to files:
cpp/src/dual_simplex/bnb_worker.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check that hard-coded GPU device IDs and resource limits are made configurable; abstract multi-backend support for different CUDA versions
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cpp,hpp,h} : Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify error propagation from CUDA to user-facing APIs is complete; ensure CUDA errors are caught and mapped to meaningful user error codes
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.cu : Verify race conditions and correctness of GPU kernel shared memory, atomics, and warp-level operations
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
📚 Learning: 2025-12-04T04:11:12.640Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 500
File: cpp/src/dual_simplex/scaling.cpp:68-76
Timestamp: 2025-12-04T04:11:12.640Z
Learning: In the cuOPT dual simplex solver, CSR/CSC matrices (including the quadratic objective matrix Q) are required to have valid dimensions and indices by construction. Runtime bounds checking in performance-critical paths like matrix scaling is avoided to prevent slowdowns. Validation is performed via debug-only check_matrix() calls wrapped in #ifdef CHECK_MATRIX.
Applied to files:
cpp/src/dual_simplex/bounds_strengthening.hpp
🧬 Code graph analysis (1)
cpp/src/dual_simplex/bnb_worker.cpp (2)
cpp/src/dual_simplex/bnb_worker.hpp (5)
bnb_worker_t(68-72)node(75-83)node(75-75)node(88-91)node_ptr(94-95)cpp/src/dual_simplex/branch_and_bound.hpp (2)
node_ptr(201-206)node_ptr(209-213)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: wheel-build-libcuopt / 13.1.0, 3.13, arm64, rockylinux8
- GitHub Check: wheel-build-libcuopt / 12.9.1, 3.13, amd64, rockylinux8
- GitHub Check: wheel-build-libcuopt / 12.9.1, 3.13, arm64, rockylinux8
- GitHub Check: wheel-build-libcuopt / 13.1.0, 3.13, amd64, rockylinux8
- GitHub Check: conda-cpp-build / 12.9.1, 3.10, amd64, rockylinux8
- GitHub Check: conda-cpp-build / 13.1.0, 3.10, arm64, rockylinux8
- GitHub Check: conda-cpp-build / 13.1.0, 3.10, amd64, rockylinux8
- GitHub Check: conda-cpp-build / 12.9.1, 3.10, arm64, rockylinux8
🔇 Additional comments (6)
cpp/src/dual_simplex/bounds_strengthening.hpp (1)
3-3: Header year update looks fine.cpp/src/dual_simplex/bnb_worker.cpp (5)
16-32: Constructor initialization looks correct.The worker initialization properly sets the initial state (EXPLORATION type, inactive, lower_bound = -∞) and constructs all necessary data structures for branch-and-bound operations.
77-79: LGTM: Standard explicit template instantiation.The conditional explicit instantiation for
bnb_worker_t<int, double>follows best practices for managing template compilation.
16-32: Verify thread safety assumptions for worker access patterns.The worker maintains mutable state (
is_active,internal_node,leaf_problem, etc.) with no visible synchronization primitives. In a master-worker B&B framework, confirm that:
- Each worker is accessed exclusively by a single thread at a time, or
- External synchronization ensures thread-safe access to worker methods
Based on coding guidelines: thread-unsafe use of shared state must be properly synchronized in concurrent code.
Also applies to: 35-53, 56-75
35-53: > Likely an incorrect or invalid review comment.
56-75: > Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @cpp/src/dual_simplex/diving_heuristics.cpp:
- Around line 28-39: The score computation can blow up when d = |solution[j] -
root_solution[j]| is very small; introduce a minimum difference threshold (e.g.,
const f_t min_diff = 1e-8 or configurable) and use d_clamped = std::max(d,
min_diff) before computing score = f / d_clamped (or alternatively skip the
variable when d < min_diff). Update both branches (where dir is set to
rounding_direction_t::DOWN and rounding_direction_t::UP) to clamp d (and use the
same min_diff symbol) to avoid division by near-zero and ensure numerical
stability.
🧹 Nitpick comments (2)
cpp/src/dual_simplex/diving_heuristics.cpp (1)
103-121: Consider documenting the heuristic threshold constants.Lines 103-121 use several hardcoded thresholds (0.4, 0.3, 0.7) to determine the rounding direction. While these may be derived from research literature or empirical tuning, their significance isn't documented.
Consider adding comments that reference the source or rationale for these values, or making them configurable parameters in
diving_heuristics_settings_tfor experimentation and tuning.cpp/src/dual_simplex/node_queue.hpp (1)
107-138: Note the trade-off in dual-heap memory management.The design shares
heap_entry_tinstances between both heaps viashared_ptr, withstd::exchangenulling the node pointer when popped from one heap (line 120). Thepop_divingmethod loops to skip already-nulled entries (lines 129-135).This is functionally correct but has trade-offs:
- Memory: Entries remain in both heaps until popped from each, doubling memory usage
- Performance:
pop_divingmay iterate through multiple nulled entries in O(n) worst caseFor the expected usage pattern (roughly balanced pops from both heaps), this is likely acceptable. If profiling reveals this as a bottleneck, consider tracking which entries have been nulled to avoid iteration overhead.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
cpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hpp
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{cu,cuh,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh,cpp,hpp,h}: Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Check that hard-coded GPU de...
Files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
**/*.{cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cpp,hpp,h}: Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Validate input sanitization to prevent buffer overflows and resource exhaustion attacks; avoid unsafe deserialization of problem files
Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
**/*.{cu,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
**/*.{h,hpp,py}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Verify C API does not break ABI stability (no struct layout changes, field reordering); maintain backward compatibility in Python and server APIs with deprecation warnings
Files:
cpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Add tests for algorithm phase transitions: verify correct initialization of bounds and state when transitioning from presolve to simplex to diving to crossover
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh} : Avoid reinventing functionality already available in Thrust, CCCL, or RMM libraries; prefer standard library utilities over custom implementations
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-12-04T04:11:12.640Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 500
File: cpp/src/dual_simplex/scaling.cpp:68-76
Timestamp: 2025-12-04T04:11:12.640Z
Learning: In the cuOPT dual simplex solver, CSR/CSC matrices (including the quadratic objective matrix Q) are required to have valid dimensions and indices by construction. Runtime bounds checking in performance-critical paths like matrix scaling is avoided to prevent slowdowns. Validation is performed via debug-only check_matrix() calls wrapped in #ifdef CHECK_MATRIX.
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-12-04T20:09:09.264Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 602
File: cpp/src/linear_programming/solve.cu:732-742
Timestamp: 2025-12-04T20:09:09.264Z
Learning: In cpp/src/linear_programming/solve.cu, the barrier solver does not currently return INFEASIBLE or UNBOUNDED status. It only returns OPTIMAL, TIME_LIMIT, NUMERICAL_ISSUES, or CONCURRENT_LIMIT.
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Applied to files:
cpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cpp,hpp,h} : Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Applied to files:
cpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cpp,hpp,h} : Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Applied to files:
cpp/src/dual_simplex/node_queue.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check that hard-coded GPU device IDs and resource limits are made configurable; abstract multi-backend support for different CUDA versions
Applied to files:
cpp/src/dual_simplex/node_queue.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Test with free variables, singleton problems, and extreme problem dimensions near resource limits to validate edge case handling
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-10-22T14:25:22.899Z
Learnt from: aliceb-nv
Repo: NVIDIA/cuopt PR: 527
File: cpp/src/mip/diversity/lns/rins.cu:167-175
Timestamp: 2025-10-22T14:25:22.899Z
Learning: In MIP (Mixed Integer Programming) problems in the cuOPT codebase, `n_integer_vars == 0` is impossible by definition—MIP problems must have at least one integer variable. If there are no integer variables, it would be a pure Linear Programming (LP) problem, not a MIP problem.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
🔇 Additional comments (15)
cpp/src/dual_simplex/diving_heuristics.cpp (1)
276-298: LGTM!The explicit template instantiations follow the codebase pattern and correctly instantiate all diving heuristic functions for the
int, doubletype pair.cpp/src/dual_simplex/node_queue.hpp (1)
23-65: LGTM!The
heap_ttemplate provides a clean wrapper around STL heap functions with good use ofstd::optionalfor thepop()return value and proper support for move semantics.cpp/src/dual_simplex/bnb_worker.hpp (4)
22-44: LGTM!The worker type enumeration and statistics structure are well-designed:
- Clear references to academic literature for the diving heuristics
- Proper use of
omp_atomic_tfor thread-safe counters- Consistent with the worker pool pattern
215-227: Clarify the factor of 2 in diving worker count.Line 217 multiplies
settings.num_diving_workersby 2 when calculating the total diving worker budget:i_t diving_workers = 2 * settings.num_diving_workers;This doubling isn't documented. Is this intentional to allow oversubscription of diving workers, or should it match the configured count? Please add a comment explaining the rationale.
47-107: LGTM!The
bnb_worker_tclass design is sound:
- Proper use of atomics for thread-shared state (
worker_type,is_active,lower_bound)- Clean separation of per-worker state (basis, bounds, presolver)
- Inline
init_best_firstis straightforward and correct
127-160: Verify the split get/pop pattern is used correctly.The worker pool provides separate
get_idle_worker()andpop_idle_worker()methods, requiring callers to invoke both in sequence. This design allows checking worker availability before committing (e.g., validating a node is still viable), but is error-prone if callers forget the pop step.Ensure all call sites in the codebase properly pair
get_idle_worker()withpop_idle_worker(), or use the combinedget_and_pop_idle_worker()method where appropriate.cpp/src/dual_simplex/branch_and_bound.hpp (2)
115-172: LGTM!The new member variables properly support the worker-based architecture:
Arow_provides row-format matrix access needed for bounds strengthening- Atomics ensure thread-safe access to shared state
node_queue_treplaces the old heap with dual-priority queuebnb_worker_pool_tand per-type counters enable worker management- Root solution storage supports diving heuristics that reference the root relaxation
186-213: LGTM!The method signature updates consistently thread the worker context through the solve pipeline:
add_feasible_solutionnow distinguishes solutions by worker typesolve_nodereceives worker context for per-type state managementvariable_selectiondispatches to the appropriate diving heuristic based on type- New
plunge_withanddive_withmethods encapsulate worker-driven explorationThese changes properly support the master-worker architecture.
cpp/src/dual_simplex/branch_and_bound.cpp (7)
240-247: LGTM!The
get_lower_boundmethod correctly aggregates lower bounds from multiple sources:
lower_bound_ceiling_captures numerical issue bounds from EXPLORATION workersnode_queue.get_lower_bound()returns the best node in the queueworker_pool_.get_lower_bounds()returns bounds from active EXPLORATION workersThe use of
std::minand returning-inffor non-finite values ensures sound bound tracking.
567-605: LGTM!The
variable_selectionrefactoring correctly dispatches to per-type heuristics:
- EXPLORATION uses pseudo-costs + Martin's criteria and updates
objective_estimatefor heap ordering- Each diving type invokes its specific heuristic (coefficient, line search, pseudocost, guided)
The comment on lines 582-584 correctly explains that only EXPLORATION updates
objective_estimatesince diving workers operate on local subtrees.
629-635: Verify iteration limit prevents unbounded diving worker execution.Lines 629-635 implement iteration limits for diving workers to prevent them from consuming excessive LP iterations:
i_t bnb_lp_iters = exploration_stats_.total_lp_iters; f_t factor = settings_.diving_settings.iteration_limit_factor; f_t max_iter = factor * bnb_lp_iters; lp_settings.iteration_limit = max_iter - stats.total_lp_iters;Ensure that
diving_settings.iteration_limit_factoris properly initialized in settings and that diving workers correctly return when the limit is reached (line 634) so they don't block progress. This should prevent scenarios where diving workers monopolize solver time.Based on coding guidelines: Verify correct initialization of algorithm state.
747-752: LGTM!The structured binding usage (line 747) cleanly unpacks the branch variable and rounding direction from
variable_selection. The subsequent assertions (lines 751-752) correctly verify the selection returned valid values, ensuring algorithm correctness.
795-891: LGTM!The
plunge_withmethod correctly implements best-first exploration using the worker:
- Proper worker state initialization (lines 800-801)
- Lower bound tracking for progress monitoring (line 817)
- Recompute flags updated based on branching decisions (lines 845-846)
- Queue management implements ramp-up phase: populate global queue when below threshold, use local stack after (lines 870-885)
- Worker properly returned to pool with count decrement (lines 889-890)
894-963: LGTM!The
dive_withmethod correctly implements diving exploration:
- Creates a local subtree via
std::move(line 906), isolating diving operations from the global tree- Maintains local statistics to track diving work independently (lines 910-914)
- Implements backtrack heuristic to prevent excessive depth (lines 956-958)
- Properly returns worker and decrements counter (lines 961-962)
- Respects iteration limits, allowing graceful termination (lines 943-944)
1221-1363: LGTM!The master-worker orchestration in the main solve loop is well-designed:
- Master thread manages worker assignment while worker threads execute tasks (lines 1223-1363)
- Loop termination condition correctly checks for active workers and queued nodes (lines 1231-1233)
- Per-type worker spawning respects configured limits and validates nodes before spawning (lines 1302-1355)
- Proper use of OpenMP task affinity hints for worker assignment (lines 1331, 1352)
- Sleep when idle prevents busy-waiting (line 1360)
- Thread-safety maintained through internal mutexes in
node_queueandworker_pool_, and atomics forupper_bound_Based on coding guidelines: Thread-safety properly handled through synchronization primitives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @cpp/src/dual_simplex/branch_and_bound.cpp:
- Around line 585-586: guided_diving reads incumbent_.x without synchronization
which races with master updates under mutex_upper_; fix by ensuring
guided_diving acquires mutex_upper_ (or another dedicated lock) around any
access to incumbent_.x and around the call to variable_selection so the vector
copy is synchronized with the master’s update of incumbent_.x (alternatively
introduce a separate atomic/lock-protected accessor for incumbent_.x and use
that in guided_diving/variable_selection); update guided_diving and any
worker-side reads to use the chosen lock/accessor and keep atomic upper_bound_
updates as-is.
🧹 Nitpick comments (4)
cpp/src/dual_simplex/bnb_worker.hpp (2)
176-209: Potential TOCTOU race betweenget_idle_worker()andpop_idle_worker().The separate
get_idle_worker()andpop_idle_worker()methods create a window where another thread could pop the same worker between the get and pop calls. Whileget_and_pop_idle_worker()exists as an atomic alternative, the current usage inbranch_and_bound.cpp(lines 1306-1324, 1346-1347) callsget_idle_worker()first to check availability, then performs work initialization, and only then callspop_idle_worker().This pattern appears intentional to allow early exit if initialization fails, but it could lead to a race if multiple master threads existed. Since OMP master is single-threaded, this is currently safe, but consider documenting this constraint or using a reservation pattern.
256-277: Verify template parameter order consistency.The function signature uses
<typename f_t, typename i_t>(lines 243, 256), which is reversed from the typical<typename i_t, typename f_t>pattern used elsewhere in the codebase (e.g.,bnb_worker_data_t,bnb_worker_pool_t). While this doesn't affect correctness, it could cause confusion or template deduction issues at call sites.💡 Suggested fix for template parameter order
-template <typename f_t, typename i_t> +template <typename i_t, typename f_t> std::vector<bnb_worker_type_t> bnb_get_worker_types(diving_heuristics_settings_t<i_t, f_t> settings)-template <typename f_t, typename i_t> +template <typename i_t, typename f_t> std::array<i_t, bnb_num_worker_types> bnb_get_num_workers_round_robin( i_t num_threads, diving_heuristics_settings_t<i_t, f_t> settings)cpp/src/dual_simplex/branch_and_bound.cpp (2)
749-758: Assertions depend on variable_selection success.The assertions at lines 753-754 will fail if
variable_selectionreturns{-1, NONE}(the default case for unknown worker types). While this shouldn't happen in normal operation, consider converting the assertion to an explicit error check with a meaningful error message for robustness, especially in debug builds.💡 Suggested defensive check
auto [branch_var, round_dir] = variable_selection( node_ptr, leaf_fractional, leaf_solution.x, worker_data->worker_type, select_log); assert(leaf_vstatus.size() == leaf_problem.num_cols); - assert(branch_var >= 0); - assert(round_dir != rounding_direction_t::NONE); + if (branch_var < 0 || round_dir == rounding_direction_t::NONE) { + log.printf("Error: variable_selection failed for worker type %d\n", + worker_data->worker_type.load()); + search_tree.update(node_ptr, node_status_t::NUMERICAL); + return {node_status_t::NUMERICAL, rounding_direction_t::NONE}; + }
879-882: Ensure worker is always returned to pool on exit.The worker cleanup at lines 880-881 occurs after the while loop, but early
breakstatements (lines 819-820, 824-825, 832-835) exit the loop without cleanup being guaranteed to execute afterward. The current structure does execute cleanup after break, but if the function is modified to add early returns, the worker could leak.Consider using RAII or a scope guard to ensure
return_worker_to_poolis always called.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{cu,cuh,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh,cpp,hpp,h}: Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Check that hard-coded GPU de...
Files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cpp,hpp,h}: Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Validate input sanitization to prevent buffer overflows and resource exhaustion attacks; avoid unsafe deserialization of problem files
Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{cu,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{h,hpp,py}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Verify C API does not break ABI stability (no struct layout changes, field reordering); maintain backward compatibility in Python and server APIs with deprecation warnings
Files:
cpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check that hard-coded GPU device IDs and resource limits are made configurable; abstract multi-backend support for different CUDA versions
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*benchmark*.{cpp,cu,py} : Include performance benchmarks and regression detection for GPU operations; verify near real-time performance on million-variable problems
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Ensure test isolation: prevent GPU state, cached memory, and global variables from leaking between test cases; verify each test independently initializes its environment
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify error propagation from CUDA to user-facing APIs is complete; ensure CUDA errors are caught and mapped to meaningful user error codes
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cpp,hpp,h} : Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Applied to files:
cpp/src/dual_simplex/CMakeLists.txt
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh} : Avoid reinventing functionality already available in Thrust, CCCL, or RMM libraries; prefer standard library utilities over custom implementations
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Test with free variables, singleton problems, and extreme problem dimensions near resource limits to validate edge case handling
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Add tests for algorithm phase transitions: verify correct initialization of bounds and state when transitioning from presolve to simplex to diving to crossover
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-12-04T20:09:09.264Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 602
File: cpp/src/linear_programming/solve.cu:732-742
Timestamp: 2025-12-04T20:09:09.264Z
Learning: In cpp/src/linear_programming/solve.cu, the barrier solver does not currently return INFEASIBLE or UNBOUNDED status. It only returns OPTIMAL, TIME_LIMIT, NUMERICAL_ISSUES, or CONCURRENT_LIMIT.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/bnb_worker.hppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-12-04T04:11:12.640Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 500
File: cpp/src/dual_simplex/scaling.cpp:68-76
Timestamp: 2025-12-04T04:11:12.640Z
Learning: In the cuOPT dual simplex solver, CSR/CSC matrices (including the quadratic objective matrix Q) are required to have valid dimensions and indices by construction. Runtime bounds checking in performance-critical paths like matrix scaling is avoided to prevent slowdowns. Validation is performed via debug-only check_matrix() calls wrapped in #ifdef CHECK_MATRIX.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cpp,hpp,h} : Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Applied to files:
cpp/src/dual_simplex/bnb_worker.hpp
📚 Learning: 2025-10-22T14:25:22.899Z
Learnt from: aliceb-nv
Repo: NVIDIA/cuopt PR: 527
File: cpp/src/mip/diversity/lns/rins.cu:167-175
Timestamp: 2025-10-22T14:25:22.899Z
Learning: In MIP (Mixed Integer Programming) problems in the cuOPT codebase, `n_integer_vars == 0` is impossible by definition—MIP problems must have at least one integer variable. If there are no integer variables, it would be a pure Linear Programming (LP) problem, not a MIP problem.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.hpp
🧬 Code graph analysis (2)
cpp/src/dual_simplex/branch_and_bound.cpp (2)
cpp/src/dual_simplex/branch_and_bound.hpp (5)
obj(158-158)symbol(159-159)solution(70-70)solution(87-87)solution(162-162)cpp/src/dual_simplex/solve.hpp (3)
compute_user_objective(37-37)compute_user_objective(40-40)solve_linear_program_with_advanced_basis(53-62)
cpp/src/dual_simplex/branch_and_bound.hpp (3)
cpp/src/dual_simplex/bnb_worker.hpp (3)
lower_bound(219-230)node_ptr(127-146)node_ptr(127-128)cpp/src/dual_simplex/mip_node.hpp (6)
node_ptr(277-283)node_ptr(277-277)log(329-337)log(329-332)log(339-354)log(339-344)cpp/src/dual_simplex/simplex_solver_settings.hpp (2)
log(100-100)log(102-102)
🪛 Clang (14.0.6)
cpp/src/dual_simplex/branch_and_bound.cpp
[error] 8-8: 'dual_simplex/branch_and_bound.hpp' file not found
(clang-diagnostic-error)
cpp/src/dual_simplex/bnb_worker.hpp
[error] 10-10: 'dual_simplex/basis_updates.hpp' file not found
(clang-diagnostic-error)
cpp/src/dual_simplex/branch_and_bound.hpp
[error] 10-10: 'dual_simplex/bnb_worker.hpp' file not found
(clang-diagnostic-error)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.13, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.12, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.13, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.10, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.11, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.12, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.10, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.11, arm64, rockylinux8
🔇 Additional comments (12)
cpp/src/dual_simplex/CMakeLists.txt (1)
34-34: LGTM!The new
diving_heuristics.cppsource file is correctly added to the build system, supporting the new diving heuristics functionality introduced in this PR.cpp/src/dual_simplex/bnb_worker.hpp (3)
37-46: LGTM!The
bnb_stats_tstructure correctly uses atomic types for fields that are accessed concurrently across threads (total_lp_solve_time,nodes_explored, etc.), whilestart_timeis appropriately non-atomic since it's set once before parallel execution begins.
219-230: LGTM!The
get_lower_bounds()implementation is thread-safe: theworkers_vector is immutable after initialization, and all accessed fields (worker_type,is_active,lower_bound) are atomic. Any race conditions only result in a conservative (higher) lower bound, which is safe for the B&B algorithm.
106-124:detach_copy()correctly performs deep copy and memory management is sound.The
detach_copy()implementation creates a newmip_node_tvia the constructor that acceptsvstatusby const reference, triggeringstd::vector's copy constructor for a proper deep copy. All branch information (branch_var, branch_dir, bounds, fractional_val, objective_estimate, node_id) is explicitly copied. The detached node is stored ininternal_node(a member variable), sostart_nodepoints to valid memory throughout the worker's lifetime with automatic cleanup via RAII. No stale data references or memory leaks are present.cpp/src/dual_simplex/branch_and_bound.cpp (5)
233-241: LGTM!The
get_lower_bound()method correctly aggregates lower bounds from three sources: the ceiling (for numerical issues), the node queue, and active exploration workers. Returning-inffor non-finite bounds is appropriate for the B&B algorithm initialization.
611-617: LGTM on iteration limiting for diving workers.The iteration limit logic correctly constrains diving workers based on the total exploration iterations, preventing diving heuristics from consuming excessive computational resources. The early return on non-positive limit is appropriate.
897-906: LGTM on isolated diving tree.The diving worker correctly creates a local
search_tree_tusing move semantics from the worker'sstart_node. This isolation ensures diving operations don't corrupt the global search tree state. The localdive_statsproperly tracks diving-specific metrics without interfering with global exploration statistics.
1364-1369: LGTM!The final solution handling correctly extracts the lower bound from the node queue when available, falling back to the root node's lower bound when the queue is empty. Setting
is_running = falsebefore final processing ensures reporting functions behave correctly.
1229-1231: The while loop condition only monitors EXPLORATION workers, but this is safe due to the implicit barrier.The termination condition at lines 1229-1231 checks only
active_workers_per_type[0](EXPLORATION), not diving worker types [1-4]. Diving workers can indeed still be executing when the loop exits, but this is intentional: the implicit barrier at the end of the#pragma omp parallelregion (line 1365) ensures all spawned tasks—including diving workers—complete before the function returns. This allows the master thread to stop launching new work once exploration is exhausted while allowing in-flight diving tasks to finish asynchronously.Adding a comment clarifying this intended behavior would improve code clarity and prevent confusion in future reviews.
cpp/src/dual_simplex/branch_and_bound.hpp (3)
138-143: LGTM on worker infrastructure declarations.The
active_workers_per_typearray with atomic elements properly tracks concurrent worker counts per type, andworker_pool_encapsulates worker lifecycle management. This design cleanly separates worker state from B&B logic.
174-184: LGTM on worker execution method declarations.The
plunge_withanddive_withmethods clearly express their intent as worker-based tree traversal operations. Thesolve_node_lpmethod signature correctly includes all necessary context (node, worker data, stats, logger) for LP relaxation solving.
80-80: New public accessorget_lower_bound()is a good addition.This provides external callers (e.g., heuristics) access to the current best lower bound without exposing internal state. Based on coding guidelines for API stability, this addition is non-breaking and enhances the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cpp/src/dual_simplex/branch_and_bound.cpp (2)
979-983: Compile error: comparing a dereferencedstd::atomic<int>to0.
*get_root_concurrent_halt() == 0(Line 980) should use.load().Proposed diff
- while (!root_crossover_solution_set_.load(std::memory_order_acquire) && - *get_root_concurrent_halt() == 0) { + while (!root_crossover_solution_set_.load(std::memory_order_acquire) && + get_root_concurrent_halt()->load(std::memory_order_acquire) == 0) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; }
410-433: Do not call user callbacks while holdingmutex_upper_.
settings_.solution_callback(...)is invoked undermutex_upper_(Line 424+ and Line 524+). This is a deadlock/reentrancy and latency risk (callback may call back into solver/logging).Proposed diff (pattern)
- mutex_upper_.lock(); + std::optional<std::vector<f_t>> cb_solution; + std::optional<f_t> cb_objective; + mutex_upper_.lock(); if (leaf_objective < upper_bound_) { incumbent_.set_incumbent_solution(leaf_objective, leaf_solution); upper_bound_ = leaf_objective; report(feasible_solution_symbol(thread_type), leaf_objective, get_lower_bound(), leaf_depth); send_solution = true; } - - if (send_solution && settings_.solution_callback != nullptr) { - std::vector<f_t> original_x; - uncrush_primal_solution(original_problem_, original_lp_, incumbent_.x, original_x); - settings_.solution_callback(original_x, upper_bound_); - } + if (send_solution && settings_.solution_callback != nullptr) { + std::vector<f_t> original_x; + uncrush_primal_solution(original_problem_, original_lp_, incumbent_.x, original_x); + cb_solution = std::move(original_x); + cb_objective = upper_bound_.load(); + } mutex_upper_.unlock(); + + if (cb_solution.has_value()) { + settings_.solution_callback(*cb_solution, *cb_objective); + }Also applies to: 516-529
🤖 Fix all issues with AI agents
In @cpp/src/dual_simplex/branch_and_bound.cpp:
- Around line 611-614: The time remaining passed into lp_settings.time_limit can
be negative; compute the remaining time as settings_.time_limit -
toc(exploration_stats_.start_time) and clamp it to a non-negative value before
assigning to lp_settings.time_limit (e.g., use std::max(0.0, ...)). Update the
assignment in branch_and_bound.cpp where lp_settings.time_limit is set so it
never gets a negative value, preserving the original units/type of time_limit.
- Around line 270-276: The code computes iter_node =
exploration_stats_.total_lp_iters / nodes_explored in branch_and_bound.cpp which
can divide by zero if nodes_explored == 0; change this to guard the division
(e.g., if (nodes_explored > 0) iter_node = exploration_stats_.total_lp_iters /
nodes_explored; else iter_node = 0.0 or std::numeric_limits<f_t>::quiet_NaN())
so reporting never crashes; update the variable initialization near iter_node
and ensure the printf call still uses iter_node.
- Around line 566-577: After calling pc_.variable_selection(...) check if
branch_var < 0 before indexing solution or root_relax_soln_.x: if branch_var is
negative, compute and assign node_ptr->objective_estimate (pc_.obj_estimate can
still be used) and return {-1, NONE} immediately; only call
martin_criteria(solution[branch_var], root_relax_soln_.x[branch_var]) and access
solution[branch_var] when branch_var >= 0. Apply the same guard to the similar
block around lines 593-596 so release builds do not perform out-of-bounds
accesses and update_tree no longer depends on an assert-only check.
- Around line 1231-1234: The master loop termination only checks
active_workers_per_type[0] and best_first_queue_size(), and discarded nodes
aren't decrementing exploration_stats_.nodes_unexplored; update the while
condition in the main loop that uses solver_status_, abs_gap, rel_gap to also
require any active worker across all types (sum or check active_workers_per_type
for all indices) and include both queue sizes (use
node_queue_.best_first_queue_size() plus the diving queue size such as
node_queue_.diving_queue_size() or diving_heap size) so the loop stays alive
while any worker or any queue has nodes; additionally, whenever a node is popped
and then skipped/discarded via the continue paths (the fathom/depth-filter
checks around where nodes are popped — refer to the pop/continue blocks near
lines handling best-first and diving pops), decrement
exploration_stats_.nodes_unexplored before continuing so unexplored node counts
remain accurate for infeasibility detection and logging.
🧹 Nitpick comments (1)
cpp/src/dual_simplex/branch_and_bound.hpp (1)
158-160: Avoidstd::stringby-value in hot-path logging APIs.
report(std::string symbol, ...)(Line 159) forces allocations/copies; preferconst char*orstd::string_view.Proposed diff
- void report(std::string symbol, f_t obj, f_t lower_bound, i_t node_depth); + void report(std::string_view symbol, f_t obj, f_t lower_bound, i_t node_depth);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{cu,cuh,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh,cpp,hpp,h}: Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Check that hard-coded GPU de...
Files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cpp,hpp,h}: Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Validate input sanitization to prevent buffer overflows and resource exhaustion attacks; avoid unsafe deserialization of problem files
Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{cu,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{h,hpp,py}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Verify C API does not break ABI stability (no struct layout changes, field reordering); maintain backward compatibility in Python and server APIs with deprecation warnings
Files:
cpp/src/dual_simplex/branch_and_bound.hpp
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Test with free variables, singleton problems, and extreme problem dimensions near resource limits to validate edge case handling
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh} : Avoid reinventing functionality already available in Thrust, CCCL, or RMM libraries; prefer standard library utilities over custom implementations
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cpp,hpp,h} : Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.cu : Verify race conditions and correctness of GPU kernel shared memory, atomics, and warp-level operations
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*test*.{cpp,cu,py} : Add tests for algorithm phase transitions: verify correct initialization of bounds and state when transitioning from presolve to simplex to diving to crossover
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-12-04T20:09:09.264Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 602
File: cpp/src/linear_programming/solve.cu:732-742
Timestamp: 2025-12-04T20:09:09.264Z
Learning: In cpp/src/linear_programming/solve.cu, the barrier solver does not currently return INFEASIBLE or UNBOUNDED status. It only returns OPTIMAL, TIME_LIMIT, NUMERICAL_ISSUES, or CONCURRENT_LIMIT.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-12-04T04:11:12.640Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 500
File: cpp/src/dual_simplex/scaling.cpp:68-76
Timestamp: 2025-12-04T04:11:12.640Z
Learning: In the cuOPT dual simplex solver, CSR/CSC matrices (including the quadratic objective matrix Q) are required to have valid dimensions and indices by construction. Runtime bounds checking in performance-critical paths like matrix scaling is avoided to prevent slowdowns. Validation is performed via debug-only check_matrix() calls wrapped in #ifdef CHECK_MATRIX.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.cppcpp/src/dual_simplex/branch_and_bound.hpp
📚 Learning: 2025-10-22T14:25:22.899Z
Learnt from: aliceb-nv
Repo: NVIDIA/cuopt PR: 527
File: cpp/src/mip/diversity/lns/rins.cu:167-175
Timestamp: 2025-10-22T14:25:22.899Z
Learning: In MIP (Mixed Integer Programming) problems in the cuOPT codebase, `n_integer_vars == 0` is impossible by definition—MIP problems must have at least one integer variable. If there are no integer variables, it would be a pure Linear Programming (LP) problem, not a MIP problem.
Applied to files:
cpp/src/dual_simplex/branch_and_bound.hpp
🧬 Code graph analysis (1)
cpp/src/dual_simplex/branch_and_bound.hpp (2)
cpp/src/dual_simplex/bnb_worker.hpp (3)
lower_bound(219-230)node_ptr(127-146)node_ptr(127-128)cpp/src/dual_simplex/mip_node.hpp (6)
node_ptr(277-283)node_ptr(277-277)log(329-337)log(329-332)log(339-354)log(339-344)
🪛 Clang (14.0.6)
cpp/src/dual_simplex/branch_and_bound.cpp
[error] 8-8: 'dual_simplex/branch_and_bound.hpp' file not found
(clang-diagnostic-error)
cpp/src/dual_simplex/branch_and_bound.hpp
[error] 10-10: 'dual_simplex/bnb_worker.hpp' file not found
(clang-diagnostic-error)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.11, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.12, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.13, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.10, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.13, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.10, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.1.0, 3.12, arm64, rockylinux8
🔇 Additional comments (2)
cpp/src/dual_simplex/branch_and_bound.cpp (1)
646-647: Nice: bounds reset + strengthening is clearly centralized in worker_data.
worker_data->set_lp_variable_bounds_for(...)(Line 646) looks like the right place to guarantee per-node bound initialization and avoid stale state across phases. Based on learnings, this kind of explicit reset is important when transitioning between exploration/diving/crossover phases.cpp/src/dual_simplex/branch_and_bound.hpp (1)
10-15: Includes are correctly configured and present in the repository.All referenced headers (
bnb_worker.hpp,diving_heuristics.hpp,initial_basis.hpp,mip_node.hpp,node_queue.hpp,phase2.hpp) exist incpp/src/dual_simplex/and the CMake configuration correctly addscpp/srcto the private include directories for thecuopttarget. The#include <dual_simplex/...>directives will resolve properly during compilation.Likely an incorrect or invalid review comment.
This PR rewrites the parallel B&B to use the master-worker model, which enables reliability branching and determinism mode. This PR should only be merged after #697.
MIPLIB2017 (GH200):
226feasible solutions with12%average primal gap (same as #697).Closes #526.
Closes #445.
Checklist
Summary by CodeRabbit
New Features
Improvements
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.