Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions cpp/src/mip_heuristics/diversity/diversity_manager.cu
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,20 @@ bool diversity_manager_t<i_t, f_t>::run_presolve(f_t time_limit)
compute_probing_cache(ls.constraint_prop.bounds_update, *problem_ptr, probing_timer);
if (problem_is_infeasible) { return false; }
}
const bool remap_cache_ids = true;
trivial_presolve(*problem_ptr, remap_cache_ids);
if (!problem_ptr->empty && !check_bounds_sanity(*problem_ptr)) { return false; }
// May overconstrain if Papilo presolve has been run before
if (context.settings.presolver == presolver_t::None) {
if (!problem_ptr->empty) {
// do the resizing no-matter what, bounds presolve might not change the bounds but initial
// trivial presolve might have
ls.constraint_prop.bounds_update.resize(*problem_ptr);
ls.constraint_prop.conditional_bounds_update.update_constraint_bounds(
*problem_ptr, ls.constraint_prop.bounds_update);
if (!check_bounds_sanity(*problem_ptr)) { return false; }
if (!presolve_timer.check_time_limit()) {
const bool remap_cache_ids = true;
trivial_presolve(*problem_ptr, remap_cache_ids);
if (!problem_ptr->empty && !check_bounds_sanity(*problem_ptr)) { return false; }
// May overconstrain if Papilo presolve has been run before
if (context.settings.presolver == presolver_t::None) {
if (!problem_ptr->empty) {
// do the resizing no-matter what, bounds presolve might not change the bounds but initial
// trivial presolve might have
ls.constraint_prop.bounds_update.resize(*problem_ptr);
ls.constraint_prop.conditional_bounds_update.update_constraint_bounds(
*problem_ptr, ls.constraint_prop.bounds_update);
if (!check_bounds_sanity(*problem_ptr)) { return false; }
}
}
}
stats.presolve_time = presolve_timer.elapsed_time();
Expand Down
7 changes: 7 additions & 0 deletions cpp/src/mip_heuristics/solve.cu
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ mip_solution_t<i_t, f_t> run_mip(detail::problem_t<i_t, f_t>& problem,
detail::trivial_presolve(scaled_problem);

detail::mip_solver_t<i_t, f_t> solver(scaled_problem, settings, scaling, timer);
if (timer.check_time_limit()) {
CUOPT_LOG_INFO("Time limit reached before main solve");
detail::solution_t<i_t, f_t> sol(problem);
auto stats = solver.get_solver_stats();
stats.total_solve_time = timer.elapsed_time();
return sol.get_solution(false, stats, false);
}
auto scaled_sol = solver.run_solver();
bool is_feasible_before_scaling = scaled_sol.get_feasible();
scaled_sol.problem_ptr = &problem;
Expand Down
16 changes: 16 additions & 0 deletions cpp/src/mip_heuristics/solver.cu
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ solution_t<i_t, f_t> mip_solver_t<i_t, f_t>::run_solver()
return sol;
}

if (timer_.check_time_limit()) {
CUOPT_LOG_INFO("Time limit reached after presolve");
solution_t<i_t, f_t> sol(*context.problem_ptr);
context.stats.total_solve_time = timer_.elapsed_time();
context.problem_ptr->post_process_solution(sol);
return sol;
}
Comment on lines +137 to +143
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find the post_process_solution implementation
rg -n "post_process_solution" --include="*.{cu,cuh,cpp,hpp,h}" -A 5 | head -100

Repository: NVIDIA/cuopt

Length of output: 497


🏁 Script executed:

#!/bin/bash
# Find all call sites of post_process_solution and the context around them
rg -n "post_process_solution" --include="*.{cu,cuh,cpp,hpp,h}" -B 2 -A 1

Repository: NVIDIA/cuopt

Length of output: 497


🏁 Script executed:

#!/bin/bash
# Check the specific file and lines mentioned in the review
cat -n cpp/src/mip_heuristics/solver.cu | sed -n '100,150p'

Repository: NVIDIA/cuopt

Length of output: 2752


🏁 Script executed:

#!/bin/bash
# Also check the other time-limit path mentioned
cat -n cpp/src/mip_heuristics/solver.cu | sed -n '290,310p'

Repository: NVIDIA/cuopt

Length of output: 1207


🏁 Script executed:

#!/bin/bash
# Search for post_process_solution method definition using ast-grep
ast-grep --pattern 'post_process_solution($_) {
  $$$
}'

Repository: NVIDIA/cuopt

Length of output: 38


🏁 Script executed:

#!/bin/bash
# Search for post_process_solution using rg with correct syntax (without --include)
rg "post_process_solution" -t cpp -t cuda -B 2 -A 5

Repository: NVIDIA/cuopt

Length of output: 84


🏁 Script executed:

#!/bin/bash
# Find the definition in the problem class
fd -e cu -e cuh -e cpp -e hpp -e h | xargs grep -l "post_process_solution" | head -5

Repository: NVIDIA/cuopt

Length of output: 269


🏁 Script executed:

#!/bin/bash
# Count occurrences of the 4-line pattern: sol construction + elapsed_time + post_process + return
# Look for the exact pattern in the file
rg "solution_t.*sol.*context\.problem_ptr" cpp/src/mip_heuristics/solver.cu -A 3 | grep -c "post_process_solution"

Repository: NVIDIA/cuopt

Length of output: 57


🏁 Script executed:

#!/bin/bash
# Look for post_process_solution definition in problem files
cat cpp/src/mip_heuristics/problem/problem.cuh | grep -n "post_process_solution" -A 10 | head -30

Repository: NVIDIA/cuopt

Length of output: 736


🏁 Script executed:

#!/bin/bash
# Check problem.cu for the implementation
cat cpp/src/mip_heuristics/problem/problem.cu | grep -n "post_process_solution" -A 15 | head -50

Repository: NVIDIA/cuopt

Length of output: 816


🏁 Script executed:

#!/bin/bash
# Find all instances of sol construction + post_process_solution pattern in solver.cu
grep -n "solution_t.*sol.*context\.problem_ptr" cpp/src/mip_heuristics/solver.cu -A 3

Repository: NVIDIA/cuopt

Length of output: 1440


🏁 Script executed:

#!/bin/bash
# Find the presolve_data.post_process_solution implementation
cat cpp/src/mip_heuristics/problem/presolve_data.cu | grep -n "post_process_solution" -A 20 | head -80

Repository: NVIDIA/cuopt

Length of output: 1146


🏁 Script executed:

#!/bin/bash
# Also check the header for the declaration
cat cpp/src/mip_heuristics/problem/presolve_data.cuh | grep -n "post_process_solution" -A 5

Repository: NVIDIA/cuopt

Length of output: 454


🏁 Script executed:

#!/bin/bash
# Count the actual occurrences of the 4-line duplication pattern more precisely
# Pattern: solution_t creation + elapsed_time + post_process + return on consecutive lines
awk '/solution_t.*sol.*context\.problem_ptr/ {
  getline; line1=$0;
  getline; line2=$0;
  getline; line3=$0;
  getline; line4=$0;
  if (line1 ~ /elapsed_time/ && line2 ~ /post_process_solution/ && line3 ~ /return/) {
    print NR-4 ": Found pattern"
    print $0; print line1; print line2; print line3
  }
}' cpp/src/mip_heuristics/solver.cu

Repository: NVIDIA/cuopt

Length of output: 367


post_process_solution called on default-constructed solution without set_problem_fully_reduced()

Both time-limit early returns (lines 137–143 and 298–302) call post_process_solution(sol) on a solution_t without calling set_problem_fully_reduced() first, unlike all other early-return paths (lines 100, 119, 126). The post_process_solution implementation accesses solution.assignment in post_process_assignment() on an uninitialized assignment. While this won't break functional correctness (the solution is marked infeasible downstream), this inconsistency should be resolved for clarity and consistency with other code paths.

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

In `@cpp/src/mip_heuristics/solver.cu` around lines 137 - 143, The early-return on
time limit creates a default solution_t<i_t, f_t> and calls
context.problem_ptr->post_process_solution(sol) without marking it as fully
reduced; update both time-limit branches (the timer_.check_time_limit() blocks
that log via CUOPT_LOG_INFO) to call sol.set_problem_fully_reduced() on the
freshly constructed solution before calling post_process_solution(sol), so
post_process_assignment() does not read an uninitialized assignment and matches
the other early-return paths.


// if the problem was reduced to a LP: run concurrent LP
if (run_presolve && context.problem_ptr->n_integer_vars == 0) {
CUOPT_LOG_INFO("Problem reduced to a LP, running concurrent LP");
Expand Down Expand Up @@ -285,6 +293,14 @@ solution_t<i_t, f_t> mip_solver_t<i_t, f_t>::run_solver()
std::placeholders::_5,
std::placeholders::_6);

if (timer_.check_time_limit()) {
CUOPT_LOG_INFO("Time limit reached during B&B setup");
solution_t<i_t, f_t> sol(*context.problem_ptr);
context.stats.total_solve_time = timer_.elapsed_time();
context.problem_ptr->post_process_solution(sol);
return sol;
}

// Fork a thread for branch and bound
// std::async and std::future allow us to get the return value of bb::solve()
// without having to manually manage the thread
Expand Down
1 change: 1 addition & 0 deletions cpp/src/pdlp/swap_and_resize_helper.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/tuple.h>
#include <thrust/universal_vector.h>

#include <cuda/std/tuple>
Expand Down
1 change: 1 addition & 0 deletions cpp/src/pdlp/utils.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <thrust/execution_policy.h>
#include <thrust/functional.h>
#include <thrust/transform_reduce.h>
#include <thrust/tuple.h>

namespace cuopt::linear_programming::detail {

Expand Down
3 changes: 2 additions & 1 deletion cpp/src/routing/utilities/check_input.cu
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand All @@ -17,6 +17,7 @@
#include <thrust/iterator/counting_iterator.h>
#include <thrust/logical.h>
#include <thrust/pair.h>
#include <thrust/tuple.h>
#include <cuda/std/functional>

#include <unordered_set>
Expand Down
1 change: 1 addition & 0 deletions cpp/src/utilities/copy_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <rmm/exec_policy.hpp>

#include <thrust/transform.h>
#include <thrust/tuple.h>
#include <thrust/universal_vector.h>

#include <cuda/std/functional>
Expand Down
1 change: 1 addition & 0 deletions cpp/src/utilities/cuda_helpers.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <utilities/macros.cuh>

#include <thrust/host_vector.h>
#include <thrust/tuple.h>
#include <mutex>
#include <raft/core/device_span.hpp>
#include <raft/util/cuda_utils.cuh>
Expand Down