Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
00ae695
no recombiner
akifcorduk Oct 22, 2025
049d07e
temporary test on obj cut
akifcorduk Oct 23, 2025
b1e7e85
fix few issues
akifcorduk Oct 24, 2025
11d853e
handle weight mismatch
akifcorduk Oct 24, 2025
5570016
ls time always 1 s
akifcorduk Oct 24, 2025
300ad96
fix timer
akifcorduk Oct 24, 2025
6f557c0
shorter fj, longer lp
akifcorduk Oct 24, 2025
b99ed04
best in population, restart fp, longer fj
akifcorduk Oct 24, 2025
d1413c8
return first feas
akifcorduk Oct 24, 2025
60c2620
Revert "return first feas"
akifcorduk Oct 27, 2025
30375e2
only do weights on FJ
akifcorduk Oct 27, 2025
9dc0ace
sqrt diversiyt
akifcorduk Oct 27, 2025
58b7b2a
fix external solutions adding
akifcorduk Oct 28, 2025
28ac0e8
fix cut issues
akifcorduk Oct 28, 2025
50f3d8e
old diversity
akifcorduk Oct 28, 2025
dca499e
run submip with cuts
akifcorduk Oct 29, 2025
aaa1097
add cutting plane to line segment
akifcorduk Oct 29, 2025
a99d0f4
added bounds prop
akifcorduk Oct 29, 2025
550635f
add also FP
akifcorduk Oct 29, 2025
f1c977b
old diversity and no objective cut on population
akifcorduk Oct 30, 2025
de8d2c3
Merge branch 'main' of github.com:NVIDIA/cuopt into obj_cut_at_recomb…
akifcorduk Nov 27, 2025
47c62fa
fix few merge conflicts
akifcorduk Nov 27, 2025
67f5008
handle review comments
akifcorduk Nov 28, 2025
2a72dde
Merge branch 'release/25.12' of github.com:NVIDIA/cuopt into obj_cut_…
akifcorduk Nov 28, 2025
1695286
build run_mip off
akifcorduk Nov 28, 2025
0acb5be
fix lp time and population insert
akifcorduk Dec 1, 2025
aa78fa6
revert timer changes
akifcorduk Dec 1, 2025
7fb2ed5
fix timer
akifcorduk Dec 1, 2025
e10e419
Merge branch 'main' of github.com:NVIDIA/cuopt into obj_cut_at_recomb…
akifcorduk Jan 13, 2026
fd701f6
license precommit runs
akifcorduk Jan 13, 2026
b22e3a4
fix merge conflicts
akifcorduk Jan 13, 2026
6b26c1b
revert lineinfo
akifcorduk Jan 14, 2026
79e71a1
revert cmake pos change
akifcorduk Jan 16, 2026
82a6020
Merge branch 'main' of github.com:NVIDIA/cuopt into obj_cut_at_recomb…
akifcorduk Jan 16, 2026
77f3721
disable cuts
akifcorduk Jan 19, 2026
a623d4b
fix swap pointer in recombiners
akifcorduk Jan 19, 2026
46a9646
adjsut local search time
akifcorduk Jan 19, 2026
a150f86
revert cuts in recombiners and population
akifcorduk Jan 19, 2026
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
4 changes: 2 additions & 2 deletions benchmarks/linear_programming/cuopt/run_mip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,6 @@ int main(int argc, char* argv[])
double memory_limit = program.get<double>("--memory-limit");
bool track_allocations = program.get<std::string>("--track-allocations")[0] == 't';

if (num_cpu_threads < 0) { num_cpu_threads = omp_get_max_threads() / n_gpus; }

if (program.is_used("--out-dir")) {
out_dir = program.get<std::string>("--out-dir");
result_file = out_dir + "/final_result.csv";
Expand Down Expand Up @@ -421,6 +419,7 @@ int main(int argc, char* argv[])
paths.push_back(entry.path());
}
}
if (num_cpu_threads < 0) { num_cpu_threads = omp_get_max_threads() / n_gpus; }
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential division by zero if n_gpus is 0.

While n_gpus defaults to 1, there's no validation preventing a user from passing --n-gpus 0, which would cause undefined behavior here. Consider adding an early validation check.

🛡️ Suggested validation (add after line 367)
if (n_gpus <= 0) {
  std::cerr << "Error: --n-gpus must be >= 1" << std::endl;
  return 1;
}
🤖 Prompt for AI Agents
In @benchmarks/linear_programming/cuopt/run_mip.cpp at line 416, Add an early
validation that ensures n_gpus is >= 1 before it's used to compute
num_cpu_threads (i.e., before the expression that calls omp_get_max_threads() /
n_gpus); if n_gpus <= 0, print a clear error to std::cerr and return a non-zero
exit code so the program aborts cleanly. Locate the check near the
initialization/parse area where n_gpus is set (before the line that assigns
num_cpu_threads using omp_get_max_threads()) and ensure the validation prevents
the subsequent division by zero.

// if batch_num is given, trim the paths to only concerned batch
if (batch_num != -1) {
if (n_batches <= 0) {
Expand Down Expand Up @@ -487,6 +486,7 @@ int main(int argc, char* argv[])
}
merge_result_files(out_dir, result_file, n_gpus, batch_num);
} else {
if (num_cpu_threads < 0) { num_cpu_threads = omp_get_max_threads(); }
auto memory_resource = make_async();
if (memory_limit > 0) {
auto limiting_adaptor =
Expand Down
1 change: 0 additions & 1 deletion cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ if(DEFINE_ASSERT)
add_definitions(-UNDEBUG)
endif()


# ##################################################################################################
# - find CPM based dependencies ------------------------------------------------------------------
rapids_cpm_init()
Expand Down
3 changes: 1 addition & 2 deletions cpp/src/mip/diversity/diversity_manager.cu
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,7 @@ void diversity_manager_t<i_t, f_t>::diversity_step(i_t max_iterations_without_im
improved = false;
while (k-- > 0) {
if (check_b_b_preemption()) { return; }
auto new_sol_vector = population.get_external_solutions();
recombine_and_ls_with_all(new_sol_vector);
population.add_external_solutions_to_population();
population.adjust_weights_according_to_best_feasible();
cuopt_assert(population.test_invariant(), "");
if (population.current_size() < 2) {
Expand Down
53 changes: 6 additions & 47 deletions cpp/src/mip/diversity/population.cu
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand All @@ -24,7 +24,6 @@ constexpr double weight_decrease_ratio = 0.9;
constexpr double max_infeasibility_weight = 1e12;
constexpr double min_infeasibility_weight = 1.;
constexpr double infeasibility_balance_ratio = 1.1;
constexpr double halving_skip_ratio = 0.75;

template <typename i_t, typename f_t>
population_t<i_t, f_t>::population_t(std::string const& name_,
Expand All @@ -42,7 +41,6 @@ population_t<i_t, f_t>::population_t(std::string const& name_,
infeasibility_importance(infeasibility_weight_),
weights(0, context.problem_ptr->handle_ptr),
rng(cuopt::seed_generator::get_seed()),
early_exit_primal_generation(false),
population_hash_map(*problem_ptr),
timer(0)
{
Expand Down Expand Up @@ -109,12 +107,11 @@ std::pair<solution_t<i_t, f_t>, solution_t<i_t, f_t>> population_t<i_t, f_t>::ge
auto second_solution = solutions[indices[j].first].second;
// if best feasible and best are the same, take the second index instead of best
if (i == 0 && j == 1) {
bool same =
check_integer_equal_on_indices(first_solution.problem_ptr->integer_indices,
first_solution.assignment,
second_solution.assignment,
first_solution.problem_ptr->tolerances.integrality_tolerance,
first_solution.handle_ptr);
bool same = check_integer_equal_on_indices(problem_ptr->integer_indices,
first_solution.assignment,
second_solution.assignment,
problem_ptr->tolerances.integrality_tolerance,
first_solution.handle_ptr);
if (same) {
auto new_sol = solutions[indices[2].first].second;
second_solution = std::move(new_sol);
Expand Down Expand Up @@ -172,7 +169,6 @@ void population_t<i_t, f_t>::add_external_solution(const std::vector<f_t>& solut
CUOPT_LOG_DEBUG("Found new best solution %g in external queue",
problem_ptr->get_user_obj_from_solver_obj(objective));
}
if (external_solution_queue.size() >= 5) { early_exit_primal_generation = true; }
solutions_in_external_queue_ = true;
}

Expand All @@ -192,7 +188,6 @@ template <typename i_t, typename f_t>
void population_t<i_t, f_t>::preempt_heuristic_solver()
{
context.preempt_heuristic_solver_ = true;
early_exit_primal_generation = true;
}

template <typename i_t, typename f_t>
Expand Down Expand Up @@ -668,42 +663,6 @@ std::vector<solution_t<i_t, f_t>> population_t<i_t, f_t>::population_to_vector()
return sol_vec;
}

template <typename i_t, typename f_t>
void population_t<i_t, f_t>::halve_the_population()
{
raft::common::nvtx::range fun_scope("halve_the_population");
// try 3/4 here
if (current_size() <= (max_solutions * halving_skip_ratio)) { return; }
CUOPT_LOG_DEBUG("Halving the population, current size: %lu", current_size());
// put population into a vector
auto sol_vec = population_to_vector();
i_t counter = 0;
constexpr i_t max_adjustments = 4;
size_t max_var_threshold = get_max_var_threshold(problem_ptr->n_integer_vars);

std::lock_guard<std::recursive_mutex> lock(write_mutex);
while (current_size() > max_solutions / 2) {
clear_except_best_feasible();
var_threshold = std::max(var_threshold * 0.97, 0.5 * problem_ptr->n_integer_vars);
for (auto& sol : sol_vec) {
add_solution(solution_t<i_t, f_t>(sol));
}
if (counter++ > max_adjustments) break;
}
counter = 0;
// if we removed too many decrease the diversity a little
while (current_size() < max_solutions / 4) {
clear_except_best_feasible();
var_threshold = std::min(
max_var_threshold,
std::min((size_t)(var_threshold * 1.02), (size_t)(0.995 * problem_ptr->n_integer_vars)));
for (auto& sol : sol_vec) {
add_solution(solution_t<i_t, f_t>(sol));
}
if (counter++ > max_adjustments) break;
}
}

template <typename i_t, typename f_t>
size_t population_t<i_t, f_t>::find_free_solution_index()
{
Expand Down
5 changes: 2 additions & 3 deletions cpp/src/mip/diversity/population.cuh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand Down Expand Up @@ -151,7 +151,6 @@ class population_t {
void find_diversity(std::vector<solution_t<i_t, f_t>>& initial_sol_vector, bool avg);

std::vector<solution_t<i_t, f_t>> population_to_vector();
void halve_the_population();

void run_solution_callbacks(solution_t<i_t, f_t>& sol);

Expand Down Expand Up @@ -202,7 +201,7 @@ class population_t {
i_t update_iter = 0;
std::recursive_mutex write_mutex;
std::mutex solution_mutex;
std::atomic<bool> early_exit_primal_generation = false;
std::atomic<bool> preempt_heuristic_solver_ = false;
std::atomic<bool> solutions_in_external_queue_ = false;
f_t best_feasible_objective = std::numeric_limits<f_t>::max();
assignment_hash_map_t<i_t, f_t> population_hash_map;
Expand Down
7 changes: 5 additions & 2 deletions cpp/src/mip/diversity/recombiners/sub_mip.cuh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* clang-format off */
/*
* SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
/* clang-format on */
Expand Down Expand Up @@ -148,7 +148,6 @@ class sub_mip_recombiner_t : public recombiner_t<i_t, f_t> {
}
cuopt_func_call(offspring.test_variable_bounds());
cuopt_assert(offspring.test_number_all_integer(), "All must be integers after offspring");
offspring.compute_feasibility();
// bool same_as_parents = this->check_if_offspring_is_same_as_parents(offspring, a, b);
// adjust the max_n_of_vars_from_other
if (n_different_vars > (i_t)sub_mip_recombiner_config_t::max_n_of_vars_from_other) {
Expand All @@ -175,6 +174,10 @@ class sub_mip_recombiner_t : public recombiner_t<i_t, f_t> {
sol.unfix_variables(fixed_assignment, variable_map);
sol.clamp_within_bounds(); // Scaling might bring some very slight variable bound violations
sol.compute_feasibility();
// the current problem is the proble with objective cut
// to add to the population, swap problem to original
cuopt_assert(sol.compute_feasibility(), "Solution must be feasible");
cuopt_assert(sol.get_feasible(), "Solution must be feasible");
cuopt_func_call(sol.test_variable_bounds());
population.add_solution(std::move(sol));
}
Expand Down
Loading