Skip to content

Store best dual objective, align root LP bound with relative_mip_gap#957

Closed
anandhkb wants to merge 1 commit intoNVIDIA:release/26.04from
anandhkb:followUpToLogPR
Closed

Store best dual objective, align root LP bound with relative_mip_gap#957
anandhkb wants to merge 1 commit intoNVIDIA:release/26.04from
anandhkb:followUpToLogPR

Conversation

@anandhkb
Copy link
Contributor

  • Callback: store only best (tightest) dual objective; it can worsen during iterations (min: keep largest, max: keep smallest)
  • set_final_solution: when returning with -inf, push root_lp_current_lower_bound_ to stats so relative_mip_gap uses the best/tightest bound
  • user_bound_callback: only update stats when new bound is better, avoid overwriting e.g. set_simplex_solution with a worse root LP value
  • Log line change: 'Root LP dual objective (last)' -> '(best)'

- Callback: store only best (tightest) dual objective; it can worsen during
  iterations (min: keep largest, max: keep smallest)
- set_final_solution: when returning with -inf, push root_lp_current_lower_bound_
  to stats so relative_mip_gap uses the best bound
- user_bound_callback: only update stats when new bound is better, avoid
  overwriting e.g. set_simplex_solution with worse root LP value
- Log: 'Root LP dual objective (last)' -> '(best)'
@anandhkb anandhkb added this to the 26.04 milestone Mar 14, 2026
@anandhkb anandhkb requested a review from a team as a code owner March 14, 2026 17:04
@anandhkb anandhkb added non-breaking Introduces a non-breaking change improvement Improves an existing functionality labels Mar 14, 2026
@copy-pr-bot
Copy link

copy-pr-bot bot commented Mar 14, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d5b3d0be-ba67-4e88-8506-bdd5e69f20b3

📥 Commits

Reviewing files that changed from the base of the PR and between d531ad1 and 6d1919e.

📒 Files selected for processing (2)
  • cpp/src/branch_and_bound/branch_and_bound.cpp
  • cpp/src/mip_heuristics/solver.cu

📝 Walkthrough

Walkthrough

The changes improve bound tracking and reporting in optimization solvers by introducing objective-sense-aware bound comparisons. The dual objective callback now only updates bounds when they represent improvements relative to the optimization direction, and messaging clarifies that reported bounds are the best observed. Early termination scenarios properly propagate updated bounds to user callbacks.

Changes

Cohort / File(s) Summary
Bound tracking refinement
cpp/src/branch_and_bound/branch_and_bound.cpp
Root LP dual objective callback now stores bounds only when they represent the best (tightest) bound accounting for objective sense (maximization vs. minimization). Log messaging updated to reflect "best" rather than "last" bound. Early-exit scenarios with -inf lower bound now propagate finite root bounds to user-bound callbacks.
Solution-bound callback improvement
cpp/src/mip_heuristics/solver.cu
Simple solution-bound update replaced with objective-sense-aware logic. Introduces is_minimization check and computes bound improvements based on current bound finiteness and optimization direction, updating stored bound only when the new bound is superior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: storing the best dual objective and aligning the root LP bound with relative_mip_gap calculation.
Description check ✅ Passed The description directly relates to the changeset, detailing the callback behavior changes, set_final_solution modifications, user_bound_callback updates, and logging changes reflected in the code modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

You can get early access to new features in CodeRabbit.

Enable the early_access setting to enable early access features such as new models, tools, and more.

@anandhkb
Copy link
Contributor Author

/ok to test 6d1919e

lp_settings.concurrent_halt = get_root_concurrent_halt();
lp_settings.dual_simplex_objective_callback = [this](f_t user_obj) {
root_lp_current_lower_bound_.store(user_obj);
// Store only the best (tightest) dual objective; it can worsen during iterations
Copy link
Contributor

Choose a reason for hiding this comment

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

The dual objective should always increase over the iterations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, thanks, I refer to Burcin's testcase:

cuopt_cli --log-file Optimality_MIP_1.log --solution-file Optimality_MIP_1.sln --time-limit 28500 Optimality_MIP_1.mps

Issue is: The dual obj value is getting worse rather than monotonically improving. He says -  "If you have taken the last dual obj for your gap calculation, the resulting value is not correct because a better dual obj value was found in an earlier iteration". Here is the log Burcin referred me to:

236000 -7.8615507602829341e+04   33078 2.15752325e+16 0.00e+00 873.90
237000 -7.8599148858700210e+04   32968 2.33309309e+16 0.00e+00 878.39
238000 -7.8628596397306974e+04   31778 4.13809980e+15 0.00e+00 882.75
239000 -7.8625353538739626e+04   31793 4.09842601e+15 0.00e+00 886.47
240000 -3.4223435428449867e+05   34910 4.33595251e+22 0.00e+00 894.38.  ### this is where dual obj value gets worse
241000 -4.9084521357962309e+05   33468 3.08252689e+20 0.00e+00 899.81.  ### and worse...
242000 -5.2980592629211734e+05   33705 7.28784267e+19 0.00e+00 904.61
243000 -5.3195161855784897e+05   32822 7.03858147e+18 2.00e-07 908.23
244000 -5.3188925240266300e+05   32597 2.46222227e+19 0.00e+00 912.64
...
279000 -5.7260862863620499e+05   24915 1.06134033e+18 0.00e+00 1234.99
280000 -5.7271001072192355e+05   24276 7.90538350e+17 0.00e+00 1241.53
281000 -5.7235100939733768e+05   24464 1.18694208e+18 0.00e+00 1257.79
New solution from primal heuristics. Objective -5.993702e+04. Gap 854.9%. Time 1258.26.    ### a heuristic solution found but gap should be 31.18%, in relation to line 239000
282000 -5.7285144600908319e+05   20031 1.07701601e+13 1.00e-07 1276.96
283000 -5.7284553597028111e+05   23587 4.28140763e+14 0.00e+00 1287.60

Copy link
Contributor

Choose a reason for hiding this comment

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

That looks like an issue in either numerics or perturbation in dual simplex. We should fix the issue inside of dual simplex, rather than adding code to hide the issue outside of dual simplex.

Please let me know how to reproduce the above log.

Copy link
Contributor

@chris-maes chris-maes left a comment

Choose a reason for hiding this comment

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

Is this PR necessary?

@anandhkb
Copy link
Contributor Author

@bbozkaya and @chris-maes to discuss further and identify IF there is an actual need for this PR. Thanks @chris-maes and @bbozkaya !

@anandhkb
Copy link
Contributor Author

Attaching the cuopt log file (partial) for the problem on which @bbozkaya saw an anomaly. I ran from a build based off main branch today.
cuopt_log.txt

@rgsl888prabhu rgsl888prabhu changed the base branch from main to release/26.04 March 19, 2026 16:29
@chris-maes
Copy link
Contributor

I will close this for now. I think this will require a larger effort to address.

@chris-maes chris-maes closed this Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants