-
Notifications
You must be signed in to change notification settings - Fork 104
Diving Improvements #697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Diving Improvements #697
Conversation
… on the objective pseudcost estimate.
… on the objective pseudcost estimate.
📝 WalkthroughWalkthroughIntroduces new diving heuristic implementations and a node_queue scheduler, replaces the old diving_queue, extends basis repair and refactor interfaces with LP bounds, changes pseudo-costs and phase2 APIs, expands branching thread types to multi-strategy bnb_thread_type_t, and updates related settings, logging, and call sites. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas needing focused review:
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
cpp/src/dual_simplex/phase2.cpp (1)
2837-2858: Passprimal_infeasibility_squaredinstead ofprimal_infeasibilitytoupdate_single_primal_infeasibilityat line 2858.The previous two calls to
update_primal_infeasibilities(lines 2837 and 2849) correctly accumulate squared infeasibility changes intoprimal_infeasibility_squared. However,update_single_primal_infeasibilityalso operates on squared infeasibilities internally (computinginfeas * infeasand accumulating viaprimal_inf + (new_val - old_val)), so it should update the same accumulator. Passingprimal_infeasibilityinstead breaks infeasibility tracking—the entering variable's squared infeasibility delta is accumulated into the wrong variable, leavingprimal_infeasibility_squaredincomplete.
🧹 Nitpick comments (8)
cpp/src/mip/diversity/recombiners/sub_mip.cuh (1)
108-114: Diving heuristics temporarily restricted with clear intent.The explicit configuration disables most diving heuristics (guided, coefficient, pseudocost) for SubMIP, restricting to line search diving only. The comment clearly indicates this is a temporary restriction pending future enablement of all heuristics.
Consider extracting this diving configuration pattern into a helper function since the same configuration appears in multiple files (sub_mip.cuh and rins.cu). This would reduce duplication and make future updates easier.
// Example helper static auto create_line_search_only_diving_settings() { diving_heuristics_settings_t settings; settings.num_diving_tasks = 1; settings.disable_guided_diving = true; settings.disable_coefficient_diving = true; settings.disable_pseudocost_diving = true; return settings; }Based on coding guidelines: refactor code duplication in solver components.
cpp/src/mip/diversity/lns/rins.cu (1)
258-270: Branch-and-bound settings correctly updated for new diving API.The configuration properly integrates the new
diving_settingsstructure while preserving existing behavior for threading, tolerances, logging, and callbacks. The temporary restriction to line search diving only is clearly documented.This file contains the same diving configuration pattern as
sub_mip.cuh. Consider consolidating this repeated configuration into a shared helper function to reduce duplication.Based on coding guidelines: refactor code duplication in solver components (3+ occurrences).
cpp/src/dual_simplex/diving_heuristics.hpp (1)
10-13: Consider adding explicit logger include.
logger_t&is used in all function signatures, but the header relies on transitive inclusion throughpseudo_costs.hpp. For better header self-containment and faster compile times, consider adding an explicit include or forward declaration:#include <dual_simplex/basis_updates.hpp> #include <dual_simplex/bounds_strengthening.hpp> #include <dual_simplex/pseudo_costs.hpp> +#include <dual_simplex/logger.hpp> #include <vector>cpp/src/dual_simplex/basis_solves.cpp (1)
663-671: Logic flow issue: condition at line 667 may be unreachable in practice.The current logic:
- Line 663: If
lower == -inf && upper == inf→ FREE- Line 665: Else if
lower > -inf→ LOWER- Line 667: Else if
upper < inf→ UPPER- Line 669: Else → assert
At line 667, we know
lower[bad_j] <= -inf(from failing line 665). Combined with failing line 663, we must haveupper[bad_j] < inf, so the condition is always true when reached. Theelseat line 669 is dead code.Consider simplifying:
if (lower[bad_j] == -inf && upper[bad_j] == inf) { vstatus[bad_j] = variable_status_t::NONBASIC_FREE; } else if (lower[bad_j] > -inf) { vstatus[bad_j] = variable_status_t::NONBASIC_LOWER; - } else if (upper[bad_j] < inf) { - vstatus[bad_j] = variable_status_t::NONBASIC_UPPER; } else { - assert(1 == 0); + vstatus[bad_j] = variable_status_t::NONBASIC_UPPER; }The assert is unnecessary since the logic is exhaustive.
cpp/src/dual_simplex/diving_heuristics.cpp (1)
49-55: Edge case: emptyfractionalvector causes undefined behavior.If
fractionalis empty, the fallback at line 50 accessesfractional[0]which is undefined, and the assertions at lines 54-55 will fail. While callers should ensurefractionalis non-empty, defensive handling would improve robustness:if (round_dir == rounding_direction_t::NONE) { + assert(!fractional.empty() && "line_search_diving called with empty fractional list"); branch_var = fractional[0]; round_dir = rounding_direction_t::DOWN; } - - assert(round_dir != rounding_direction_t::NONE); - assert(branch_var >= 0);cpp/src/dual_simplex/node_queue.hpp (3)
33-38: Incorrect use ofstd::forwardwith doubly-referenced type.The
Args&&in the template parameter already declares forwarding references. Usingstd::forward<Args&&>adds an extra&&, which is redundant and could cause issues with some compilers.template <typename... Args> void emplace(Args&&... args) { - buffer.emplace_back(std::forward<Args&&>(args)...); + buffer.emplace_back(std::forward<Args>(args)...); std::push_heap(buffer.begin(), buffer.end(), comp); }
136-146: Potential integer type narrowing in size accessors.
heap_t::size()returnssize_t, butdiving_queue_size()andbest_first_queue_size()returni_t(typicallyint). For very large heaps exceedingINT_MAX, this could cause truncation.Consider returning
size_tor usingstatic_castwith appropriate bounds checking:- i_t diving_queue_size() + size_t diving_queue_size() { std::lock_guard<omp_mutex_t> lock(mutex); return diving_heap.size(); } - i_t best_first_queue_size() + size_t best_first_queue_size() { std::lock_guard<omp_mutex_t> lock(mutex); return best_first_heap.size(); }
116-134: Stale entries indiving_heapcause O(n) iterations inpop_diving().Both
best_first_heapanddiving_heapreference the sameheap_entry_tobjects viashared_ptr. Whenpop_best_first()executesstd::exchange(entry.value()->node, nullptr)at line 110, it nullifies the entry's node pointer. However, the entry itself remains indiving_heap. Subsequent calls topop_diving()must iterate through these stale entries (lines 122–130) until finding a valid one, resulting in O(n) complexity where n is the number of stale entries accumulated.Consider maintaining a count of valid entries or implementing atomic removal from both heaps to avoid worst-case iteration when heavy best-first activity precedes diving operations.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
cpp/src/dual_simplex/CMakeLists.txt(1 hunks)cpp/src/dual_simplex/basis_solves.cpp(3 hunks)cpp/src/dual_simplex/basis_solves.hpp(1 hunks)cpp/src/dual_simplex/basis_updates.cpp(2 hunks)cpp/src/dual_simplex/basis_updates.hpp(1 hunks)cpp/src/dual_simplex/bounds_strengthening.cpp(2 hunks)cpp/src/dual_simplex/branch_and_bound.cpp(30 hunks)cpp/src/dual_simplex/branch_and_bound.hpp(8 hunks)cpp/src/dual_simplex/crossover.cpp(3 hunks)cpp/src/dual_simplex/diving_heuristics.cpp(1 hunks)cpp/src/dual_simplex/diving_heuristics.hpp(1 hunks)cpp/src/dual_simplex/diving_queue.hpp(0 hunks)cpp/src/dual_simplex/logger.hpp(1 hunks)cpp/src/dual_simplex/mip_node.hpp(4 hunks)cpp/src/dual_simplex/node_queue.hpp(1 hunks)cpp/src/dual_simplex/phase2.cpp(12 hunks)cpp/src/dual_simplex/primal.cpp(1 hunks)cpp/src/dual_simplex/pseudo_costs.cpp(4 hunks)cpp/src/dual_simplex/pseudo_costs.hpp(1 hunks)cpp/src/dual_simplex/simplex_solver_settings.hpp(3 hunks)cpp/src/mip/diversity/lns/rins.cu(1 hunks)cpp/src/mip/diversity/recombiners/sub_mip.cuh(1 hunks)cpp/src/mip/solver.cu(1 hunks)
💤 Files with no reviewable changes (1)
- cpp/src/dual_simplex/diving_queue.hpp
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{cu,cuh,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh,cpp,hpp,h}: Track GPU device memory allocations and deallocations to prevent memory leaks; ensure cudaMalloc/cudaFree balance and cleanup of streams/events
Validate algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Check numerical stability: prevent overflow/underflow, precision loss, division by zero/near-zero, and use epsilon comparisons for floating-point equality checks
Validate correct initialization of variable bounds, constraint coefficients, and algorithm state before solving; ensure reset when transitioning between algorithm phases (presolve, simplex, diving, crossover)
Ensure variables and constraints are accessed from the correct problem context (original vs presolve vs folded vs postsolve); verify index mapping consistency across problem transformations
For concurrent CUDA operations (barriers, async operations), explicitly create and manage dedicated streams instead of reusing the default stream; document stream lifecycle
Eliminate unnecessary host-device synchronization (cudaDeviceSynchronize) in hot paths that blocks GPU pipeline; use streams and events for async execution
Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Verify correct problem size checks before expensive GPU/CPU operations; prevent resource exhaustion on oversized problems
Identify assertions with overly strict numerical tolerances that fail on legitimate degenerate/edge cases (near-zero pivots, singular matrices, empty problems)
Ensure race conditions are absent in multi-GPU code and multi-threaded server implementations; verify proper synchronization of shared state
Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Check that hard-coded GPU de...
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cucpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/branch_and_bound.cpp
**/*.{h,hpp,py}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Verify C API does not break ABI stability (no struct layout changes, field reordering); maintain backward compatibility in Python and server APIs with deprecation warnings
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hpp
**/*.{cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cpp,hpp,h}: Check for unclosed file handles when reading MPS/QPS problem files; ensure RAII patterns or proper cleanup in exception paths
Validate input sanitization to prevent buffer overflows and resource exhaustion attacks; avoid unsafe deserialization of problem files
Prevent thread-unsafe use of global and static variables; use proper mutex/synchronization in server code accessing shared solver state
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/branch_and_bound.cpp
**/*.{cu,cpp,hpp,h}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
Avoid inappropriate use of exceptions in performance-critical GPU operation paths; prefer error codes or CUDA error checking for latency-sensitive code
Files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/logger.hppcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cucpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/src/dual_simplex/branch_and_bound.cpp
**/*.{cu,cuh}
📄 CodeRabbit inference engine (.github/.coderabbit_review_guide.md)
**/*.{cu,cuh}: Every CUDA kernel launch and memory operation must have error checking with CUDA_CHECK or equivalent verification
Avoid reinventing functionality already available in Thrust, CCCL, or RMM libraries; prefer standard library utilities over custom implementations
Files:
cpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.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/diversity/lns/rins.cucpp/src/mip/solver.cu
🧠 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
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)
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
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
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/mip/solver.cucpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/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/basis_updates.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/mip/diversity/recombiners/sub_mip.cuhcpp/src/dual_simplex/CMakeLists.txtcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cucpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/mip_node.hppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/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 algorithm correctness in optimization logic: simplex pivots, branch-and-bound decisions, routing heuristics, and constraint/objective handling must produce correct results
Applied to files:
cpp/src/dual_simplex/basis_updates.hppcpp/src/dual_simplex/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.hppcpp/src/dual_simplex/CMakeLists.txtcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cucpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/pseudo_costs.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/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/bounds_strengthening.cppcpp/src/mip/solver.cucpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/pseudo_costs.cppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/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/bounds_strengthening.cppcpp/src/dual_simplex/CMakeLists.txtcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cucpp/src/dual_simplex/primal.cppcpp/src/dual_simplex/crossover.cppcpp/src/dual_simplex/basis_updates.cppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/basis_solves.cppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/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} : 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/bounds_strengthening.cppcpp/src/dual_simplex/basis_solves.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/bounds_strengthening.cppcpp/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} : 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/bounds_strengthening.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Refactor code duplication in solver components (3+ occurrences) into shared utilities; for GPU kernels, use templated device functions to avoid duplication
Applied to files:
cpp/src/dual_simplex/CMakeLists.txtcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cucpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/node_queue.hppcpp/src/dual_simplex/branch_and_bound.hppcpp/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/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} : 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.txtcpp/src/mip/diversity/lns/rins.cucpp/src/mip/solver.cu
📚 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
📚 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 **/*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-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/mip/solver.cucpp/src/dual_simplex/diving_heuristics.hppcpp/src/dual_simplex/phase2.cppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.hppcpp/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/mip/solver.cucpp/src/dual_simplex/pseudo_costs.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/basis_solves.cppcpp/src/dual_simplex/branch_and_bound.hpp
🧬 Code graph analysis (11)
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/logger.hpp (1)
cpp/src/dual_simplex/simplex_solver_settings.hpp (2)
log_filename(99-99)log_filename(99-99)
cpp/src/dual_simplex/primal.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/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_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/basis_solves.cpp (1)
cpp/src/dual_simplex/presolve.cpp (3)
lower(240-240)upper(85-85)upper(241-241)
cpp/src/dual_simplex/diving_heuristics.hpp (2)
cpp/src/dual_simplex/pseudo_costs.hpp (2)
fractional(46-49)fractional(51-52)cpp/src/dual_simplex/simplex_solver_settings.hpp (2)
log(98-98)log(100-100)
cpp/src/dual_simplex/pseudo_costs.cpp (1)
cpp/src/dual_simplex/pseudo_costs.hpp (2)
fractional(46-49)fractional(51-52)
cpp/src/dual_simplex/phase2.cpp (1)
cpp/src/dual_simplex/primal.cpp (2)
primal_infeasibility(202-240)primal_infeasibility(202-205)
cpp/src/dual_simplex/node_queue.hpp (1)
cpp/src/dual_simplex/mip_node.hpp (4)
lower(97-108)lower(97-99)lower(112-130)lower(112-114)
cpp/src/dual_simplex/branch_and_bound.hpp (1)
cpp/src/dual_simplex/node_queue.hpp (4)
node(21-25)node(21-21)node(27-31)node(27-27)
⏰ 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.0.2, 3.11, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.0.2, 3.13, arm64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.0.2, 3.10, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.0.2, 3.13, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-mps-parser / 13.0.2, 3.11, amd64, rockylinux8
- GitHub Check: wheel-build-cuopt-sh-client / 13.0.2, 3.10, amd64, rockylinux8
- GitHub Check: checks / check-style
🔇 Additional comments (39)
cpp/src/dual_simplex/CMakeLists.txt (1)
34-34: LGTM!The addition of
diving_heuristics.cppto the build aligns with the PR objectives to introduce new diving heuristic strategies.cpp/src/dual_simplex/bounds_strengthening.cpp (2)
157-164: Logging level correctly adjusted to debug.The change from
printftosettings.log.debug()appropriately reduces stdout noise while preserving diagnostic information for debugging. This is proper logging hygiene for infeasibility detection during bounds strengthening iterations.
214-216: Logging level correctly adjusted to debug.Consistent with the previous logging change, this infeasibility message is appropriately moved to debug level logging.
cpp/src/dual_simplex/primal.cpp (1)
301-309: All basis_repair call sites have been consistently updated with bound parameters.The call in
primal.cppat lines 301-309 correctly passeslp.lowerandlp.upperas the 3rd and 4th parameters. Verification confirms this pattern is consistent across all five basis_repair call sites in the codebase:
primal.cpp:301- passeslp.lower, lp.uppercrossover.cpp:788, 1142, 1341- all passlp.lower, lp.upperbasis_updates.cpp:2071- passeslower, upper(local variables in templated context)This ensures bounds-aware basis repair during algorithm phase transitions (simplex, crossover phases).
cpp/src/mip/solver.cu (1)
176-180: Threading configuration correctly refactored for new diving_settings structure.The code properly updates the thread distribution logic to use the new
diving_settings.num_diving_tasksfield instead of the previousnum_diving_threads. The thread allocation strategy remains unchanged (BFS threads = num_threads/4, diving tasks = remaining threads).cpp/src/dual_simplex/pseudo_costs.hpp (1)
46-49: API change correctly expands pseudo-cost functionality.The function signature update from
variable_selectiontovariable_selection_and_obj_estimateproperly reflects the expanded responsibility: returning both the selected variable index and an objective estimate. The addition of thelower_boundparameter enables more sophisticated objective estimation for diving heuristics.All call sites have been correctly updated. The old
variable_selectionfunction is preserved as a backward-compatibility wrapper that properly unpacks the returned pair viastd::tie, stores the objective estimate in node state for search tree ordering, and returns the branch decision. New call sites directly usevariable_selection_and_obj_estimatewith proper structured binding to capture both returned elements.cpp/src/dual_simplex/logger.hpp (1)
33-44: LGTM! Backward-compatible API refinement.The change from
std::stringtoconst char*for the mode parameter avoids unnecessary string construction when passing literals. The default value"w"ensures backward compatibility with existing callers likeset_log_filenamethat don't specify a mode.cpp/src/dual_simplex/basis_solves.hpp (1)
42-51: LGTM! Bound-aware basis repair signature.The addition of
lowerandupperbound vectors enablesbasis_repairto correctly assign variable status (NONBASIC_FREE, NONBASIC_LOWER, or NONBASIC_UPPER) for variables being removed from the basis. This is essential for maintaining dual feasibility during repair operations. Based on coding guidelines, this correctly validates variable bounds during algorithm state transitions.cpp/src/dual_simplex/crossover.cpp (3)
788-796: LGTM! Correct bound propagation to basis repair.The
lp.lowerandlp.upperbounds are correctly passed tobasis_repair, enabling proper variable status assignment during the primal push refactoring phase.
1142-1150: LGTM! Consistent bound handling in crossover initialization.Bounds are correctly propagated during the initial basis repair in the crossover function, consistent with the other call sites.
1341-1349: LGTM! Bounds passed after phase 1 completion.The third call site correctly passes bounds after phase 1 completes, maintaining consistency across all
basis_repairinvocations in the crossover workflow.cpp/src/dual_simplex/basis_updates.cpp (2)
2046-2054: LGTM! Signature update matches declaration.The
refactor_basisimplementation correctly accepts the newlowerandupperbound parameters, consistent with the header declaration inbasis_updates.hpp.
2071-2072: LGTM! Bounds correctly forwarded to basis_repair.When initial factorization fails, the bounds are properly passed to
basis_repairto enable correct variable status assignment during the repair process. Based on coding guidelines, this ensures correct initialization of variable bounds when transitioning between algorithm phases.cpp/src/dual_simplex/basis_updates.hpp (1)
374-380: Verify all callers ofrefactor_basishave been updated to pass the new bound parameters.The
refactor_basisdeclaration correctly addslowerandupperbound vectors as const references. All callers in phase2.cpp (lines 2248, 2910, 2917) have been properly updated to passlp.lowerandlp.upper. This is a breaking API change requiring all callers to be updated.cpp/src/dual_simplex/simplex_solver_settings.hpp (1)
22-34: Well-structured diving configuration.The new
diving_heuristics_settings_tstruct cleanly encapsulates diving-related parameters with sensible defaults. The separation of heuristic enable/disable flags and resource limits (node_limit, iteration_limit_factor, backtrack) follows good configuration design practices.cpp/src/dual_simplex/pseudo_costs.cpp (2)
202-202: Good improvement: RAII-based locking.Using
std::lock_guard<omp_mutex_t>ensures the mutex is properly released even if an exception occurs or the function returns early. This is a safer pattern than manual lock/unlock.
256-321: Correct implementation of pseudocost-based objective estimate.The function correctly:
- Uses RAII locking for thread safety
- Computes per-variable pseudocosts with fallback to averages for uninitialized values
- Applies the reliability branching score formula (product of down/up estimates)
- Accumulates a conservative objective estimate using the minimum of up/down contributions
The algorithm aligns with standard MIP solver literature (Achterberg Sect. 6.4).
cpp/src/dual_simplex/diving_heuristics.hpp (1)
17-47: Clean diving heuristics API design.The header provides a well-organized interface for the four diving strategies from Achterberg's thesis:
- Line search diving (Sect. 9.2.4)
- Pseudocost diving (Sect. 9.2.5)
- Guided diving (Sect. 9.2.3)
- Coefficient diving (Sect. 9.2.1)
The
branch_variable_treturn type cleanly bundles the selected variable with its rounding direction.cpp/src/dual_simplex/diving_heuristics.cpp (3)
66-139: Correct pseudocost diving implementation with thread safety.The implementation correctly:
- Acquires mutex lock before accessing shared pseudocost data
- Uses fallback averages for uninitialized pseudocosts
- Applies the scoring formula from Achterberg Sect. 9.2.5
- Uses threshold-based direction selection (0.4 for root distance, 0.3/0.7 for fractionality)
The magic constants are standard heuristic values from MIP literature.
141-197: Correct guided diving implementation.The function properly implements Achterberg's guided diving (Sect. 9.2.3):
- Direction determined by proximity to incumbent solution
- Score weighted 5:1 in favor of the preferred direction
- Thread-safe pseudocost access
Note the same empty
fractionaledge case applies here.
229-273: Correct coefficient diving implementation.The function implements Achterberg's coefficient diving (Sect. 9.2.1):
- Selects variable with minimum constraint locks
- Prefers rounding direction that creates fewer constraint violations
- Uses fractionality as tie-breaker when locks are equal
The same empty
fractionaledge case consideration applies.cpp/src/dual_simplex/basis_solves.cpp (1)
613-622: Signature extension for bound-aware basis repair is complete and correctly integrated.The addition of
lowerandupperbound vectors enables correct variable status assignment during basis repair. All call sites have been updated to pass the bound vectors:
primal.cpp(1 call)crossover.cpp(3 calls)basis_updates.cpp(1 call)All invocations properly pass
lp.lowerandlp.upper(or locallower/upperfrom the calling context). The signature change aligns with the PR's goal of propagating bound information through solver phases.cpp/src/dual_simplex/node_queue.hpp (1)
60-101: Well-structured dual-heap design for unified node scheduling.The
node_queue_tclass effectively unifies best-first and diving heaps with shared entries, aligning with the PR objective to reduce memory consumption. The use ofshared_ptr<heap_entry_t>for cross-heap entry sharing is a clean approach.cpp/src/dual_simplex/phase2.cpp (3)
620-651: Signature change correctly separates squared and linear infeasibility.The updated
compute_initial_primal_infeasibilitiesnow properly computes both forms:
- Returns
primal_inf_squared(sum of squared infeasibilities)- Outputs
primal_inf(sum of linear infeasibilities) via referenceThis distinction is important for different algorithmic needs (squared for steepest-edge pricing weights, linear for feasibility checks). The initialization of
squared_infeasibilitiesvector at lines 631-632 ensures clean state.
2365-2373: Proper initialization of infeasibility tracking variables.The new code correctly initializes
primal_infeasibilityandprimal_infeasibility_squaredseparately, withcompute_initial_primal_infeasibilitiespopulating both values. This ensures clean state before the main iteration loop.
2248-2251: Allrefactor_basiscall sites are consistent with the function signature.Verification confirms that all three call sites in phase2.cpp (lines 2248, 2910–2911, and 2917–2918) correctly include the
lp.lowerandlp.upperbound parameters matching the function signature in basis_updates.hpp and basis_updates.cpp.cpp/src/dual_simplex/branch_and_bound.hpp (4)
56-67: Clear documentation and well-structured enum for diving strategies.The
bnb_thread_type_tenum provides clear categorization with references to the Achterberg dissertation sections. This aligns well with the PR objective of implementing multiple diving heuristics.
75-86: Thread-safe statistics structure with atomic counters.The
bnb_stats_tstruct appropriately usesomp_atomic_tfor counters that may be updated from multiple threads. Thelast_logandnodes_since_last_logmembers with the comment about main-thread-only usage help clarify the intended access pattern.
182-184: Unified node queue replaces separate heap structures.The replacement of the previous heap-based structures with
node_queue_taligns with the PR objective to "unify diving and best-first heaps into a single node_queue object." This should help reduce memory consumption as mentioned in the PR description.
261-266:variable_selectionreturn type and parameters are well-designed.Returning
branch_variable_t<i_t>which includes both the variable index and rounding direction is cleaner than having multiple output parameters. The additionallogger_t& logparameter enables per-call logging control.cpp/src/dual_simplex/branch_and_bound.cpp (9)
558-577: Martin's criteria implementation for rounding direction.The
martin_criteriafunction correctly implements the rounding heuristic based on distance from the root relaxation value. The epsilon tolerance (1e-6) for tie-breaking is reasonable.
579-619: Clean dispatch pattern for variable selection strategies.The
variable_selectionmethod uses a clear switch statement to dispatch to different diving heuristics. The objective estimate calculation is correctly scoped to only the EXPLORATION case where it's needed for heap ordering.
640-643: Appropriate fallback from GUIDED_DIVING to PSEUDOCOST_DIVING.When there's no incumbent solution (
upper_bound == inf), guided diving cannot function since it relies on the incumbent for guidance. Falling back to pseudocost diving is a sensible default.
656-661: Iteration budget enforcement for diving threads.The iteration limit for diving threads is computed as a factor of total B&B LP iterations minus iterations already consumed by this dive. This prevents diving from consuming too many iterations.
However, if
stats.total_lp_itersis close tomax_iter, this could returnITERATION_LIMITvery early. Verify that theiteration_limit_factorsetting provides sufficient budget for meaningful dives.
1143-1219: Deep diving implementation with backtrack limit.The
dive_frommethod implements the diving heuristics with proper backtracking control. Key observations:
- Lines 1163-1166: Local
dive_statsproperly tracks per-dive statistics- Lines 1179-1180: Time and node limits checked within the dive loop
- Lines 1215-1218: Backtrack limit enforces shallow backtracking by removing nodes from the back of the stack when depth difference exceeds the limit
The algorithm correctly prioritizes depth-first exploration while limiting the breadth of backtracking.
1248-1255: Bounds propagation for diving thread efficiency.The code correctly retrieves variable bounds from the node and applies bounds strengthening before diving. The
reset_starting_boundsflag ensures bounds are properly reset when starting from a new node.
1518-1535: Diving strategy configuration is flexible and well-structured.The diving strategies are populated based on settings, allowing users to disable specific strategies. The
reserve(4)call is appropriate given the four possible strategies.
251-260: Improved lower bound computation uses node_queue.The
get_lower_boundmethod correctly combines:
lower_bound_ceiling_(for numerical issue tracking)node_queue.get_lower_bound()(heap minimum)local_lower_bounds_(per-thread tracking)This provides an accurate global lower bound across all active exploration paths.
1354-1354: Row-major matrix initialization for bounds strengthening.Converting the constraint matrix to row-major format (
Arow_) enables efficient row-based access during bounds strengthening. This is initialized once at the start ofsolve(), avoiding repeated conversions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
cpp/src/dual_simplex/diving_heuristics.cpp (1)
244-244: Type mismatch:locksshould bei_t, notf_t.The variable
locksstores the minimum of twoi_tvalues but is declared asf_t. This causes an unnecessary type conversion.- f_t locks = std::min(up_lock, down_lock); + i_t locks = std::min(up_lock, down_lock);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
cpp/src/dual_simplex/branch_and_bound.cpp(30 hunks)cpp/src/dual_simplex/diving_heuristics.cpp(1 hunks)cpp/src/dual_simplex/mip_node.hpp(4 hunks)cpp/src/dual_simplex/simplex_solver_settings.hpp(3 hunks)
🧰 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/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.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/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.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/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.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/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
🧠 Learnings (12)
📓 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: 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
📚 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/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : 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/mip_node.hppcpp/src/dual_simplex/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : 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/mip_node.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 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/mip_node.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/mip_node.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : 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/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*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/simplex_solver_settings.hppcpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Reduce tight coupling between solver components (presolve, simplex, basis, barrier); increase modularity and reusability of optimization algorithms
Applied to files:
cpp/src/dual_simplex/simplex_solver_settings.hppcpp/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/simplex_solver_settings.hpp
📚 Learning: 2025-11-25T10:20:49.822Z
Learnt from: CR
Repo: NVIDIA/cuopt PR: 0
File: .github/.coderabbit_review_guide.md:0-0
Timestamp: 2025-11-25T10:20:49.822Z
Learning: Applies to **/*.{cu,cuh,cpp,hpp,h} : Assess algorithmic complexity for large-scale problems (millions of variables/constraints); ensure O(n log n) or better complexity, not O(n²) or worse
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
📚 Learning: 2025-12-04T20:09:09.264Z
Learnt from: chris-maes
Repo: NVIDIA/cuopt PR: 602
File: cpp/src/linear_programming/solve.cu:732-742
Timestamp: 2025-12-04T20:09:09.264Z
Learning: In cpp/src/linear_programming/solve.cu, the barrier solver does not currently return INFEASIBLE or UNBOUNDED status. It only returns OPTIMAL, TIME_LIMIT, NUMERICAL_ISSUES, or CONCURRENT_LIMIT.
Applied to files:
cpp/src/dual_simplex/diving_heuristics.cppcpp/src/dual_simplex/branch_and_bound.cpp
🧬 Code graph analysis (1)
cpp/src/dual_simplex/branch_and_bound.cpp (3)
cpp/src/dual_simplex/node_queue.hpp (11)
buffer(40-48)buffer(50-50)buffer(51-51)buffer(52-52)buffer(53-53)lower(116-134)lower(116-118)node(21-25)node(21-21)node(27-31)node(27-27)cpp/src/dual_simplex/branch_and_bound.hpp (7)
leaf_objective(205-208)node_ptr(247-259)node_ptr(262-266)solution(116-116)solution(134-134)solution(201-201)node(215-215)cpp/src/dual_simplex/diving_heuristics.hpp (3)
line_search_diving(24-27)pseudocost_diving(30-34)guided_diving(37-41)
🔇 Additional comments (24)
cpp/src/dual_simplex/mip_node.hpp (5)
48-48: LGTM: Consistent initialization ofobjective_estimate.The field is properly initialized to infinity using
std::numeric_limits<f_t>::infinity(), which is type-safe for the template parameterf_t.
63-63: LGTM: Type-safe initialization in root constructor.This initialization now correctly uses
std::numeric_limits<f_t>::infinity()matching the default constructor, ensuring type safety when the template is instantiated with different floating-point types.
85-85: LGTM: Proper propagation from parent node.The objective estimate is correctly propagated from the parent node to child nodes, which is essential for the diving heuristics' node scoring mechanism.
233-239: LGTM: Complete field copying indetach_copy().All relevant fields including
objective_estimateare now copied when detaching a node, ensuring the detached copy retains all necessary state for independent processing.
245-245: LGTM: Public member declaration.The
objective_estimatefield is appropriately declared as public alongside other node attributes likelower_bound, enabling direct access for node queue sorting operations.cpp/src/dual_simplex/simplex_solver_settings.hpp (3)
22-34: Well-structured diving settings configuration.The new
diving_heuristics_settings_tstruct cleanly encapsulates all diving-related parameters with sensible defaults:
node_limit = 500bounds exploration depthiteration_limit_factor = 0.05prevents runaway simplex iterations during divesbacktrack = 5limits backtracking depth in the dive stackThis aligns well with standard MIP solver diving configurations.
94-94: LGTM: Correct use ofstd::maxfor diving task count.The initialization now correctly ensures at least 1 diving task while allowing more threads when available:
std::max(num_threads - num_bfs_threads, 1).
155-156: LGTM: Clean integration of diving settings.The diving settings are properly integrated as a member of the solver settings struct, maintaining a clean separation of concerns.
cpp/src/dual_simplex/diving_heuristics.cpp (5)
12-64: LGTM: Line search diving implementation.The implementation correctly follows Achterberg's line search diving heuristic (§9.2.4):
- Scores variables based on fractional part divided by distance from root solution
- Prefers rounding toward the root solution value
- Has a sensible fallback when the solution equals the root
The mutex-free design is appropriate since this function only reads shared state.
66-139: LGTM: Pseudocost diving with proper synchronization.The implementation correctly:
- Acquires a lock before accessing pseudo-cost data (line 73)
- Falls back to averages for uninitialized pseudo-costs (lines 91-96)
- Uses
(1 + pc)in denominators to prevent division by zero (lines 98-99)- Applies the multi-criteria decision logic from Achterberg §9.2.5
141-197: LGTM: Guided diving implementation.The guided diving correctly uses the incumbent solution to determine rounding direction (line 166-167), preferring the direction that moves closer to the known feasible solution. The weighted scoring (5:1 ratio) appropriately prioritizes the chosen direction.
199-227: LGTM: Variable locks calculation.The function correctly counts up/down locks based on constraint structure:
- Handles ranged constraints (both bounds finite) by counting both directions
- Uses coefficient sign to determine lock direction for one-sided constraints
The return type is now correctly
std::tuple<i_t, i_t>matching the integer lock counts.
275-297: LGTM: Template instantiations.Explicit instantiations for
int/doubleare provided under theDUAL_SIMPLEX_INSTANTIATE_DOUBLEguard, matching the project's pattern.cpp/src/dual_simplex/branch_and_bound.cpp (11)
195-205: LGTM: Extended thread type symbols for logging.The 2-character symbols (B, CD, LD, PD, GD) provide clear identification of the source thread type in logs while maintaining column alignment.
249-260: LGTM: Unified lower bound computation.The lower bound now correctly aggregates from multiple sources:
- The ceiling from numerical issues
- The node queue's best-first lower bound
- All local thread bounds
The
std::isfinitecheck at line 259 correctly handles uninitialized or infinite bounds.
558-619: Well-structured variable selection dispatch.The
variable_selectionfunction cleanly dispatches to the appropriate diving heuristic based on thread type. Key observations:
- EXPLORATION uses pseudo-cost selection with Martin's criteria for direction
- The
objective_estimateis only set for EXPLORATION (line 600), which is correct since only exploration threads push nodes to the queue- The default case logs and returns an invalid result, which will trigger assertions downstream - consider returning a more defensive fallback.
640-643: Good defensive fallback for guided diving.When no incumbent exists (
upper_bound == inf), guided diving cannot function since it requires an incumbent solution to guide the rounding direction. Falling back to pseudocost diving is the correct behavior.
656-661: Verify iteration limit calculation for edge cases.The iteration limit for diving threads is calculated as
max_iter - stats.total_lp_iters. This could underflow ifstats.total_lp_itersexceedsmax_iterdue to floating-point precision when computingmax_iter = iteration_limit_factor * bnb_lp_iters.Consider using explicit clamping:
if (thread_type != bnb_thread_type_t::EXPLORATION) { i_t bnb_lp_iters = exploration_stats_.total_lp_iters; f_t max_iter = settings_.diving_settings.iteration_limit_factor * bnb_lp_iters; - lp_settings.iteration_limit = max_iter - stats.total_lp_iters; + lp_settings.iteration_limit = std::max(static_cast<i_t>(max_iter) - stats.total_lp_iters, static_cast<i_t>(0)); if (lp_settings.iteration_limit <= 0) { return node_solve_info_t::ITERATION_LIMIT; } }This ensures the limit is never negative even with floating-point truncation.
814-815: LGTM: Iteration limit handling in solve_node.The new
ITERATION_LIMITcase correctly propagates the status when diving threads exhaust their iteration budget, allowing clean exit from the dive.
1143-1220: Well-implemented diving exploration with backtracking.The
dive_fromfunction correctly implements bounded diving with:
- Local subtree for isolation from the main search tree
- Per-dive statistics tracking (
dive_stats)- Node and iteration limits (lines 1180-1181)
- Backtrack depth limiting (lines 1215-1218)
The backtrack logic at lines 1215-1218 trims the stack when depth difference exceeds the configured limit, preventing excessive memory usage during deep dives.
1222-1268: LGTM: Diving thread implementation.The diving thread correctly:
- Maintains local problem state and bounds
- Resets starting bounds when beginning a new dive (lines 1241-1246)
- Applies bounds strengthening before diving (line 1254)
- Checks for cutoff before committing to a dive (line 1255)
1354-1377: Good defensive handling of disabled diving strategies.The code properly builds the diving strategies vector based on settings and emits a warning when all are disabled (line 1376). This is correctly paired with the guard at line 1564 that skips task spawning when the vector is empty.
1564-1570: LGTM: Safe diving task dispatch.The guard at line 1564 (
if (!diving_strategies.empty())) correctly prevents the modulo operation when no strategies are available, addressing the potential division-by-zero concern from the past review.
1574-1576: LGTM: Final lower bound computation.The final lower bound correctly uses the node queue's lower bound when nodes remain, or falls back to the root's lower bound when the queue is empty.
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
/ok to test 0aa344e |
|
/ok to test 7a5284e |
|
/ok to test 9f07cbb |
The goal of this PR is to improve the diving framework in the MIP solver based on [1, Section 9.2]. It introduces the following changes:
node_queue) to allow the sharing of information between them. This also greatly reduces memory consumption (33GBvs48GBforneos-848589after250s) since the lower and upper variable no longer needs to be stored for diving (Unified Node Queue + Diving Node and Iteration Limits #718).MIPLIB results (GH200):
Reference:
[1] T. Achterberg, “Constraint Integer Programming,” PhD, Technischen Universität Berlin,
Berlin, 2007. doi: 10.14279/depositonce-1634.
Checklist
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.