From 97e338c1d8bcf7dff489e7c714c27350b5900d6e Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Wed, 21 May 2025 12:36:42 -0700 Subject: [PATCH 1/3] Fix bug in C API for bool parameters. Fix bug on irish-electricty Also log when we change settings. And don't print the log headers. --- cpp/cuopt_cli.cpp | 1 + cpp/src/linear_programming/cuopt_c.cpp | 20 ++++++++ cpp/src/linear_programming/solve.cu | 16 +++++-- cpp/src/math_optimization/solver_settings.cu | 49 +++++++++++++++++--- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/cpp/cuopt_cli.cpp b/cpp/cuopt_cli.cpp index a81804a70a..67eed31edb 100644 --- a/cpp/cuopt_cli.cpp +++ b/cpp/cuopt_cli.cpp @@ -86,6 +86,7 @@ int run_single_file(const std::string& file_path, { const raft::handle_t handle_{}; cuopt::linear_programming::solver_settings_t settings; + cuopt::default_logger().set_pattern("%v"); try { for (auto& [key, val] : settings_strings) { diff --git a/cpp/src/linear_programming/cuopt_c.cpp b/cpp/src/linear_programming/cuopt_c.cpp index eaa934ca50..db72cb4ff2 100644 --- a/cpp/src/linear_programming/cuopt_c.cpp +++ b/cpp/src/linear_programming/cuopt_c.cpp @@ -61,6 +61,7 @@ int8_t cuOptGetIntSize() { return sizeof(cuopt_int_t); } cuopt_int_t cuOptReadProblem(const char* filename, cuOptOptimizationProblem* problem_ptr) { + cuopt::default_logger().set_pattern("%v"); problem_and_stream_view_t* problem_and_stream = new problem_and_stream_view_t(); std::string filename_str(filename); bool input_mps_strict = false; @@ -100,6 +101,7 @@ cuopt_int_t cuOptCreateProblem(cuopt_int_t num_constraints, const char* variable_types, cuOptOptimizationProblem* problem_ptr) { + cuopt::default_logger().set_pattern("%v"); if (problem_ptr == nullptr || objective_coefficients == nullptr || constraint_matrix_row_offsets == nullptr || constraint_matrix_column_indices == nullptr || constraint_matrix_coefficent_values == nullptr || constraint_sense == nullptr || @@ -155,6 +157,7 @@ cuopt_int_t cuOptCreateRangedProblem(cuopt_int_t num_constraints, const char* variable_types, cuOptOptimizationProblem* problem_ptr) { + cuopt::default_logger().set_pattern("%v"); if (problem_ptr == nullptr || objective_coefficients == nullptr || constraint_matrix_row_offsets == nullptr || constraint_matrix_column_indices == nullptr || constraint_matrix_coefficent_values == nullptr || constraint_lower_bounds == nullptr || @@ -431,6 +434,7 @@ cuopt_int_t cuOptGetVariableTypes(cuOptOptimizationProblem problem, char* variab cuopt_int_t cuOptCreateSolverSettings(cuOptSolverSettings* settings_ptr) { + cuopt::default_logger().set_pattern("%v"); if (settings_ptr == nullptr) { return CUOPT_INVALID_ARGUMENT; } solver_settings_t* settings = new solver_settings_t(); @@ -492,6 +496,14 @@ cuopt_int_t cuOptSetIntegerParameter(cuOptSolverSettings settings, static_cast*>(settings); try { solver_settings->set_parameter(parameter_name, parameter_value); + } catch (const std::invalid_argument& e) { + // We could be trying to set a boolean parameter. Try that + try { + bool value = static_cast(parameter_value); + solver_settings->set_parameter(parameter_name, value); + } catch (const std::exception& e) { + return CUOPT_INVALID_ARGUMENT; + } } catch (const std::exception& e) { return CUOPT_INVALID_ARGUMENT; } @@ -509,6 +521,14 @@ cuopt_int_t cuOptGetIntegerParameter(cuOptSolverSettings settings, static_cast*>(settings); try { *parameter_value_ptr = solver_settings->get_parameter(parameter_name); + } catch (const std::invalid_argument& e) { + // We could be trying to get a boolean parameter. Try that + try { + *parameter_value_ptr = + static_cast(solver_settings->get_parameter(parameter_name)); + } catch (const std::exception& e) { + return CUOPT_INVALID_ARGUMENT; + } } catch (const std::exception& e) { return CUOPT_INVALID_ARGUMENT; } diff --git a/cpp/src/linear_programming/solve.cu b/cpp/src/linear_programming/solve.cu index 84cc4ce0c5..a6ffa6a413 100644 --- a/cpp/src/linear_programming/solve.cu +++ b/cpp/src/linear_programming/solve.cu @@ -257,6 +257,7 @@ optimization_problem_solution_t convert_dual_simplex_sol( info.solve_time = duration; info.number_of_steps_taken = solution.iterations; + pdlp_termination_status_t termination_status = to_termination_status(status); auto sol = optimization_problem_solution_t(final_primal_solution, final_dual_solution, final_reduced_cost, @@ -264,7 +265,13 @@ optimization_problem_solution_t convert_dual_simplex_sol( problem.var_names, problem.row_names, info, - to_termination_status(status)); + termination_status); + + if (termination_status != pdlp_termination_status_t::Optimal && + termination_status != pdlp_termination_status_t::TimeLimit && + termination_status != pdlp_termination_status_t::ConcurrentLimit) { + CUOPT_LOG_INFO("Dual simplex status %s", sol.get_termination_status_string().c_str()); + } problem.handle_ptr->sync_stream(); return sol; @@ -295,7 +302,9 @@ std::tuple, dual_simplex::lp_status_t, f_t CUOPT_LOG_INFO("Dual simplex finished in %.2f seconds", duration.count() / 1000.0); - if (settings.concurrent_halt != nullptr) { + if (settings.concurrent_halt != nullptr && (status == dual_simplex::lp_status_t::OPTIMAL || + status == dual_simplex::lp_status_t::UNBOUNDED || + status == dual_simplex::lp_status_t::INFEASIBLE)) { // We finished. Tell PDLP to stop if it is still running. settings.concurrent_halt->store(1, std::memory_order_release); } @@ -398,7 +407,8 @@ optimization_problem_solution_t run_pdlp(detail::problem_t& sol.copy_from(problem.handle_ptr, sol_crossover); CUOPT_LOG_INFO("Crossover status %s", sol.get_termination_status_string().c_str()); } - if (crossover_info == 0 && settings.concurrent_halt != nullptr) { + if (settings.concurrent_halt != nullptr && crossover_info == 0 && + sol.get_termination_status() == pdlp_termination_status_t::Optimal) { // We finished. Tell dual simplex to stop if it is still running. settings.concurrent_halt->store(1, std::memory_order_release); } diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index 0eef789bea..2666e7bd58 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -16,6 +16,7 @@ */ #include +#include #include namespace cuopt::linear_programming { @@ -119,7 +120,8 @@ template void solver_settings_t::set_parameter_from_string(const std::string& name, const std::string& value) { - bool found = false; + bool found = false; + bool output = false; for (auto& param : int_parameters) { if (param.param_name == name) { i_t value_int; @@ -129,6 +131,10 @@ void solver_settings_t::set_parameter_from_string(const std::string& n } *param.value_ptr = value_int; found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %d", name.c_str(), value_int); + output = true; + } } else { throw std::invalid_argument("Parameter " + name + " value " + value + " is not an integer"); } @@ -143,6 +149,10 @@ void solver_settings_t::set_parameter_from_string(const std::string& n } *param.value_ptr = value_float; found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %e", name.c_str(), value_float); + output = true; + } } else { throw std::invalid_argument("Parameter " + name + " value " + value + " is not a float"); } @@ -154,6 +164,10 @@ void solver_settings_t::set_parameter_from_string(const std::string& n if (string_to_bool(value, value_bool)) { *param.value_ptr = value_bool; found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %s", name.c_str(), value_bool ? "true" : "false"); + output = true; + } } else { throw std::invalid_argument("Parameter " + name + " value " + value + " must be true or false"); @@ -164,7 +178,11 @@ void solver_settings_t::set_parameter_from_string(const std::string& n for (auto& param : string_parameters) { if (param.param_name == name) { *param.value_ptr = value; - found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %s", name.c_str(), value.c_str()); + output = true; + } + found = true; } } if (!found) { throw std::invalid_argument("Parameter " + name + " not found"); } @@ -174,7 +192,8 @@ template template void solver_settings_t::set_parameter(const std::string& name, T value) { - bool found = false; + bool found = false; + bool output = false; if constexpr (std::is_same_v) { for (auto& param : int_parameters) { if (param.param_name == name) { @@ -182,7 +201,11 @@ void solver_settings_t::set_parameter(const std::string& name, T value throw std::invalid_argument("Parameter " + name + " out of range"); } *param.value_ptr = value; - found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %d", name.c_str(), value); + output = true; + } + found = true; } } } @@ -193,7 +216,11 @@ void solver_settings_t::set_parameter(const std::string& name, T value throw std::invalid_argument("Parameter " + name + " out of range"); } *param.value_ptr = value; - found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %e", name.c_str(), value); + output = true; + } + found = true; } } } @@ -201,7 +228,11 @@ void solver_settings_t::set_parameter(const std::string& name, T value for (auto& param : bool_parameters) { if (param.param_name == name) { *param.value_ptr = value; - found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %s", name.c_str(), value ? "true" : "false"); + output = true; + } + found = true; } } } @@ -209,7 +240,11 @@ void solver_settings_t::set_parameter(const std::string& name, T value for (auto& param : string_parameters) { if (param.param_name == name) { *param.value_ptr = value; - found = true; + if (!output) { + CUOPT_LOG_INFO("Setting parameter %s to %s", name.c_str(), value.c_str()); + output = true; + } + found = true; } } } From d0bde3e7acd441e8fef97d5ce7fde50c52e98ae2 Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Wed, 21 May 2025 13:49:41 -0700 Subject: [PATCH 2/3] Set the log pattern in default_logger(). Fix docstring issue from Flora --- cpp/cuopt_cli.cpp | 1 - cpp/include/cuopt/logger.hpp | 4 ++++ cpp/src/linear_programming/cuopt_c.cpp | 4 ---- cpp/src/linear_programming/solve.cu | 3 --- cpp/src/mip/solve.cu | 3 --- python/cuopt/cuopt/linear_programming/solver/solver.py | 4 ++-- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/cpp/cuopt_cli.cpp b/cpp/cuopt_cli.cpp index 67eed31edb..a81804a70a 100644 --- a/cpp/cuopt_cli.cpp +++ b/cpp/cuopt_cli.cpp @@ -86,7 +86,6 @@ int run_single_file(const std::string& file_path, { const raft::handle_t handle_{}; cuopt::linear_programming::solver_settings_t settings; - cuopt::default_logger().set_pattern("%v"); try { for (auto& [key, val] : settings_strings) { diff --git a/cpp/include/cuopt/logger.hpp b/cpp/include/cuopt/logger.hpp index 0d1cc353cd..f455faf4ce 100644 --- a/cpp/include/cuopt/logger.hpp +++ b/cpp/include/cuopt/logger.hpp @@ -72,7 +72,11 @@ inline rapids_logger::logger& default_logger() { static rapids_logger::logger logger_ = [] { rapids_logger::logger logger_{"CUOPT", {default_sink()}}; +#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO + logger_.set_pattern("%v"); +#else logger_.set_pattern(default_pattern()); +#endif logger_.set_level(default_level()); logger_.flush_on(rapids_logger::level_enum::info); diff --git a/cpp/src/linear_programming/cuopt_c.cpp b/cpp/src/linear_programming/cuopt_c.cpp index db72cb4ff2..074566ba7b 100644 --- a/cpp/src/linear_programming/cuopt_c.cpp +++ b/cpp/src/linear_programming/cuopt_c.cpp @@ -61,7 +61,6 @@ int8_t cuOptGetIntSize() { return sizeof(cuopt_int_t); } cuopt_int_t cuOptReadProblem(const char* filename, cuOptOptimizationProblem* problem_ptr) { - cuopt::default_logger().set_pattern("%v"); problem_and_stream_view_t* problem_and_stream = new problem_and_stream_view_t(); std::string filename_str(filename); bool input_mps_strict = false; @@ -101,7 +100,6 @@ cuopt_int_t cuOptCreateProblem(cuopt_int_t num_constraints, const char* variable_types, cuOptOptimizationProblem* problem_ptr) { - cuopt::default_logger().set_pattern("%v"); if (problem_ptr == nullptr || objective_coefficients == nullptr || constraint_matrix_row_offsets == nullptr || constraint_matrix_column_indices == nullptr || constraint_matrix_coefficent_values == nullptr || constraint_sense == nullptr || @@ -157,7 +155,6 @@ cuopt_int_t cuOptCreateRangedProblem(cuopt_int_t num_constraints, const char* variable_types, cuOptOptimizationProblem* problem_ptr) { - cuopt::default_logger().set_pattern("%v"); if (problem_ptr == nullptr || objective_coefficients == nullptr || constraint_matrix_row_offsets == nullptr || constraint_matrix_column_indices == nullptr || constraint_matrix_coefficent_values == nullptr || constraint_lower_bounds == nullptr || @@ -434,7 +431,6 @@ cuopt_int_t cuOptGetVariableTypes(cuOptOptimizationProblem problem, char* variab cuopt_int_t cuOptCreateSolverSettings(cuOptSolverSettings* settings_ptr) { - cuopt::default_logger().set_pattern("%v"); if (settings_ptr == nullptr) { return CUOPT_INVALID_ARGUMENT; } solver_settings_t* settings = new solver_settings_t(); diff --git a/cpp/src/linear_programming/solve.cu b/cpp/src/linear_programming/solve.cu index a6ffa6a413..7677d28d15 100644 --- a/cpp/src/linear_programming/solve.cu +++ b/cpp/src/linear_programming/solve.cu @@ -521,9 +521,6 @@ optimization_problem_solution_t solve_lp(optimization_problem_t= RAPIDS_LOGGER_LOG_LEVEL_INFO - cuopt::default_logger().set_pattern("%v"); -#endif // Init libraies before to not include it in solve time // This needs to be called before pdlp is initialized diff --git a/cpp/src/mip/solve.cu b/cpp/src/mip/solve.cu index a2547ef277..d8fbd03e9c 100644 --- a/cpp/src/mip/solve.cu +++ b/cpp/src/mip/solve.cu @@ -159,9 +159,6 @@ mip_solution_t solve_mip(optimization_problem_t& op_problem, try { // Create log stream for file logging and add it to default logger init_logger_t log(settings.log_file, settings.log_to_console); -#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO - cuopt::default_logger().set_pattern("%v"); -#endif // Init libraies before to not include it in solve time // This needs to be called before pdlp is initialized init_handler(op_problem.get_handle_ptr()); diff --git a/python/cuopt/cuopt/linear_programming/solver/solver.py b/python/cuopt/cuopt/linear_programming/solver/solver.py index 94b4904f36..24812e70c9 100644 --- a/python/cuopt/cuopt/linear_programming/solver/solver.py +++ b/python/cuopt/cuopt/linear_programming/solver/solver.py @@ -54,7 +54,7 @@ def Solve(data_model, solver_settings=None, log_file=""): -------- >>> from cuopt import linear_programming >>> from cuopt.linear_programming.solver_settings import PDLPSolverMode - >>> from cuopt.linear_programming.solver_parameters import * + >>> from cuopt.linear_programming.solver.solver_parameters import * >>> >>> data_model = linear_programming.DataModel() >>> @@ -140,7 +140,7 @@ def BatchSolve(data_model_list, solver_settings=None, log_file=""): -------- >>> from cuopt import linear_programming >>> from cuopt.linear_programming.solver_settings import PDLPSolverMode - >>> from cuopt.linear_programming.solver_parameters import * + >>> from cuopt.linear_programming.solver.solver_parameters import * >>> import cuopt_mps_parser >>> >>> data_models = [] From 1c70bc020b26e785ba4bf5aa32c0744639ea91d5 Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Wed, 21 May 2025 15:05:34 -0700 Subject: [PATCH 3/3] Also change reset_default_logger() --- cpp/include/cuopt/logger.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/include/cuopt/logger.hpp b/cpp/include/cuopt/logger.hpp index f455faf4ce..5fb42b62d3 100644 --- a/cpp/include/cuopt/logger.hpp +++ b/cpp/include/cuopt/logger.hpp @@ -94,7 +94,11 @@ inline void reset_default_logger() { default_logger().sinks().clear(); default_logger().sinks().push_back(default_sink()); +#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO + default_logger().set_pattern("%v"); +#else default_logger().set_pattern(default_pattern()); +#endif default_logger().set_level(default_level()); default_logger().flush_on(rapids_logger::level_enum::info); }