Skip to content

Papilo primal/dual crush#1104

Open
aliceb-nv wants to merge 15 commits into
NVIDIA:mainfrom
aliceb-nv:papilo-crush
Open

Papilo primal/dual crush#1104
aliceb-nv wants to merge 15 commits into
NVIDIA:mainfrom
aliceb-nv:papilo-crush

Conversation

@aliceb-nv

Copy link
Copy Markdown
Contributor

This PR implements support for crushing primal incumbents in MIP mode into the Papilo problem space, and crushing primal/dual vectors for LP.

A bugfix is also included to allow consecutive solves to be run in the same GTest process without corrupting the OpenMP runtime.

Closes #513
Closes #1060

Description

Issue

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

@aliceb-nv aliceb-nv added this to the 26.04 milestone Apr 15, 2026
@aliceb-nv aliceb-nv requested a review from rg20 April 15, 2026 10:18
@aliceb-nv aliceb-nv requested review from a team as code owners April 15, 2026 10:18
@aliceb-nv aliceb-nv requested a review from chris-maes April 15, 2026 10:18
@aliceb-nv aliceb-nv added non-breaking Introduces a non-breaking change improvement Improves an existing functionality labels Apr 15, 2026
@aliceb-nv aliceb-nv requested a review from tmckayus April 15, 2026 10:18
@copy-pr-bot

copy-pr-bot Bot commented Apr 15, 2026

Copy link
Copy Markdown

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.

@aliceb-nv

Copy link
Copy Markdown
Contributor Author

/ok to test d47d709

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b85a8a41-ecd6-46a9-afe8-5c577bdeac33

📥 Commits

Reviewing files that changed from the base of the PR and between 6f5f716 and 0174bee.

📒 Files selected for processing (3)
  • cpp/src/mip_heuristics/diversity/diversity_manager.cu
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
  • cpp/src/mip_heuristics/solve.cu
💤 Files with no reviewable changes (3)
  • cpp/src/mip_heuristics/diversity/diversity_manager.cu
  • cpp/src/mip_heuristics/solve.cu
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp

📝 Walkthrough

Walkthrough

Adds forward "crush" mappings to transform original-space solutions into Papilo reduced space, integrates crushing into initial-solution workflows (including GPU-disabled path), adjusts Papilo presolve selection and column-integrality handling, introduces RAII guards for OpenMP resource cleanup, and collects multiple early incumbents for improved population seeding.

Changes

Papilo Crushing and Solution-Space Mapping

Layer / File(s) Summary
Papilo solution crushing API & presolve tuning
cpp/src/mip_heuristics/presolve/third_party_presolve.cpp, cpp/src/mip_heuristics/presolve/third_party_presolve.hpp
Added crush_primal_solution and crush_primal_dual_solution to map original → reduced solutions by replaying reductions in forward order; implement handling for specific reduction types (kParallelCol, kRowBoundChangeForcedByRow, kCoefficientChange, kSubstitutedColWithDual), project using origcol_mapping/origrow_mapping, and apply dual/RC corrections. Restrict setColIntegral to MIP category only. Move SingletonStuffing from unconditional to conditional list (only when !dual_postsolve) to avoid dual crushing failures on documented instances.
Initial-solution crushing & insertion flow
cpp/src/mip_heuristics/diversity/diversity_manager.cu
When Papilo postsolve data exists, validate variable-count match against original size, copy assignments host↔device, apply crush_primal_solution transformation, and log mapping at DEBUG level. Downgrade "initial solution added" success logging from INFO to DEBUG. In GPU-disabled path, insert user initial solutions into population earlier and perform early B&B preemption check post-insertion. In main solver path, reorder insertion before preemption check and remove later redundant population addition.
Early incumbent pooling & OMP resource cleanup
cpp/src/mip_heuristics/solve.cu
Add RAII scope_guard to pause OpenMP resources (omp_pause_resource_all) on scope exit, preventing resource exhaustion in multi-threaded solve contexts. Remove presolve-disable condition when initial-solutions are non-empty. Introduce early_incumbent_pool to collect all improved early incumbents (objective + assignment) during presolve feasibility-jump callback; after early phases, convert pooled assignments to device data and append into settings.initial_solutions for downstream crushing and diversity management.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested reviewers

  • tmckayus
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% 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
Title check ✅ Passed The title 'Papilo primal/dual crush' directly summarizes the main feature: implementing crushing of primal and dual vectors in Papilo reduced problem space.
Description check ✅ Passed The description clearly relates to the changeset, explaining support for crushing primal/dual vectors and including an OMP bugfix, with closed issue references.
Linked Issues check ✅ Passed The PR implements all core requirements: primal crushing for MIP (#513), primal/dual crushing for LP (#1060), and a related OMP bugfix for consecutive solves.
Out of Scope Changes check ✅ Passed All changes are in scope: crushing logic in third_party_presolve, diversity manager integration, early heuristic incumbent pooling, test additions, and expanded dataset downloads.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp`:
- Around line 1092-1096: The loop that updates z for removed rows uses an exact
check y[i] == 0 which is too strict; replace that check with the
function/epsilon-based test used elsewhere in this function (i.e., treat y as
zero when fabs(y[i]) <= the existing numeric tolerance or by calling the
existing isZero/is_near_zero helper) so that only truly near-zero y[i] are
skipped; locate the loop referencing storage.nRowsOriginal, row_survives, y,
A_offsets, A_indices, z and get_coeff and change the condition to use the same
tolerance variable or helper used elsewhere in this file to avoid injecting
noise into z (and therefore z_reduced).
- Around line 973-980: The kParallelCol case only updates the primal x but fails
to fold reduced costs; update the corresponding dual/reduced-cost vector (z)
analogously so eliminated parallel-column contributions aren't lost: inside the
ReductionType::kParallelCol branch (where col1 = indices[first], col2 =
indices[first+2], scale = values[first+4] and x[col2] += scale * x[col1]) also
perform z[col2] += scale * z[col1] (using the same index mapping and scale),
ensuring you access the z array from the same problem context and respect any
index-mapping helpers used elsewhere in this function.

In `@cpp/tests/linear_programming/unit_tests/presolve_test.cu`:
- Around line 859-861: The test currently uses EXPECT_LT(warm_iters, cold_iters)
which enforces a strict decrease and makes the test flaky; change the assertion
to EXPECT_LE(warm_iters, cold_iters) so the warm-started PDLP is allowed to take
the same number of iterations as the cold run. Update the failure message if
desired but keep the same variables (warm_iters, cold_iters) and replace the
EXPECT_LT macro with EXPECT_LE in the presolve_test assertion.

In `@cpp/tests/mip/incumbent_callback_test.cu`:
- Around line 41-44: The destructor of scoped_env_restore_t always calls
::setenv(name_, prev_value_.c_str(), 1) which re-creates the variable as an
empty string if it was originally unset; change scoped_env_restore_t to record
whether the environment var existed (e.g. a bool prev_exists_ set in the
constructor when std::getenv(env_name) != nullptr) and in
~scoped_env_restore_t() call ::unsetenv(name_) when prev_exists_ is false,
otherwise restore the original value via ::setenv using prev_value_; update the
constructor and member fields (prev_exists_ and prev_value_) accordingly and
ensure behavior is consistent for CUOPT_DISABLE_GPU_HEURISTICS and similar uses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 81564330-0c16-431c-9cbc-81de259afadb

📥 Commits

Reviewing files that changed from the base of the PR and between 9fe95f2 and d47d709.

📒 Files selected for processing (7)
  • cpp/src/mip_heuristics/diversity/diversity_manager.cu
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
  • cpp/src/mip_heuristics/presolve/third_party_presolve.hpp
  • cpp/src/mip_heuristics/solve.cu
  • cpp/tests/linear_programming/unit_tests/presolve_test.cu
  • cpp/tests/mip/incumbent_callback_test.cu
  • datasets/mip/download_miplib_test_dataset.sh

Comment on lines +973 to +980
case ReductionType::kParallelCol: {
// Storage layout: [orig_col1, flags1, orig_col2, flags2, -1]
// [col1lb, col1ub, col2lb, col2ub, col2scale]
int col1 = indices[first];
int col2 = indices[first + 2];
const f_t& scale = values[first + 4];
x[col2] += scale * x[col1];
break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fold reduced costs through kParallelCol as well.

This forward replay updates the survivor primal value, but it leaves z in the original basis. After the final projection, any eliminated parallel column contribution is dropped, so z_reduced is wrong whenever dual/reduced-cost crushing hits a parallel-column reduction.

🐛 Suggested fix
       case ReductionType::kParallelCol: {
         // Storage layout: [orig_col1, flags1, orig_col2, flags2, -1]
         //                 [col1lb,    col1ub, col2lb,    col2ub, col2scale]
         int col1         = indices[first];
         int col2         = indices[first + 2];
         const f_t& scale = values[first + 4];
         x[col2] += scale * x[col1];
+        if (crush_rc) { z[col2] += scale * z[col1]; }
         break;
       }

As per coding guidelines, **/*.{cu,cuh,cpp,hpp,h}: Validate algorithm correctness in optimization logic and 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.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp` around lines 973 -
980, The kParallelCol case only updates the primal x but fails to fold reduced
costs; update the corresponding dual/reduced-cost vector (z) analogously so
eliminated parallel-column contributions aren't lost: inside the
ReductionType::kParallelCol branch (where col1 = indices[first], col2 =
indices[first+2], scale = values[first+4] and x[col2] += scale * x[col1]) also
perform z[col2] += scale * z[col1] (using the same index mapping and scale),
ensuring you access the z array from the same problem context and respect any
index-mapping helpers used elsewhere in this function.

Comment on lines +1092 to +1096
for (int i = 0; i < (int)storage.nRowsOriginal; ++i) {
if (row_survives[i] || y[i] == 0) continue;
for (i_t p = A_offsets[i]; p < A_offsets[i + 1]; ++p) {
z[A_indices[p]] += y[i] * get_coeff(i, A_indices[p]);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid exact-zero checks on removed-row duals.

y[i] == 0 is too strict for approximate PDLP/DualSimplex duals. Near-zero removed-row multipliers will still enter this correction path and inject noise into z_reduced. Use the same numeric tolerance machinery you already use elsewhere in this function.

As per coding guidelines, **/*.{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.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp` around lines 1092 -
1096, The loop that updates z for removed rows uses an exact check y[i] == 0
which is too strict; replace that check with the function/epsilon-based test
used elsewhere in this function (i.e., treat y as zero when fabs(y[i]) <= the
existing numeric tolerance or by calling the existing isZero/is_near_zero
helper) so that only truly near-zero y[i] are skipped; locate the loop
referencing storage.nRowsOriginal, row_survives, y, A_offsets, A_indices, z and
get_coeff and change the condition to use the same tolerance variable or helper
used elsewhere in this file to avoid injecting noise into z (and therefore
z_reduced).

Comment on lines +859 to +861
EXPECT_LT(warm_iters, cold_iters)
<< "warmstarted solve should not take more iterations than cold solve"
<< " (cold=" << cold_iters << ", warm=" << warm_iters << ")";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don’t require a strict iteration drop here.

Warm-started PDLP can legitimately converge in the same number of iterations as the cold run because of fixed startup/restart behavior. EXPECT_LT makes this test flaky even when the warm start is working.

💡 Suggested fix
-  EXPECT_LT(warm_iters, cold_iters)
+  EXPECT_LE(warm_iters, cold_iters)
     << "warmstarted solve should not take more iterations than cold solve"
     << " (cold=" << cold_iters << ", warm=" << warm_iters << ")";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
EXPECT_LT(warm_iters, cold_iters)
<< "warmstarted solve should not take more iterations than cold solve"
<< " (cold=" << cold_iters << ", warm=" << warm_iters << ")";
EXPECT_LE(warm_iters, cold_iters)
<< "warmstarted solve should not take more iterations than cold solve"
<< " (cold=" << cold_iters << ", warm=" << warm_iters << ")";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/tests/linear_programming/unit_tests/presolve_test.cu` around lines 859 -
861, The test currently uses EXPECT_LT(warm_iters, cold_iters) which enforces a
strict decrease and makes the test flaky; change the assertion to
EXPECT_LE(warm_iters, cold_iters) so the warm-started PDLP is allowed to take
the same number of iterations as the cold run. Update the failure message if
desired but keep the same variables (warm_iters, cold_iters) and replace the
EXPECT_LT macro with EXPECT_LE in the presolve_test assertion.

Comment on lines +41 to +44
if (const char* prev = std::getenv(env_name)) { prev_value_ = prev; }
::setenv(env_name, new_value, 1);
}
~scoped_env_restore_t() { ::setenv(name_, prev_value_.c_str(), 1); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Restore the original unset state, not an empty string.

If CUOPT_DISABLE_GPU_HEURISTICS was originally unset, the destructor currently leaves it defined as "". That leaks process-global state across tests and can change behavior for code that branches on std::getenv(...) != nullptr.

💡 Suggested fix
 class scoped_env_restore_t {
  public:
   scoped_env_restore_t(const char* env_name, const char* new_value) : name_(env_name)
   {
-    if (const char* prev = std::getenv(env_name)) { prev_value_ = prev; }
+    if (const char* prev = std::getenv(env_name)) {
+      had_prev_value_ = true;
+      prev_value_     = prev;
+    }
     ::setenv(env_name, new_value, 1);
   }
-  ~scoped_env_restore_t() { ::setenv(name_, prev_value_.c_str(), 1); }
+  ~scoped_env_restore_t()
+  {
+    if (had_prev_value_) {
+      ::setenv(name_, prev_value_.c_str(), 1);
+    } else {
+      ::unsetenv(name_);
+    }
+  }
   scoped_env_restore_t(const scoped_env_restore_t&)            = delete;
   scoped_env_restore_t& operator=(const scoped_env_restore_t&) = delete;

  private:
   const char* name_;
+  bool had_prev_value_ = false;
   std::string prev_value_;
 };

As per coding guidelines, **/*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.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/tests/mip/incumbent_callback_test.cu` around lines 41 - 44, The
destructor of scoped_env_restore_t always calls ::setenv(name_,
prev_value_.c_str(), 1) which re-creates the variable as an empty string if it
was originally unset; change scoped_env_restore_t to record whether the
environment var existed (e.g. a bool prev_exists_ set in the constructor when
std::getenv(env_name) != nullptr) and in ~scoped_env_restore_t() call
::unsetenv(name_) when prev_exists_ is false, otherwise restore the original
value via ::setenv using prev_value_; update the constructor and member fields
(prev_exists_ and prev_value_) accordingly and ensure behavior is consistent for
CUOPT_DISABLE_GPU_HEURISTICS and similar uses.

* kRowBoundChangeForcedByRow — conditionally transfers y[deleted_row] → y[kept_row]
*/
template <typename i_t, typename f_t>
void third_party_presolve_t<i_t, f_t>::crush_primal_dual_solution(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we push this to Papilo itself?

When new presolvers (or reductions) are added, this can get outdated.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's on my radar :) There are a couple of PRs I will be pushing to Papilo

@anandhkb anandhkb modified the milestones: 26.04, 26.06 Apr 16, 2026
@github-actions

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@aliceb-nv

Copy link
Copy Markdown
Contributor Author

/ok to test 157045b

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/src/mip_heuristics/diversity/diversity_manager.cu`:
- Around line 439-441: The early return when check_b_b_preemption() is true can
skip loading warm-starts, causing initial_sol_vector not to be added to
population; move or duplicate the calls to
add_user_given_solutions(initial_sol_vector) and
population.add_solutions_from_vec(std::move(initial_sol_vector)) so they run
before the preemption check (or ensure they run unconditionally irrespective of
preempt_heuristic_solver_), keeping the check_b_b_preemption() return behavior
and references to population.best_feasible() unchanged.
- Around line 193-199: The code currently calls cuopt_assert when
init_sol_assignment.size() != papilo_orig_n inside the has_papilo branch;
instead, guard that condition with a runtime check and treat it as a recoverable
bad warm-start: if sizes differ, log/reject the warm-start entry and skip the
Papilo-specific path (do not call
problem_ptr->presolve_data.papilo_presolve_ptr->crush_primal_solution or
device_copy), allowing the existing “cannot add” handling to run later; replace
the cuopt_assert with an if that records the mismatch (using the same logging
mechanism used elsewhere) and continues without aborting so malformed user input
is handled gracefully.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4f3f0adf-41f2-4749-89ad-2df9c433d3c6

📥 Commits

Reviewing files that changed from the base of the PR and between d47d709 and 157045b.

📒 Files selected for processing (2)
  • cpp/src/mip_heuristics/diversity/diversity_manager.cu
  • cpp/src/mip_heuristics/solve.cu
🚧 Files skipped from review as they are similar to previous changes (1)
  • cpp/src/mip_heuristics/solve.cu

Comment thread cpp/src/mip_heuristics/diversity/diversity_manager.cu
Comment thread cpp/src/mip_heuristics/diversity/diversity_manager.cu Outdated
@aliceb-nv

Copy link
Copy Markdown
Contributor Author

/ok to test 6f5f716

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cpp/src/mip_heuristics/diversity/diversity_manager.cu`:
- Line 480: The early return when check_b_b_preemption() is true can skip adding
user warm-starts; ensure initial_sol_vector is always moved into population
before any preemption return by calling
population.add_solutions_from_vec(std::move(initial_sol_vector)) prior to the
check_b_b_preemption() short-circuit, or alternatively defer the check and
replace the early return with a conditional that first adds the solutions then
returns population.best_feasible(); update the logic around
check_b_b_preemption(),
population.add_solutions_from_vec(std::move(initial_sol_vector)), and the
population.best_feasible() return to guarantee user-provided initial solutions
are added before exiting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0ba11407-611e-4f51-af1e-1f8fc3a89a98

📥 Commits

Reviewing files that changed from the base of the PR and between 157045b and 6f5f716.

📒 Files selected for processing (1)
  • cpp/src/mip_heuristics/diversity/diversity_manager.cu

population.allocate_solutions();
if (check_b_b_preemption()) { return population.best_feasible(); }
add_user_given_solutions(initial_sol_vector);
if (check_b_b_preemption()) { return population.best_feasible(); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Early preemption can still drop user warm-starts in the main path.

At Line 480, check_b_b_preemption() can return before population.add_solutions_from_vec(std::move(initial_sol_vector)) (Line 616), so user-provided initial solutions may never reach population on early exit.

Suggested minimal fix
   add_user_given_solutions(initial_sol_vector);
-  if (check_b_b_preemption()) { return population.best_feasible(); }
+  if (check_b_b_preemption()) {
+    population.add_solutions_from_vec(std::move(initial_sol_vector));
+    return population.best_feasible();
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (check_b_b_preemption()) { return population.best_feasible(); }
add_user_given_solutions(initial_sol_vector);
if (check_b_b_preemption()) {
population.add_solutions_from_vec(std::move(initial_sol_vector));
return population.best_feasible();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cpp/src/mip_heuristics/diversity/diversity_manager.cu` at line 480, The early
return when check_b_b_preemption() is true can skip adding user warm-starts;
ensure initial_sol_vector is always moved into population before any preemption
return by calling
population.add_solutions_from_vec(std::move(initial_sol_vector)) prior to the
check_b_b_preemption() short-circuit, or alternatively defer the check and
replace the early return with a conditional that first adds the solutions then
returns population.best_feasible(); update the logic around
check_b_b_preemption(),
population.add_solutions_from_vec(std::move(initial_sol_vector)), and the
population.best_feasible() return to guarantee user-provided initial solutions
are added before exiting.

@aliceb-nv aliceb-nv requested a review from rg20 April 24, 2026 14:47
@github-actions

github-actions Bot commented May 2, 2026

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

2 similar comments
@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@github-actions

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@nguidotti nguidotti added the P2 label May 19, 2026
@ramakrishnap-nv ramakrishnap-nv changed the base branch from main to release/26.06 May 20, 2026 17:46
@nguidotti nguidotti modified the milestones: 26.06, 26.08 May 22, 2026
@nguidotti nguidotti changed the base branch from release/26.06 to main May 22, 2026 09:45
@nguidotti

Copy link
Copy Markdown
Contributor

Moving to 26.08

@github-actions

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

3 similar comments
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@github-actions

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@github-actions

Copy link
Copy Markdown

🔔 Hi @anandhkb, this pull request has had no activity for 7 days. Please update or let us know if it can be closed. Thank you!

If this is an "epic" issue, then please add the "epic" label to this issue.
If it is a PR and not ready for review, then please convert this to draft.
If you just want to switch off this notification, then use the "skip inactivity reminder" label.

@aliceb-nv

Copy link
Copy Markdown
Contributor Author

/ok to test a6a6a1b

@aliceb-nv aliceb-nv requested a review from a team as a code owner June 23, 2026 11:54
This reverts commit 3025d8e.
@aliceb-nv

Copy link
Copy Markdown
Contributor Author

/ok to test 0174bee

presolver.addPresolveMethod(uptr(new papilo::Probing<f_t>()));

if (!dual_postsolve) {
// SingletonStuffing causes dual crushing failures on:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There is no dual crush for MIP right?


// Track current coefficient values for entries modified by kCoefficientChange,
// so repeated changes to the same (row, col) are handled correctly.
std::map<std::pair<int, int>, f_t> coeff_current;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This can be very slow.

Can you avoid map? Can you just store a CSR/COO of the size of the original matrix?

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 P2

Projects

None yet

4 participants