Skip to content

Several bug fixes#786

Merged
rapids-bot[bot] merged 12 commits intoNVIDIA:release/26.02from
nguidotti:fix-bugs
Jan 26, 2026
Merged

Several bug fixes#786
rapids-bot[bot] merged 12 commits intoNVIDIA:release/26.02from
nguidotti:fix-bugs

Conversation

@nguidotti
Copy link
Contributor

@nguidotti nguidotti commented Jan 20, 2026

  • Fixed early termination in CMS750_4 due to an incorrect root objective from the PDLP. It provides an objective in user space and B&B expects the objective in the solver space.
  • Fixed setting the number of threads to a fixed value when running cuopt_cli. Now the number of threads in the probing cache can be controlled by the bounds_update::settings_t.
  • Inverted loop order in probing cache to avoid creating and deleting the OpenMP thread pool each iteration.
  • PDLP/Barrier no longer set the root objective and solution when the B&B is already running.
  • Improved the logs when solving the root relaxation using the concurrent mode.

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

    • Per-instance threading for presolve with sensible defaults and clamping.
    • Bidirectional objective conversion so callbacks receive both solver-space and user-space objective values.
  • Bug Fixes

    • Root relaxation solution handling made idempotent to avoid overwrites.
    • Reduced verbose logging inside MIP solves and refined root/crossover status messages.
  • Style

    • Updated header/license years and minor logging formatting improvements.

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

@nguidotti nguidotti added this to the 26.02 milestone Jan 20, 2026
@nguidotti nguidotti self-assigned this Jan 20, 2026
@nguidotti nguidotti requested a review from a team as a code owner January 20, 2026 14:33
@nguidotti nguidotti added bug Something isn't working non-breaking Introduces a non-breaking change labels Jan 20, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

Reworks objective handling to pass both user-space and solver-space objectives, adds bidirectional objective conversion, makes root-solution setting idempotent, introduces configurable presolve threading, and adds conditional logging to suppress verbose LP messages during MIP solves.

Changes

Cohort / File(s) Summary
Objective conversion & B&B callback
cpp/src/mip/diversity/diversity_manager.cu, cpp/src/mip/problem/problem.cuh, cpp/src/mip/problem/problem.cu
Add get_solver_obj_from_user_obj(f_t) and use it to derive a solver-space objective from the PDLP/user objective. Update callback invocations to pass solver_obj then user_obj. Adjust related comments and data flow.
Root solution idempotency & logging flow
cpp/src/dual_simplex/branch_and_bound.hpp, cpp/src/dual_simplex/branch_and_bound.cpp
Add is_root_solution_set flag and guard assignments in set_root_relaxation_solution/root handling to avoid overwriting cached root crossover data; propagate solver name, iterations and objective from crossover when present; minor logging/formatting adjustments.
Presolve threading & probing cache
cpp/src/mip/presolve/bounds_presolve.cuh, cpp/src/mip/presolve/probing_cache.cu
Add settings.num_threads (default -1), include OpenMP header, compute/clamp num_threads (fallback 0.2 * omp_get_max_threads()), resize per-thread pools to num_threads, and run parallel regions with num_threads.
Conditional LP logging & macros
cpp/src/linear_programming/solve.cu, cpp/src/dual_simplex/phase2.cpp
Introduce CUOPT_LOG_CONDITIONAL_INFO(condition, ...) and replace direct INFO logs with conditional macro to suppress logs when inside MIP; remove redundant root-relaxation logging in phase2; update copyright year.
LP status helper
cpp/src/dual_simplex/solve.hpp
Add internal helper lp_status_to_string(lp_status_t) mapping enum values to strings.
Build/manifest files
manifest_file, CMakeLists.txt
Minor manifest/CMake adjustments listed in diff (lines changed small).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Several bug fixes' is vague and generic, using non-descriptive language that does not convey meaningful information about the specific changes in the changeset. Replace with a more specific title that highlights the primary change, such as 'Fix root objective handling in Branch & Bound PDLP integration' or 'Fix PDLP objective space mapping in root relaxation'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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.

…ed concurrent solution when the B&B is already running. moved number of threads in the probing cache to the setting struct.
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cpp/src/mip/presolve/probing_cache.cu (1)

859-910: Add defensive validation for num_threads before pool sizing and parallel launch

The code assumes settings.num_threads is always positive, but since settings_t is a public struct, external code can set num_threads to 0 (or modify it between initialization and use). If 0 is assigned:

  • modification_vector_pool and substitution_vector_pool would have size 0
  • #pragma omp parallel num_threads(0) produces undefined behavior (OpenMP spec)
  • If threads spawn despite 0, thread_idx from omp_get_thread_num() will exceed pool bounds, causing out-of-bounds access

Add a defensive clamp before sizing the pools:

Proposed fix
-  const size_t num_threads = bound_presolve.settings.num_threads;
+  const i_t requested_threads = bound_presolve.settings.num_threads;
+  size_t num_threads =
+    requested_threads > 0 ? static_cast<size_t>(requested_threads)
+                          : static_cast<size_t>(omp_get_max_threads());
+  if (num_threads == 0) { num_threads = 1; }

Aligns with multithreading safety guidelines to prevent resource exhaustion and thread safety violations.


#include <thread> // For std::thread

#define CUOPT_LP_SOLVER_LOG_INFO(...) \
Copy link
Contributor

Choose a reason for hiding this comment

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

Can't we undef the previous macro and still use CUOPT_LOG_INFO here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it is better to add another macro, since there are some methods where we do not pass the setting as argument, hence they need to use the old version.

Copy link
Contributor Author

@nguidotti nguidotti Jan 22, 2026

Choose a reason for hiding this comment

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

Ideally, we should add logger_t to the settings rather than CUOPT_LOG_INFO or rapids::logger_t.

@rgsl888prabhu rgsl888prabhu added the do not merge Do not merge if this flag is set label Jan 22, 2026
@rg20 rg20 added do not merge Do not merge if this flag is set and removed do not merge Do not merge if this flag is set labels Jan 22, 2026
@rgsl888prabhu rgsl888prabhu changed the base branch from main to release/26.02 January 22, 2026 16:39
@nguidotti nguidotti changed the title Fixed early termination in CMS750_4 + Fixed hard-coded number of threads Several bug fixes Jan 22, 2026

// Check if crossover was stopped by dual simplex
if (crossover_status == crossover_status_t::OPTIMAL) {
settings_.log.printf("\nCrossover found an optimal solution for the root relaxation\n\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

This is where we should indicate that PDLP/Barrier won. Can you use the is_pdlp_solution to determine which of them won and print it here?

Copy link
Contributor Author

@nguidotti nguidotti Jan 22, 2026

Choose a reason for hiding this comment

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

I did not find a way to get the winner solver from the optimization_problem_solution_t unless we change the API (#787). This object is user-facing, so it needs to be reflect on the Python side as well.

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.hpp`:
- Around line 87-97: The plain bool is_root_solution_set is accessed
concurrently (read in set_root_relaxation_solution and written in
solve_root_relaxation), causing a data race; change the declaration of
is_root_solution_set to std::atomic<bool> and update all reads/writes in
functions such as set_root_relaxation_solution and solve_root_relaxation to use
.load()/.store() with appropriate memory orders (e.g., memory_order_acquire for
reads and memory_order_release for writes) to match the existing
root_crossover_solution_set_ usage, ensuring thread-safe checks and updates.

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

🤖 Fix all issues with AI agents
In `@cpp/src/dual_simplex/branch_and_bound.cpp`:
- Around line 1372-1386: The plain bool is_root_solution_set is written in
branch_and_bound.cpp (at the shown block) and concurrently read by
set_root_relaxation_solution(), causing a data race; change its declaration to
std::atomic<bool> (matching root_crossover_solution_set_) or guard all accesses
with mutex_upper_ to synchronize with upper-bound updates; update all
reads/writes of is_root_solution_set to use atomic operations (or lock
mutex_upper_) and ensure consistency with existing root_crossover_solution_set_
usage patterns.
- Around line 1351-1358: The composite iteration count from the
barrier+crossover solution (root_crossover_soln_) is being copied into
root_relax_soln_.iterations and later used via exploration_stats_.total_lp_iters
to compute diving limits, which is incorrect; update the swap logic around
root_relax_soln_, root_crossover_soln_, root_vstatus_, root_status,
user_objective and solver_name so that you do not propagate the composite
barrier+crossover iteration total into the dual-simplex/diving accounting—either
reset iter to 0 (or to a separate dual-simplex pivot counter) immediately after
assigning root_relax_soln_ = root_crossover_soln_ or preserve and copy a stored
dual-simplex iteration field instead; ensure exploration_stats_.total_lp_iters
and lp_settings.iteration_limit continue to use the dual-simplex pivot count (or
a fresh counter) rather than the barrier+crossover composite value so diving
workers aren’t terminated prematurely.

@nguidotti nguidotti removed the do not merge Do not merge if this flag is set label Jan 26, 2026
@nguidotti
Copy link
Contributor Author

/merge

@rapids-bot rapids-bot bot merged commit aa99f98 into NVIDIA:release/26.02 Jan 26, 2026
101 checks passed
@nguidotti nguidotti deleted the fix-bugs branch January 26, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants