From 39b49a3bfa64c89b612d5ec9c48d6ed352e52914 Mon Sep 17 00:00:00 2001 From: Kumar Aatish Date: Sun, 8 Jun 2025 16:42:25 -0400 Subject: [PATCH 1/4] fix constraint bounds inversion --- .../mip/solver_settings.hpp | 11 +++--- cpp/src/mip/diversity/diversity_manager.cu | 4 +- cpp/src/mip/presolve/bounds_presolve.cu | 37 +++++++++++++------ .../mip/presolve/bounds_update_helpers.cuh | 6 +++ cpp/src/mip/problem/problem_helpers.cuh | 32 ++++++++-------- 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/cpp/include/cuopt/linear_programming/mip/solver_settings.hpp b/cpp/include/cuopt/linear_programming/mip/solver_settings.hpp index 71afb366d5..e40fd80f88 100644 --- a/cpp/include/cuopt/linear_programming/mip/solver_settings.hpp +++ b/cpp/include/cuopt/linear_programming/mip/solver_settings.hpp @@ -70,11 +70,12 @@ class mip_solver_settings_t { bool has_initial_solution() const; struct tolerances_t { - f_t absolute_tolerance = 1.0e-4; - f_t relative_tolerance = 1.0e-6; - f_t integrality_tolerance = 1.0e-5; - f_t absolute_mip_gap = 1.0e-10; - f_t relative_mip_gap = 1.0e-4; + f_t presolve_absolute_tolerance = 1.0e-6; + f_t absolute_tolerance = 1.0e-4; + f_t relative_tolerance = 1.0e-6; + f_t integrality_tolerance = 1.0e-5; + f_t absolute_mip_gap = 1.0e-10; + f_t relative_mip_gap = 1.0e-4; }; /** diff --git a/cpp/src/mip/diversity/diversity_manager.cu b/cpp/src/mip/diversity/diversity_manager.cu index 4a8f56e987..8ce5ca4d1e 100644 --- a/cpp/src/mip/diversity/diversity_manager.cu +++ b/cpp/src/mip/diversity/diversity_manager.cu @@ -246,7 +246,7 @@ bool diversity_manager_t::run_presolve(f_t time_limit) if (termination_criterion_t::NO_UPDATE != term_crit) { ls.constraint_prop.bounds_update.set_updated_bounds(*problem_ptr); trivial_presolve(*problem_ptr); - if (!problem_ptr->empty) { check_bounds_sanity(*problem_ptr); } + if (!problem_ptr->empty && !check_bounds_sanity(*problem_ptr)) { return false; } } if (!problem_ptr->empty) { // do the resizing no-matter what, bounds presolve might not change the bounds but initial @@ -254,7 +254,7 @@ bool diversity_manager_t::run_presolve(f_t time_limit) ls.constraint_prop.bounds_update.resize(*problem_ptr); ls.constraint_prop.conditional_bounds_update.update_constraint_bounds( *problem_ptr, ls.constraint_prop.bounds_update); - check_bounds_sanity(*problem_ptr); + if (!check_bounds_sanity(*problem_ptr)) { return false; } } stats.presolve_time = presolve_timer.elapsed_time(); return true; diff --git a/cpp/src/mip/presolve/bounds_presolve.cu b/cpp/src/mip/presolve/bounds_presolve.cu index 19527d9d08..5e7d989979 100644 --- a/cpp/src/mip/presolve/bounds_presolve.cu +++ b/cpp/src/mip/presolve/bounds_presolve.cu @@ -20,7 +20,9 @@ #include #include +#include #include +#include #include #include #include @@ -350,18 +352,29 @@ void bound_presolve_t::calc_and_set_updated_constraint_bounds(problem_ { calculate_activity_on_problem_bounds(pb); - thrust::transform(pb.handle_ptr->get_thrust_policy(), - upd.max_activity.begin(), - upd.max_activity.end(), - pb.constraint_upper_bounds.begin(), - pb.constraint_upper_bounds.begin(), - thrust::minimum()); - thrust::transform(pb.handle_ptr->get_thrust_policy(), - upd.min_activity.begin(), - upd.min_activity.end(), - pb.constraint_lower_bounds.begin(), - pb.constraint_lower_bounds.begin(), - thrust::maximum()); + thrust::for_each(pb.handle_ptr->get_thrust_policy(), + thrust::make_counting_iterator(0), + thrust::make_counting_iterator(pb.n_constraints), + [pb = pb.view(), + min_act = make_span(upd.min_activity), + max_act = make_span(upd.max_activity), + cnst_lb = make_span(pb.constraint_lower_bounds), + cnst_ub = make_span(pb.constraint_upper_bounds)] __device__(i_t idx) { + auto min_a = min_act[idx]; + auto max_a = max_act[idx]; + auto c_lb = cnst_lb[idx]; + auto c_ub = cnst_ub[idx]; + auto new_c_lb = max(c_lb, min_a); + auto new_c_ub = min(c_ub, max_a); + i_t infeas = check_infeasibility( + min_a, max_a, new_c_lb, new_c_ub, pb.tolerances.presolve_absolute_tolerance); + if (!infeas && (new_c_lb > new_c_ub)) { + new_c_lb = (new_c_lb + new_c_ub) / 2; + new_c_ub = new_c_lb; + } + cnst_lb[idx] = new_c_lb; + cnst_ub[idx] = new_c_ub; + }); } #if MIP_INSTANTIATE_FLOAT diff --git a/cpp/src/mip/presolve/bounds_update_helpers.cuh b/cpp/src/mip/presolve/bounds_update_helpers.cuh index 57f3e08b9e..9fd45fb484 100644 --- a/cpp/src/mip/presolve/bounds_update_helpers.cuh +++ b/cpp/src/mip/presolve/bounds_update_helpers.cuh @@ -142,6 +142,12 @@ __global__ void calc_activity_kernel(typename problem_t::view_t pb, // Update bounds +template +inline __device__ bool check_infeasibility(f_t min_a, f_t max_a, f_t cnst_lb, f_t cnst_ub, f_t eps) +{ + return (min_a > cnst_ub + eps) || (max_a < cnst_lb - eps); +} + template inline __device__ bool check_infeasibility( f_t min_a, f_t max_a, f_t cnst_lb, f_t cnst_ub, f_t abs_tol, f_t rel_tol) diff --git a/cpp/src/mip/problem/problem_helpers.cuh b/cpp/src/mip/problem/problem_helpers.cuh index 758095b349..ddb9cbe7e2 100644 --- a/cpp/src/mip/problem/problem_helpers.cuh +++ b/cpp/src/mip/problem/problem_helpers.cuh @@ -248,42 +248,40 @@ static void check_csr_representation([[maybe_unused]] const rmm::device_uvector< } template -static void check_var_bounds_sanity(const detail::problem_t& problem) +static bool check_var_bounds_sanity(const detail::problem_t& problem) { bool crossing_bounds_detected = thrust::any_of(problem.handle_ptr->get_thrust_policy(), thrust::counting_iterator(0), thrust::counting_iterator((i_t)problem.variable_lower_bounds.size()), - [lb = make_span(problem.variable_lower_bounds), - ub = make_span(problem.variable_upper_bounds)] __device__(i_t index) { - return lb[index] > ub[index]; + [tolerance = problem.tolerances.presolve_absolute_tolerance, + lb = make_span(problem.variable_lower_bounds), + ub = make_span(problem.variable_upper_bounds)] __device__(i_t index) { + return (lb[index] > ub[index] + tolerance); }); - cuopt_expects(!crossing_bounds_detected, - error_type_t::ValidationError, - "There shouldn't be any crossing bounds in variable bounds."); + return !crossing_bounds_detected; } template -static void check_constraint_bounds_sanity(const detail::problem_t& problem) +static bool check_constraint_bounds_sanity(const detail::problem_t& problem) { bool crossing_bounds_detected = thrust::any_of(problem.handle_ptr->get_thrust_policy(), thrust::counting_iterator(0), thrust::counting_iterator((i_t)problem.constraint_lower_bounds.size()), - [lb = make_span(problem.constraint_lower_bounds), - ub = make_span(problem.constraint_upper_bounds)] __device__(i_t index) { - return lb[index] > ub[index]; + [tolerance = problem.tolerances.presolve_absolute_tolerance, + lb = make_span(problem.constraint_lower_bounds), + ub = make_span(problem.constraint_upper_bounds)] __device__(i_t index) { + return (lb[index] > ub[index] + tolerance); }); - cuopt_expects(!crossing_bounds_detected, - error_type_t::ValidationError, - "There shouldn't be any crossing bounds in constraints bounds."); + return !crossing_bounds_detected; } template -static void check_bounds_sanity(const detail::problem_t& problem) +static bool check_bounds_sanity(const detail::problem_t& problem) { - check_var_bounds_sanity(problem); - check_constraint_bounds_sanity(problem); + return check_var_bounds_sanity(problem) && + check_constraint_bounds_sanity(problem); } } // namespace cuopt::linear_programming::detail From be5d01680b9e1ad4b56382619468f2a917776156 Mon Sep 17 00:00:00 2001 From: Kumar Aatish Date: Mon, 9 Jun 2025 08:51:22 -0400 Subject: [PATCH 2/4] fix test for termination status --- cpp/tests/mip/unit_test.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/tests/mip/unit_test.cu b/cpp/tests/mip/unit_test.cu index 54a274b437..2b06c8abbc 100644 --- a/cpp/tests/mip/unit_test.cu +++ b/cpp/tests/mip/unit_test.cu @@ -163,7 +163,7 @@ TEST(ErrorTest, TestError) auto result = cuopt::linear_programming::solve_mip(&handle, problem, settings); EXPECT_EQ(result.get_termination_status(), - cuopt::linear_programming::mip_termination_status_t::NoTermination); + cuopt::linear_programming::mip_termination_status_t::Infeasible); } class MILPTestParams From 159d740fad9acaaa0aeb89ed91872c9f3009ad1a Mon Sep 17 00:00:00 2001 From: Kumar Aatish Date: Mon, 9 Jun 2025 10:02:43 -0400 Subject: [PATCH 3/4] throw validation error --- cpp/src/mip/problem/problem.cu | 197 ++++++++++++++++++++------------- cpp/tests/mip/unit_test.cu | 2 +- 2 files changed, 119 insertions(+), 80 deletions(-) diff --git a/cpp/src/mip/problem/problem.cu b/cpp/src/mip/problem/problem.cu index 1ba681d132..c0008d7580 100644 --- a/cpp/src/mip/problem/problem.cu +++ b/cpp/src/mip/problem/problem.cu @@ -320,21 +320,31 @@ void problem_t::check_problem_representation(bool check_transposed, // Presolve reductions might trivially solve the problem to optimality/infeasibility. // In this case, it is exptected that the problem fields are empty. - cuopt_assert(!offsets.is_empty(), "A_offsets must never be empty."); + cuopt_expects( + !offsets.is_empty(), error_type_t::ValidationError, "A_offsets must never be empty."); if (check_transposed) { - cuopt_assert(!reverse_offsets.is_empty(), "A_offsets must never be empty."); + cuopt_expects( + !reverse_offsets.is_empty(), error_type_t::ValidationError, "A_offsets must never be empty."); } if (!empty) { // Check for empty fields - cuopt_assert(!coefficients.is_empty(), "A_values must be set before calling the solver."); - cuopt_assert(!variables.is_empty(), "A_indices must be set before calling the solver."); + cuopt_expects(!coefficients.is_empty(), + error_type_t::ValidationError, + "A_values must be set before calling the solver."); + cuopt_expects(!variables.is_empty(), + error_type_t::ValidationError, + "A_indices must be set before calling the solver."); if (check_transposed) { - cuopt_assert(!reverse_coefficients.is_empty(), - "A_values must be set before calling the solver."); - cuopt_assert(!reverse_constraints.is_empty(), - "A_indices must be set before calling the solver."); + cuopt_expects(!reverse_coefficients.is_empty(), + error_type_t::ValidationError, + "A_values must be set before calling the solver."); + cuopt_expects(!reverse_constraints.is_empty(), + error_type_t::ValidationError, + "A_indices must be set before calling the solver."); } - cuopt_assert(!objective_coefficients.is_empty(), "c must be set before calling the solver."); + cuopt_expects(!objective_coefficients.is_empty(), + error_type_t::ValidationError, + "c must be set before calling the solver."); } // Check CSR validity @@ -348,47 +358,58 @@ void problem_t::check_problem_representation(bool check_transposed, handle_ptr, n_constraints, n_variables); - cuopt_assert(check_transpose_validity(this->coefficients, - this->offsets, - this->variables, - this->reverse_coefficients, - this->reverse_offsets, - this->reverse_constraints, - handle_ptr), - "Tranpose invalide"); + cuopt_expects(check_transpose_validity(this->coefficients, + this->offsets, + this->variables, + this->reverse_coefficients, + this->reverse_offsets, + this->reverse_constraints, + handle_ptr), + error_type_t::ValidationError, + "Tranpose invalide"); } // Check variable bounds are set and with the correct size if (!empty) { - cuopt_assert(!variable_lower_bounds.is_empty() && !variable_upper_bounds.is_empty(), - "Variable lower bounds and variable upper bounds must be set."); + cuopt_expects(!variable_lower_bounds.is_empty() && !variable_upper_bounds.is_empty(), + error_type_t::ValidationError, + "Variable lower bounds and variable upper bounds must be set."); } - cuopt_assert(variable_lower_bounds.size() == objective_coefficients.size(), - "Sizes for vectors related to the variables are not the same."); - cuopt_assert(variable_upper_bounds.size() == objective_coefficients.size(), - "Sizes for vectors related to the variables are not the same"); - cuopt_assert(variable_upper_bounds.size() == (std::size_t)n_variables, - "Sizes for vectors related to the variables are not the same."); - cuopt_assert(variable_types.size() == (std::size_t)n_variables, - "Sizes for vectors related to the variables are not the same."); + cuopt_expects(variable_lower_bounds.size() == objective_coefficients.size(), + error_type_t::ValidationError, + "Sizes for vectors related to the variables are not the same."); + cuopt_expects(variable_upper_bounds.size() == objective_coefficients.size(), + error_type_t::ValidationError, + "Sizes for vectors related to the variables are not the same"); + cuopt_expects(variable_upper_bounds.size() == (std::size_t)n_variables, + error_type_t::ValidationError, + "Sizes for vectors related to the variables are not the same."); + cuopt_expects(variable_types.size() == (std::size_t)n_variables, + error_type_t::ValidationError, + "Sizes for vectors related to the variables are not the same."); // Check constraints bounds sizes if (!empty) { - cuopt_assert(!constraint_lower_bounds.is_empty() && !constraint_upper_bounds.is_empty(), - "Constraints lower bounds and constraints upper bounds must be set."); + cuopt_expects(!constraint_lower_bounds.is_empty() && !constraint_upper_bounds.is_empty(), + error_type_t::ValidationError, + "Constraints lower bounds and constraints upper bounds must be set."); } - cuopt_assert(constraint_lower_bounds.size() == constraint_upper_bounds.size(), - "Sizes for vectors related to the constraints are not the same."); - cuopt_assert(constraint_lower_bounds.size() == (size_t)n_constraints, - "Sizes for vectors related to the constraints are not the same."); - cuopt_assert((offsets.size() - 1) == constraint_lower_bounds.size(), - "Sizes for vectors related to the constraints are not the same."); + cuopt_expects(constraint_lower_bounds.size() == constraint_upper_bounds.size(), + error_type_t::ValidationError, + "Sizes for vectors related to the constraints are not the same."); + cuopt_expects(constraint_lower_bounds.size() == (size_t)n_constraints, + error_type_t::ValidationError, + "Sizes for vectors related to the constraints are not the same."); + cuopt_expects((offsets.size() - 1) == constraint_lower_bounds.size(), + error_type_t::ValidationError, + "Sizes for vectors related to the constraints are not the same."); // Check combined bounds - cuopt_assert(combined_bounds.size() == (size_t)n_constraints, - "Sizes for vectors related to the constraints are not the same."); + cuopt_expects(combined_bounds.size() == (size_t)n_constraints, + error_type_t::ValidationError, + "Sizes for vectors related to the constraints are not the same."); // Check the validity of bounds - cuopt_assert( + cuopt_expects( thrust::all_of(handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), thrust::make_counting_iterator(n_variables), @@ -396,8 +417,9 @@ void problem_t::check_problem_representation(bool check_transposed, variable_upper_bounds = variable_upper_bounds.data()] __device__(i_t idx) { return variable_lower_bounds[idx] <= variable_upper_bounds[idx]; }), + error_type_t::ValidationError, "Variable bounds are invalid"); - cuopt_assert( + cuopt_expects( thrust::all_of(handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), thrust::make_counting_iterator(n_constraints), @@ -405,45 +427,57 @@ void problem_t::check_problem_representation(bool check_transposed, constraint_upper_bounds = constraint_upper_bounds.data()] __device__(i_t idx) { return constraint_lower_bounds[idx] <= constraint_upper_bounds[idx]; }), + error_type_t::ValidationError, "Constraints bounds are invalid"); if (check_mip_related_data) { - cuopt_assert(n_integer_vars == integer_indices.size(), "incorrect integer indices structure"); - cuopt_assert(is_binary_variable.size() == n_variables, "incorrect binary variable table size"); - - cuopt_assert(thrust::is_sorted( - handle_ptr->get_thrust_policy(), binary_indices.begin(), binary_indices.end()), - "binary indices are not sorted"); - cuopt_assert( + cuopt_expects(static_cast(n_integer_vars) == integer_indices.size(), + error_type_t::ValidationError, + "incorrect integer indices structure"); + cuopt_expects(is_binary_variable.size() == static_cast(n_variables), + error_type_t::ValidationError, + "incorrect binary variable table size"); + + cuopt_expects(thrust::is_sorted( + handle_ptr->get_thrust_policy(), binary_indices.begin(), binary_indices.end()), + error_type_t::ValidationError, + "binary indices are not sorted"); + cuopt_expects( thrust::is_sorted( handle_ptr->get_thrust_policy(), nonbinary_indices.begin(), nonbinary_indices.end()), + error_type_t::ValidationError, "nonbinary indices are not sorted"); - cuopt_assert(thrust::is_sorted( - handle_ptr->get_thrust_policy(), integer_indices.begin(), integer_indices.end()), - "integer indices are not sorted"); + cuopt_expects( + thrust::is_sorted( + handle_ptr->get_thrust_policy(), integer_indices.begin(), integer_indices.end()), + error_type_t::ValidationError, + "integer indices are not sorted"); // check precomputed helpers - cuopt_assert(thrust::all_of(handle_ptr->get_thrust_policy(), - integer_indices.cbegin(), - integer_indices.cend(), - [types = variable_types.data()] __device__(i_t idx) { - return types[idx] == var_t::INTEGER; - }), - "The integer indices table contains references to non-integer variables."); - cuopt_assert(thrust::all_of(handle_ptr->get_thrust_policy(), - binary_indices.cbegin(), - binary_indices.cend(), - [bin_table = is_binary_variable.data()] __device__(i_t idx) { - return bin_table[idx]; - }), - "The binary indices table contains references to non-binary variables."); - cuopt_assert(thrust::all_of(handle_ptr->get_thrust_policy(), - nonbinary_indices.cbegin(), - nonbinary_indices.cend(), - [bin_table = is_binary_variable.data()] __device__(i_t idx) { - return !bin_table[idx]; - }), - "The non-binary indices table contains references to binary variables."); - cuopt_assert( + cuopt_expects(thrust::all_of(handle_ptr->get_thrust_policy(), + integer_indices.cbegin(), + integer_indices.cend(), + [types = variable_types.data()] __device__(i_t idx) { + return types[idx] == var_t::INTEGER; + }), + error_type_t::ValidationError, + "The integer indices table contains references to non-integer variables."); + cuopt_expects(thrust::all_of(handle_ptr->get_thrust_policy(), + binary_indices.cbegin(), + binary_indices.cend(), + [bin_table = is_binary_variable.data()] __device__(i_t idx) { + return bin_table[idx]; + }), + error_type_t::ValidationError, + "The binary indices table contains references to non-binary variables."); + cuopt_expects(thrust::all_of(handle_ptr->get_thrust_policy(), + nonbinary_indices.cbegin(), + nonbinary_indices.cend(), + [bin_table = is_binary_variable.data()] __device__(i_t idx) { + return !bin_table[idx]; + }), + error_type_t::ValidationError, + "The non-binary indices table contains references to binary variables."); + cuopt_expects( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), @@ -475,8 +509,9 @@ void problem_t::check_problem_representation(bool check_transposed, } return true; }), + error_type_t::ValidationError, "Some variables aren't referenced in the appropriate indice tables"); - cuopt_assert( + cuopt_expects( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), @@ -508,8 +543,9 @@ void problem_t::check_problem_representation(bool check_transposed, } return true; }), + error_type_t::ValidationError, "Some variables aren't referenced in the appropriate indice tables"); - cuopt_assert( + cuopt_expects( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), @@ -541,8 +577,9 @@ void problem_t::check_problem_representation(bool check_transposed, } return true; }), + error_type_t::ValidationError, "Some variables aren't referenced in the appropriate indice tables"); - cuopt_assert( + cuopt_expects( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_zip_iterator(thrust::make_counting_iterator(0), @@ -558,13 +595,15 @@ void problem_t::check_problem_representation(bool check_transposed, return pred == (types[idx] != var_t::CONTINUOUS && v.integer_equal(lb[idx], 0.) && v.integer_equal(ub[idx], 1.)); }), + error_type_t::ValidationError, "The binary variable table is incorrect."); if (!empty) { - cuopt_assert(is_binary_pb == (n_variables == thrust::count(handle_ptr->get_thrust_policy(), - is_binary_variable.begin(), - is_binary_variable.end(), - 1)), - "is_binary_pb is incorrectly set"); + cuopt_expects(is_binary_pb == (n_variables == thrust::count(handle_ptr->get_thrust_policy(), + is_binary_variable.begin(), + is_binary_variable.end(), + 1)), + error_type_t::ValidationError, + "is_binary_pb is incorrectly set"); } } } diff --git a/cpp/tests/mip/unit_test.cu b/cpp/tests/mip/unit_test.cu index 2b06c8abbc..54a274b437 100644 --- a/cpp/tests/mip/unit_test.cu +++ b/cpp/tests/mip/unit_test.cu @@ -163,7 +163,7 @@ TEST(ErrorTest, TestError) auto result = cuopt::linear_programming::solve_mip(&handle, problem, settings); EXPECT_EQ(result.get_termination_status(), - cuopt::linear_programming::mip_termination_status_t::Infeasible); + cuopt::linear_programming::mip_termination_status_t::NoTermination); } class MILPTestParams From 59110cc133e4fc2a9f48f3ae8e05ede8dfc74786 Mon Sep 17 00:00:00 2001 From: Kumar Aatish Date: Mon, 9 Jun 2025 10:53:51 -0400 Subject: [PATCH 4/4] revert some validation errors --- cpp/src/mip/problem/problem.cu | 191 +++++++++++++-------------------- 1 file changed, 77 insertions(+), 114 deletions(-) diff --git a/cpp/src/mip/problem/problem.cu b/cpp/src/mip/problem/problem.cu index c0008d7580..5b8511b924 100644 --- a/cpp/src/mip/problem/problem.cu +++ b/cpp/src/mip/problem/problem.cu @@ -320,31 +320,21 @@ void problem_t::check_problem_representation(bool check_transposed, // Presolve reductions might trivially solve the problem to optimality/infeasibility. // In this case, it is exptected that the problem fields are empty. - cuopt_expects( - !offsets.is_empty(), error_type_t::ValidationError, "A_offsets must never be empty."); + cuopt_assert(!offsets.is_empty(), "A_offsets must never be empty."); if (check_transposed) { - cuopt_expects( - !reverse_offsets.is_empty(), error_type_t::ValidationError, "A_offsets must never be empty."); + cuopt_assert(!reverse_offsets.is_empty(), "A_offsets must never be empty."); } if (!empty) { // Check for empty fields - cuopt_expects(!coefficients.is_empty(), - error_type_t::ValidationError, - "A_values must be set before calling the solver."); - cuopt_expects(!variables.is_empty(), - error_type_t::ValidationError, - "A_indices must be set before calling the solver."); + cuopt_assert(!coefficients.is_empty(), "A_values must be set before calling the solver."); + cuopt_assert(!variables.is_empty(), "A_indices must be set before calling the solver."); if (check_transposed) { - cuopt_expects(!reverse_coefficients.is_empty(), - error_type_t::ValidationError, - "A_values must be set before calling the solver."); - cuopt_expects(!reverse_constraints.is_empty(), - error_type_t::ValidationError, - "A_indices must be set before calling the solver."); + cuopt_assert(!reverse_coefficients.is_empty(), + "A_values must be set before calling the solver."); + cuopt_assert(!reverse_constraints.is_empty(), + "A_indices must be set before calling the solver."); } - cuopt_expects(!objective_coefficients.is_empty(), - error_type_t::ValidationError, - "c must be set before calling the solver."); + cuopt_assert(!objective_coefficients.is_empty(), "c must be set before calling the solver."); } // Check CSR validity @@ -358,55 +348,44 @@ void problem_t::check_problem_representation(bool check_transposed, handle_ptr, n_constraints, n_variables); - cuopt_expects(check_transpose_validity(this->coefficients, - this->offsets, - this->variables, - this->reverse_coefficients, - this->reverse_offsets, - this->reverse_constraints, - handle_ptr), - error_type_t::ValidationError, - "Tranpose invalide"); + cuopt_assert(check_transpose_validity(this->coefficients, + this->offsets, + this->variables, + this->reverse_coefficients, + this->reverse_offsets, + this->reverse_constraints, + handle_ptr), + "Tranpose invalide"); } // Check variable bounds are set and with the correct size if (!empty) { - cuopt_expects(!variable_lower_bounds.is_empty() && !variable_upper_bounds.is_empty(), - error_type_t::ValidationError, - "Variable lower bounds and variable upper bounds must be set."); + cuopt_assert(!variable_lower_bounds.is_empty() && !variable_upper_bounds.is_empty(), + "Variable lower bounds and variable upper bounds must be set."); } - cuopt_expects(variable_lower_bounds.size() == objective_coefficients.size(), - error_type_t::ValidationError, - "Sizes for vectors related to the variables are not the same."); - cuopt_expects(variable_upper_bounds.size() == objective_coefficients.size(), - error_type_t::ValidationError, - "Sizes for vectors related to the variables are not the same"); - cuopt_expects(variable_upper_bounds.size() == (std::size_t)n_variables, - error_type_t::ValidationError, - "Sizes for vectors related to the variables are not the same."); - cuopt_expects(variable_types.size() == (std::size_t)n_variables, - error_type_t::ValidationError, - "Sizes for vectors related to the variables are not the same."); + cuopt_assert(variable_lower_bounds.size() == objective_coefficients.size(), + "Sizes for vectors related to the variables are not the same."); + cuopt_assert(variable_upper_bounds.size() == objective_coefficients.size(), + "Sizes for vectors related to the variables are not the same"); + cuopt_assert(variable_upper_bounds.size() == (std::size_t)n_variables, + "Sizes for vectors related to the variables are not the same."); + cuopt_assert(variable_types.size() == (std::size_t)n_variables, + "Sizes for vectors related to the variables are not the same."); // Check constraints bounds sizes if (!empty) { - cuopt_expects(!constraint_lower_bounds.is_empty() && !constraint_upper_bounds.is_empty(), - error_type_t::ValidationError, - "Constraints lower bounds and constraints upper bounds must be set."); + cuopt_assert(!constraint_lower_bounds.is_empty() && !constraint_upper_bounds.is_empty(), + "Constraints lower bounds and constraints upper bounds must be set."); } - cuopt_expects(constraint_lower_bounds.size() == constraint_upper_bounds.size(), - error_type_t::ValidationError, - "Sizes for vectors related to the constraints are not the same."); - cuopt_expects(constraint_lower_bounds.size() == (size_t)n_constraints, - error_type_t::ValidationError, - "Sizes for vectors related to the constraints are not the same."); - cuopt_expects((offsets.size() - 1) == constraint_lower_bounds.size(), - error_type_t::ValidationError, - "Sizes for vectors related to the constraints are not the same."); + cuopt_assert(constraint_lower_bounds.size() == constraint_upper_bounds.size(), + "Sizes for vectors related to the constraints are not the same."); + cuopt_assert(constraint_lower_bounds.size() == (size_t)n_constraints, + "Sizes for vectors related to the constraints are not the same."); + cuopt_assert((offsets.size() - 1) == constraint_lower_bounds.size(), + "Sizes for vectors related to the constraints are not the same."); // Check combined bounds - cuopt_expects(combined_bounds.size() == (size_t)n_constraints, - error_type_t::ValidationError, - "Sizes for vectors related to the constraints are not the same."); + cuopt_assert(combined_bounds.size() == (size_t)n_constraints, + "Sizes for vectors related to the constraints are not the same."); // Check the validity of bounds cuopt_expects( @@ -431,53 +410,42 @@ void problem_t::check_problem_representation(bool check_transposed, "Constraints bounds are invalid"); if (check_mip_related_data) { - cuopt_expects(static_cast(n_integer_vars) == integer_indices.size(), - error_type_t::ValidationError, - "incorrect integer indices structure"); - cuopt_expects(is_binary_variable.size() == static_cast(n_variables), - error_type_t::ValidationError, - "incorrect binary variable table size"); - - cuopt_expects(thrust::is_sorted( - handle_ptr->get_thrust_policy(), binary_indices.begin(), binary_indices.end()), - error_type_t::ValidationError, - "binary indices are not sorted"); - cuopt_expects( + cuopt_assert(n_integer_vars == integer_indices.size(), "incorrect integer indices structure"); + cuopt_assert(is_binary_variable.size() == n_variables, "incorrect binary variable table size"); + + cuopt_assert(thrust::is_sorted( + handle_ptr->get_thrust_policy(), binary_indices.begin(), binary_indices.end()), + "binary indices are not sorted"); + cuopt_assert( thrust::is_sorted( handle_ptr->get_thrust_policy(), nonbinary_indices.begin(), nonbinary_indices.end()), - error_type_t::ValidationError, "nonbinary indices are not sorted"); - cuopt_expects( - thrust::is_sorted( - handle_ptr->get_thrust_policy(), integer_indices.begin(), integer_indices.end()), - error_type_t::ValidationError, - "integer indices are not sorted"); + cuopt_assert(thrust::is_sorted( + handle_ptr->get_thrust_policy(), integer_indices.begin(), integer_indices.end()), + "integer indices are not sorted"); // check precomputed helpers - cuopt_expects(thrust::all_of(handle_ptr->get_thrust_policy(), - integer_indices.cbegin(), - integer_indices.cend(), - [types = variable_types.data()] __device__(i_t idx) { - return types[idx] == var_t::INTEGER; - }), - error_type_t::ValidationError, - "The integer indices table contains references to non-integer variables."); - cuopt_expects(thrust::all_of(handle_ptr->get_thrust_policy(), - binary_indices.cbegin(), - binary_indices.cend(), - [bin_table = is_binary_variable.data()] __device__(i_t idx) { - return bin_table[idx]; - }), - error_type_t::ValidationError, - "The binary indices table contains references to non-binary variables."); - cuopt_expects(thrust::all_of(handle_ptr->get_thrust_policy(), - nonbinary_indices.cbegin(), - nonbinary_indices.cend(), - [bin_table = is_binary_variable.data()] __device__(i_t idx) { - return !bin_table[idx]; - }), - error_type_t::ValidationError, - "The non-binary indices table contains references to binary variables."); - cuopt_expects( + cuopt_assert(thrust::all_of(handle_ptr->get_thrust_policy(), + integer_indices.cbegin(), + integer_indices.cend(), + [types = variable_types.data()] __device__(i_t idx) { + return types[idx] == var_t::INTEGER; + }), + "The integer indices table contains references to non-integer variables."); + cuopt_assert(thrust::all_of(handle_ptr->get_thrust_policy(), + binary_indices.cbegin(), + binary_indices.cend(), + [bin_table = is_binary_variable.data()] __device__(i_t idx) { + return bin_table[idx]; + }), + "The binary indices table contains references to non-binary variables."); + cuopt_assert(thrust::all_of(handle_ptr->get_thrust_policy(), + nonbinary_indices.cbegin(), + nonbinary_indices.cend(), + [bin_table = is_binary_variable.data()] __device__(i_t idx) { + return !bin_table[idx]; + }), + "The non-binary indices table contains references to binary variables."); + cuopt_assert( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), @@ -509,9 +477,8 @@ void problem_t::check_problem_representation(bool check_transposed, } return true; }), - error_type_t::ValidationError, "Some variables aren't referenced in the appropriate indice tables"); - cuopt_expects( + cuopt_assert( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), @@ -543,9 +510,8 @@ void problem_t::check_problem_representation(bool check_transposed, } return true; }), - error_type_t::ValidationError, "Some variables aren't referenced in the appropriate indice tables"); - cuopt_expects( + cuopt_assert( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_counting_iterator(0), @@ -577,9 +543,8 @@ void problem_t::check_problem_representation(bool check_transposed, } return true; }), - error_type_t::ValidationError, "Some variables aren't referenced in the appropriate indice tables"); - cuopt_expects( + cuopt_assert( thrust::all_of( handle_ptr->get_thrust_policy(), thrust::make_zip_iterator(thrust::make_counting_iterator(0), @@ -595,15 +560,13 @@ void problem_t::check_problem_representation(bool check_transposed, return pred == (types[idx] != var_t::CONTINUOUS && v.integer_equal(lb[idx], 0.) && v.integer_equal(ub[idx], 1.)); }), - error_type_t::ValidationError, "The binary variable table is incorrect."); if (!empty) { - cuopt_expects(is_binary_pb == (n_variables == thrust::count(handle_ptr->get_thrust_policy(), - is_binary_variable.begin(), - is_binary_variable.end(), - 1)), - error_type_t::ValidationError, - "is_binary_pb is incorrectly set"); + cuopt_assert(is_binary_pb == (n_variables == thrust::count(handle_ptr->get_thrust_policy(), + is_binary_variable.begin(), + is_binary_variable.end(), + 1)), + "is_binary_pb is incorrectly set"); } } }