From 55d78311e7096434493c0f223d177b924dde7970 Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 12:00:35 +0000 Subject: [PATCH 1/7] fix edge case --- .../mip/feasibility_jump/feasibility_jump_impl_common.cuh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh index fbc5a7b39..127b9322c 100644 --- a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh +++ b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh @@ -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 */ @@ -144,8 +144,8 @@ HDI std::pair feas_score_constraint( bool new_viol = fj.excess_score(cstr_idx, current_lhs + cstr_coeff * delta, c_lb, c_ub) < -cstr_tolerance; - bool old_sat = old_lhs < rhs + cstr_tolerance; - bool new_sat = new_lhs < rhs + cstr_tolerance; + bool old_sat = old_lhs <= rhs + cstr_tolerance; + bool new_sat = new_lhs <= rhs + cstr_tolerance; // equality if (fj.pb.integer_equal(c_lb, c_ub)) { From b80b3fd6a531f1b2f62df2ec2072d5612a9e9f93 Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 12:01:21 +0000 Subject: [PATCH 2/7] bump1 --- cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh index 127b9322c..91fdd6a47 100644 --- a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh +++ b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh @@ -147,7 +147,7 @@ HDI std::pair feas_score_constraint( bool old_sat = old_lhs <= rhs + cstr_tolerance; bool new_sat = new_lhs <= rhs + cstr_tolerance; - // equality + // equality1 if (fj.pb.integer_equal(c_lb, c_ub)) { if (!old_viol) cuopt_assert(old_sat == !old_viol, ""); if (!new_viol) cuopt_assert(new_sat == !new_viol, ""); From 3bf65220b27f9e880d19340776009399a46e2f1b Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 12:01:39 +0000 Subject: [PATCH 3/7] bump2 --- cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh index 91fdd6a47..127b9322c 100644 --- a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh +++ b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh @@ -147,7 +147,7 @@ HDI std::pair feas_score_constraint( bool old_sat = old_lhs <= rhs + cstr_tolerance; bool new_sat = new_lhs <= rhs + cstr_tolerance; - // equality1 + // equality if (fj.pb.integer_equal(c_lb, c_ub)) { if (!old_viol) cuopt_assert(old_sat == !old_viol, ""); if (!new_viol) cuopt_assert(new_sat == !new_viol, ""); From 523835d21143936850a51519542f4372541a5f53 Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 13:51:56 +0000 Subject: [PATCH 4/7] tentative fixes --- cpp/src/dual_simplex/cuts.cpp | 1 + cpp/src/linear_programming/pdlp_constants.hpp | 3 ++- cpp/src/mip/feasibility_jump/feasibility_jump.cu | 14 ++++++++------ .../feasibility_jump_impl_common.cuh | 2 ++ .../feasibility_jump/feasibility_jump_kernels.cu | 3 ++- cpp/src/mip/local_search/local_search.cu | 3 +-- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cpp/src/dual_simplex/cuts.cpp b/cpp/src/dual_simplex/cuts.cpp index be3f3001d..0bb4e1744 100644 --- a/cpp/src/dual_simplex/cuts.cpp +++ b/cpp/src/dual_simplex/cuts.cpp @@ -2775,6 +2775,7 @@ void verify_cuts_against_saved_solution(const csr_matrix_t& cuts, #ifdef DUAL_SIMPLEX_INSTANTIATE_DOUBLE template class cut_pool_t; template class cut_generation_t; +template class knapsack_generation_t; template class tableau_equality_t; template class mixed_integer_rounding_cut_t; diff --git a/cpp/src/linear_programming/pdlp_constants.hpp b/cpp/src/linear_programming/pdlp_constants.hpp index a2b36a4aa..cf17cc985 100644 --- a/cpp/src/linear_programming/pdlp_constants.hpp +++ b/cpp/src/linear_programming/pdlp_constants.hpp @@ -14,7 +14,8 @@ namespace cuopt::linear_programming::detail { inline constexpr int block_size = 128; -static std::pair inline kernel_config_from_batch_size(const size_t batch_size) +[[maybe_unused]] static std::pair inline kernel_config_from_batch_size( + const size_t batch_size) { assert(batch_size > 0 && "Batch size must be greater than 0"); const size_t block_size = std::min(static_cast(256), batch_size); diff --git a/cpp/src/mip/feasibility_jump/feasibility_jump.cu b/cpp/src/mip/feasibility_jump/feasibility_jump.cu index c43939cd1..7d721b361 100644 --- a/cpp/src/mip/feasibility_jump/feasibility_jump.cu +++ b/cpp/src/mip/feasibility_jump/feasibility_jump.cu @@ -258,13 +258,15 @@ void fj_t::copy_weights(const weight_t& weights, fj_left_weights = make_span(cstr_left_weights), fj_right_weights = make_span(cstr_right_weights), new_weights = make_span(weights.cstr_weights)] __device__(i_t idx) { - fj_weights[idx] = idx >= old_size ? 1. : new_weights[idx]; + f_t new_weight = idx >= old_size ? 1. : new_weights[idx]; + cuopt_assert(isfinite(new_weight), "invalid weight"); + cuopt_assert(new_weight >= 0.0, "invalid weight"); + new_weight = std::max(new_weight, 0.0); + + fj_weights[idx] = idx >= old_size ? 1. : new_weight; // TODO: ask Alice how we can manage the previous left,right weights - fj_left_weights[idx] = idx >= old_size ? 1. : new_weights[idx]; - fj_right_weights[idx] = idx >= old_size ? 1. : new_weights[idx]; - cuopt_assert(isfinite(fj_weights[idx]), "invalid weight"); - cuopt_assert(isfinite(fj_left_weights[idx]), "invalid left weight"); - cuopt_assert(isfinite(fj_right_weights[idx]), "invalid right weight"); + fj_left_weights[idx] = idx >= old_size ? 1. : new_weight; + fj_right_weights[idx] = idx >= old_size ? 1. : new_weight; }); thrust::transform(handle_ptr->get_thrust_policy(), weights.objective_weight.data(), diff --git a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh index 127b9322c..e57f0ec9e 100644 --- a/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh +++ b/cpp/src/mip/feasibility_jump/feasibility_jump_impl_common.cuh @@ -138,6 +138,8 @@ HDI std::pair feas_score_constraint( cuopt_assert(isfinite(new_lhs), ""); cuopt_assert(isfinite(old_slack) && isfinite(new_slack), ""); + cstr_weight = std::max(cstr_weight, 0.0); + f_t cstr_tolerance = fj.get_corrected_tolerance(cstr_idx); bool old_viol = fj.excess_score(cstr_idx, current_lhs, c_lb, c_ub) < -cstr_tolerance; diff --git a/cpp/src/mip/feasibility_jump/feasibility_jump_kernels.cu b/cpp/src/mip/feasibility_jump/feasibility_jump_kernels.cu index 5e6fef7e1..41151d377 100644 --- a/cpp/src/mip/feasibility_jump/feasibility_jump_kernels.cu +++ b/cpp/src/mip/feasibility_jump/feasibility_jump_kernels.cu @@ -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 */ @@ -119,6 +119,7 @@ DI void update_weights(typename fj_t::climber_data_t::view_t& fj) if (threadIdx.x == 0) { // DEVICE_LOG_DEBUG("weight of con %d updated to %g, excess %f\n", cstr_idx, new_weight, // curr_excess_score); + new_weight = std::max(new_weight, 0.0); fj.cstr_weights[cstr_idx] = max(fj.cstr_weights[cstr_idx], new_weight); if (curr_lower_excess < 0.) { fj.cstr_left_weights[cstr_idx] = new_weight; diff --git a/cpp/src/mip/local_search/local_search.cu b/cpp/src/mip/local_search/local_search.cu index 71b944a09..dafa81e3d 100644 --- a/cpp/src/mip/local_search/local_search.cu +++ b/cpp/src/mip/local_search/local_search.cu @@ -82,8 +82,7 @@ void local_search_t::start_cpufj_scratch_threads(population_t 0); cpu_fj.fj_cpu->log_prefix = "******* scratch " + std::to_string(counter) + ": "; - cpu_fj.fj_cpu->improvement_callback = [&population, problem_ptr = context.problem_ptr]( - f_t obj, const std::vector& h_vec) { + cpu_fj.fj_cpu->improvement_callback = [&population](f_t obj, const std::vector& h_vec) { population.add_external_solution(h_vec, obj, solution_origin_t::CPUFJ); if (obj < local_search_best_obj) { CUOPT_LOG_TRACE("******* New local search best obj %g, best overall %g", From c1f71032255eb788fa9fe28315e7de97450496e8 Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 13:52:16 +0000 Subject: [PATCH 5/7] bump1 --- cpp/src/mip/local_search/local_search.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/mip/local_search/local_search.cu b/cpp/src/mip/local_search/local_search.cu index dafa81e3d..a6ff5315d 100644 --- a/cpp/src/mip/local_search/local_search.cu +++ b/cpp/src/mip/local_search/local_search.cu @@ -79,7 +79,7 @@ void local_search_t::start_cpufj_scratch_threads(population_t 0); + /*1randomize=*/counter > 0); cpu_fj.fj_cpu->log_prefix = "******* scratch " + std::to_string(counter) + ": "; cpu_fj.fj_cpu->improvement_callback = [&population](f_t obj, const std::vector& h_vec) { From cdafbf03bfe6ad5f9e923f4a86d7c0cf5a1c0b7b Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 13:52:30 +0000 Subject: [PATCH 6/7] bump2 --- cpp/src/mip/local_search/local_search.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/mip/local_search/local_search.cu b/cpp/src/mip/local_search/local_search.cu index a6ff5315d..dafa81e3d 100644 --- a/cpp/src/mip/local_search/local_search.cu +++ b/cpp/src/mip/local_search/local_search.cu @@ -79,7 +79,7 @@ void local_search_t::start_cpufj_scratch_threads(population_t 0); + /*randomize=*/counter > 0); cpu_fj.fj_cpu->log_prefix = "******* scratch " + std::to_string(counter) + ": "; cpu_fj.fj_cpu->improvement_callback = [&population](f_t obj, const std::vector& h_vec) { From 313ad62440be833267082292f1d9748cf827b798 Mon Sep 17 00:00:00 2001 From: Alice Boucher Date: Fri, 6 Feb 2026 15:19:43 +0000 Subject: [PATCH 7/7] review comment --- cpp/src/mip/local_search/local_search.cu | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/src/mip/local_search/local_search.cu b/cpp/src/mip/local_search/local_search.cu index dafa81e3d..4f56c52ee 100644 --- a/cpp/src/mip/local_search/local_search.cu +++ b/cpp/src/mip/local_search/local_search.cu @@ -82,8 +82,10 @@ void local_search_t::start_cpufj_scratch_threads(population_t 0); cpu_fj.fj_cpu->log_prefix = "******* scratch " + std::to_string(counter) + ": "; - cpu_fj.fj_cpu->improvement_callback = [&population](f_t obj, const std::vector& h_vec) { + cpu_fj.fj_cpu->improvement_callback = [&population, problem_ptr = context.problem_ptr]( + f_t obj, const std::vector& h_vec) { population.add_external_solution(h_vec, obj, solution_origin_t::CPUFJ); + (void)problem_ptr; if (obj < local_search_best_obj) { CUOPT_LOG_TRACE("******* New local search best obj %g, best overall %g", problem_ptr->get_user_obj_from_solver_obj(obj),