Skip to content

Conversation

@nguidotti
Copy link
Contributor

@nguidotti nguidotti commented Jan 9, 2026

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):
226 feasible solutions with 12% average primal gap (same as #697).

Closes #526.
Closes #445.

Checklist

  • I am familiar with the Contributing Guidelines.
  • Testing
    • New or existing tests cover these changes
    • Added tests
    • Created an issue to follow-up
    • NA
  • Documentation
    • The documentation is up to date with these changes
    • Added new documentation
    • NA

Summary by CodeRabbit

  • New Features

    • Multiple diving heuristics added (line-search, pseudocost, guided, coefficient) for improved branching.
    • Worker-pool and dual-queue support to enable richer, configurable parallel B&B exploration.
  • Improvements

    • Bounds-aware basis repair and stronger bounds-strengthening controls for more robust solves.
    • Better thread-safety and atomic/lock improvements; logging moved to debug-level where appropriate.
  • Refactor

    • Threading configuration reorganized to a worker/ diving-settings model for clearer controls.

✏️ Tip: You can customize this high-level summary in your review settings.

nguidotti and others added 30 commits December 12, 2025 10:22
…iteration and node limit to the diving threads.
@nguidotti nguidotti added this to the 26.02 milestone Jan 9, 2026
@nguidotti nguidotti self-assigned this Jan 9, 2026
@nguidotti nguidotti requested review from a team as code owners January 9, 2026 14:39
@nguidotti nguidotti added the non-breaking Introduces a non-breaking change label Jan 9, 2026
@nguidotti nguidotti requested a review from tmckayus January 9, 2026 14:39
@nguidotti nguidotti added improvement Improves an existing functionality mip labels Jan 9, 2026
@aliceb-nv
Copy link
Contributor

Awesome work getting this pushed so soon Nicolas :)
Let's focus on merging your dependent branches ASAP so that we can get going with this one as well. It will be easier to review as a result (since it will only contain your master-worker changes)

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Introduces 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

Cohort / File(s) Summary
B&B Worker & Types
cpp/src/dual_simplex/bnb_worker.hpp
New worker-type enum, per-worker stats/data classes, worker-pool API and utilities for selecting worker types and round-robin counts.
Branch-and-Bound Core
cpp/src/dual_simplex/branch_and_bound.hpp, cpp/src/dual_simplex/branch_and_bound.cpp
Large refactor to per-type worker model: replaces legacy thread enums/heap with worker pool and node_queue_t, adds Arow_, plunge/dive flows, per-type solve signatures, reporting helpers, and many public-signature adjustments.
Node Queue / Heaps
cpp/src/dual_simplex/node_queue.hpp
New generic heap wrapper and dual-priority node_queue_t (best-first and diving heaps) with thread-safe push/pop and lower-bound queries.
Diving Heuristics
cpp/src/dual_simplex/diving_heuristics.hpp, cpp/src/dual_simplex/diving_heuristics.cpp
New branch_variable_t type and implementations for line-search, pseudocost, guided, coefficient diving, plus helper to compute variable locks and explicit instantiations.
Removed: Legacy Diving Queue
cpp/src/dual_simplex/diving_queue.hpp
Deleted legacy diving_root_t and diving_queue_t (min-heap) replaced by node_queue and worker pool.
Basis Repair / Refactor Bounds
cpp/src/dual_simplex/basis_solves.hpp, cpp/src/dual_simplex/basis_solves.cpp, cpp/src/dual_simplex/basis_updates.hpp, cpp/src/dual_simplex/basis_updates.cpp
basis_repair and refactor_basis signatures extended to accept lower/upper vectors; nonbasic status assignment made bounds-aware; call sites updated.
Call Site Updates (repair/refactor)
cpp/src/dual_simplex/crossover.cpp, cpp/src/dual_simplex/primal.cpp, cpp/src/dual_simplex/phase2.cpp
Updated calls to pass lp.lower/lp.upper to basis_repair/refactor_basis; phase2 also updates compute_initial_primal_infeasibilities outputs.
Bounds Strengthening API
cpp/src/dual_simplex/bounds_strengthening.hpp, cpp/src/dual_simplex/bounds_strengthening.cpp, cpp/src/dual_simplex/presolve.cpp
Removed internal bounds_changed member; bounds_strengthening now accepts const std::vector<bool>& bounds_changed; call sites updated.
Pseudo-Costs Enhancements
cpp/src/dual_simplex/pseudo_costs.hpp, cpp/src/dual_simplex/pseudo_costs.cpp
Added obj_estimate API; replaced manual mutex ops with std::lock_guard<omp_mutex_t>; logging switched to log.debug.
Phase2 Changes
cpp/src/dual_simplex/phase2.cpp
compute_initial_primal_infeasibilities gains f_t& primal_inf output; returns squared infeasibility; updated usages and refactor_basis bound passing.
Settings & Logging
cpp/src/dual_simplex/simplex_solver_settings.hpp, cpp/src/dual_simplex/logger.hpp
Adds diving_heuristics_settings_t and diving_settings in solver settings; renames num_bfs_threads→num_bfs_workers; logger file-mode APIs const-corrected.
MIP Integration Changes
cpp/src/mip/solver.cu, cpp/src/mip/diversity/lns/rins.cu, cpp/src/mip/diversity/recombiners/sub_mip.cuh
Update B&B thread/worker configuration to use new num_bfs_workers and diving_settings; restrict diving heuristics in RINS/sub-MIP contexts.
Node & Utilities
cpp/src/dual_simplex/mip_node.hpp, cpp/src/utilities/omp_helpers.hpp
Added objective_estimate to mip_node_t; removed node_compare_t; omp_atomic_t::load() made const-qualified.
Basis Files & CMake
cpp/src/dual_simplex/CMakeLists.txt
Added diving_heuristics.cpp to build and updated license year.
Various small changes
multiple files (logger, headers, copyright lines)
Minor API tweaks, logging callsite changes, copyright year updates across files.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Master-Worker Framework for B&B' accurately describes the primary architectural change in this PR - replacing the parallel branch-and-bound implementation with a master-worker model.
Linked Issues check ✅ Passed The PR addresses both linked issues: #526 (report/repair separation) via plunge_with/dive_with worker methods and #445 (improved lower bound via worker-based aggregation from multiple sources).
Out of Scope Changes check ✅ Passed All changes are directly related to the master-worker framework implementation. The worker pool infrastructure, diving heuristics, bounds management, and basis operations are all integral to the new architecture.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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: Make operator T() const to align with load() const (avoids const-read compilation failures).
Right now, const omp_atomic_t<T> can call load() 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 when fractional is empty.

Static analysis flagged line 314: if fractional is empty, the loop on lines 303-309 never executes, leaving select = -1. The subsequent access score[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 calling get_lower_bound() while holding mutex_upper_ (lock-ordering risk).

add_feasible_solution() holds mutex_upper_ and calls report(... get_lower_bound() ...), where get_lower_bound() locks node_queue. If any other path ever locks node_queue then tries to lock mutex_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_criteria function, the bounds should be computed from val (the current node solution), not root_val (the root LP solution). The current implementation uses floor(root_val) and ceil(root_val) for bounds, but distances as val - down_val and up_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) and ceil(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 (both f_t) and assigns to lp_settings.iteration_limit (type i_t). Additionally, total_lp_iters is stored as omp_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_ti_t implicit conversion. Consider:

  • Either store total_lp_iters as i_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 for branch_and_bound_t to prevent unsafe mutex/atomic sharing.

The class contains omp_mutex_t members (mutex_upper_, mutex_repair_) and atomic state (upper_bound_, solver_status_, etc.) that manage critical parallel resources. While omp_mutex_t and omp_atomic_t are 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() returns primal_inf_squared (sum of squared infeasibilities) but outputs via reference primal_inf as the sum of unsquared infeasibilities. Later, update_single_primal_infeasibility() at line 2851 receives primal_infeasibility (unsquared) but treats it as a squared sum by performing primal_inf += (new_val - old_val) where both new_val and old_val are squared values. This corrupts primal_infeasibility, which is then used for pricing decisions, termination checks, and recompute conditions.

In contrast, update_primal_infeasibilities() (lines 2828, 2840) correctly receives primal_infeasibility_squared and 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_UPPER

The 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_strengthening to false, and line 624 uses if 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 true is 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.hpp declares 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

📥 Commits

Reviewing files that changed from the base of the PR and between 392e7a0 and 421cbfd.

📒 Files selected for processing (28)
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/basis_updates.hpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/dual_simplex/diving_queue.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/phase2.cpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/mip/solver.cu
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cuh
  • cpp/src/mip/solver.cu
  • cpp/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.cu
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/primal.cpp
  • cpp/src/utilities/omp_helpers.hpp
  • cpp/src/mip/diversity/recombiners/sub_mip.cuh
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/mip_node.hpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/pseudo_costs.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/pseudo_costs.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/basis_solves.hpp
  • cpp/src/dual_simplex/logger.hpp
  • cpp/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.txt
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.txt
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/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.txt
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • 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 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.cpp
  • cpp/src/dual_simplex/diving_heuristics.hpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_updates.cpp
  • cpp/src/dual_simplex/crossover.cpp
  • cpp/src/dual_simplex/presolve.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/mip/diversity/lns/rins.cu
  • cpp/src/dual_simplex/bounds_strengthening.cpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • 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/diving_heuristics.hpp
  • cpp/src/mip/solver.cu
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cu
  • cpp/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.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/basis_solves.cpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/src/dual_simplex/simplex_solver_settings.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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_t struct 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 = -1 sentinel 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_workers and num_diving_workers represent 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 exactly num_threads threads. 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 lower and upper bounds to refactor_basis enables 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_estimate method 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_estimate field is correctly:

  1. Initialized to infinity in root/default constructors
  2. Inherited from parent during child node construction
  3. Copied in detach_copy() for node serialization

This 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 new objective_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_repair is properly updated to include the new lower and upper bound parameters.

cpp/src/mip/diversity/recombiners/sub_mip.cuh (1)

106-117: LGTM! Updated to new worker-based configuration.

The configuration properly:

  1. Uses num_bfs_workers instead of the old num_bfs_threads
  2. Restricts diving to guided diving only (appropriate for sub-MIP where exploration budget is limited)
  3. Updates the solution_callback lambda 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.cpp and diving_heuristics.cpp files 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 mode parameter to enable_log_to_file and set_log_file provides flexibility for append mode logging while maintaining backward compatibility via the default "w" argument.


46-51: Good fix: proper state reset in close_log_file.

Explicitly resetting log_file to nullptr and log_to_file to false prevents 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_repair call now passes lp.lower and lp.upper, aligning with the new signature in basis_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 calculates num_bfs_workers=1 and num_diving_workers=1 (due to max(1, 1-1)), resulting in 2 workers for 1 thread. Similarly for num_threads=2 or 3.

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 lower and upper parameters 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_guard instead of manual lock/unlock ensures the mutex is released even if an exception occurs.


319-362: LGTM! New obj_estimate function 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 since A is 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_changed parameter 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 printf to log.debug is 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.

Comment on lines 1217 to 1363
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)); }
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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:


🌐 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 taskyield syntax 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 taskyield behavior.
  • The affinity clause (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.

Copy link

@coderabbitai coderabbitai bot left a 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 whether bounds_changed is an input mask or an output report (current const& implies input).
As-is, the name reads like an output (“these bounds were changed”), but const 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/assume bounds_changed*.size() == lower_bounds.size() == upper_bounds.size() (or problem.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

📥 Commits

Reviewing files that changed from the base of the PR and between 421cbfd and 6faeed0.

📒 Files selected for processing (3)
  • cpp/src/dual_simplex/bnb_worker.cpp
  • cpp/src/dual_simplex/bounds_strengthening.hpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • 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} : 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.cpp
  • 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 **/*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.cpp
  • cpp/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:

  1. Each worker is accessed exclusively by a single thread at a time, or
  2. 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.

Copy link

@coderabbitai coderabbitai bot left a 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_t for 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_t instances between both heaps via shared_ptr, with std::exchange nulling the node pointer when popped from one heap (line 120). The pop_diving method 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_diving may iterate through multiple nulled entries in O(n) worst case

For 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6faeed0 and d7046e3.

📒 Files selected for processing (5)
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/src/dual_simplex/diving_heuristics.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.cpp
  • 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/diving_heuristics.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • 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/diving_heuristics.cpp
  • 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/diving_heuristics.cpp
  • cpp/src/dual_simplex/node_queue.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/branch_and_bound.hpp
  • cpp/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.hpp
  • cpp/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.hpp
  • cpp/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.cpp
  • cpp/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, double type pair.

cpp/src/dual_simplex/node_queue.hpp (1)

23-65: LGTM!

The heap_t template provides a clean wrapper around STL heap functions with good use of std::optional for the pop() 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_t for 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_workers by 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_t class 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_first is straightforward and correct

127-160: Verify the split get/pop pattern is used correctly.

The worker pool provides separate get_idle_worker() and pop_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() with pop_idle_worker(), or use the combined get_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_t replaces the old heap with dual-priority queue
  • bnb_worker_pool_t and 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_solution now distinguishes solutions by worker type
  • solve_node receives worker context for per-type state management
  • variable_selection dispatches to the appropriate diving heuristic based on type
  • New plunge_with and dive_with methods encapsulate worker-driven exploration

These changes properly support the master-worker architecture.

cpp/src/dual_simplex/branch_and_bound.cpp (7)

240-247: LGTM!

The get_lower_bound method correctly aggregates lower bounds from multiple sources:

  • lower_bound_ceiling_ captures numerical issue bounds from EXPLORATION workers
  • node_queue.get_lower_bound() returns the best node in the queue
  • worker_pool_.get_lower_bounds() returns bounds from active EXPLORATION workers

The use of std::min and returning -inf for non-finite values ensures sound bound tracking.


567-605: LGTM!

The variable_selection refactoring correctly dispatches to per-type heuristics:

  • EXPLORATION uses pseudo-costs + Martin's criteria and updates objective_estimate for 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_estimate since 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_factor is 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_with method 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_with method 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_queue and worker_pool_, and atomics for upper_bound_

Based on coding guidelines: Thread-safety properly handled through synchronization primitives.

Copy link

@coderabbitai coderabbitai bot left a 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 between get_idle_worker() and pop_idle_worker().

The separate get_idle_worker() and pop_idle_worker() methods create a window where another thread could pop the same worker between the get and pop calls. While get_and_pop_idle_worker() exists as an atomic alternative, the current usage in branch_and_bound.cpp (lines 1306-1324, 1346-1347) calls get_idle_worker() first to check availability, then performs work initialization, and only then calls pop_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_selection returns {-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 break statements (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_pool is always called.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7046e3 and 14441d1.

📒 Files selected for processing (4)
  • cpp/src/dual_simplex/CMakeLists.txt
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.hpp
  • cpp/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.txt
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.txt
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.txt
  • cpp/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.txt
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.txt
  • 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} : 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.txt
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.txt
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.txt
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/src/dual_simplex/bnb_worker.hpp
  • cpp/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.cpp
  • cpp/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.cpp source 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_t structure correctly uses atomic types for fields that are accessed concurrently across threads (total_lp_solve_time, nodes_explored, etc.), while start_time is appropriately non-atomic since it's set once before parallel execution begins.


219-230: LGTM!

The get_lower_bounds() implementation is thread-safe: the workers_ 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 new mip_node_t via the constructor that accepts vstatus by const reference, triggering std::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 in internal_node (a member variable), so start_node points 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 -inf for 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_t using move semantics from the worker's start_node. This isolation ensures diving operations don't corrupt the global search tree state. The local dive_stats properly 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 = false before 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 parallel region (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_type array with atomic elements properly tracks concurrent worker counts per type, and worker_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_with and dive_with methods clearly express their intent as worker-based tree traversal operations. The solve_node_lp method signature correctly includes all necessary context (node, worker data, stats, logger) for LP relaxation solving.


80-80: New public accessor get_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.

Copy link

@coderabbitai coderabbitai bot left a 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 dereferenced std::atomic<int> to 0.

*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 holding mutex_upper_.

settings_.solution_callback(...) is invoked under mutex_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: Avoid std::string by-value in hot-path logging APIs.

report(std::string symbol, ...) (Line 159) forces allocations/copies; prefer const char* or std::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

📥 Commits

Reviewing files that changed from the base of the PR and between 14441d1 and 89cc6de.

📒 Files selected for processing (2)
  • cpp/src/dual_simplex/branch_and_bound.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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.cpp
  • cpp/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
  • cpp/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.cpp
  • cpp/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 in cpp/src/dual_simplex/ and the CMake configuration correctly adds cpp/src to the private include directories for the cuopt target. The #include <dual_simplex/...> directives will resolve properly during compilation.

Likely an incorrect or invalid review comment.

@nguidotti nguidotti mentioned this pull request Jan 14, 2026
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality mip non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEA] Move report/repair to a separated task during the ramp up phase [FEA] Improve the lower bound calculation in the ramp-up phase

3 participants