diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 799eb291f..447b03a32 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,6 +56,11 @@ repos: - repo: https://github.com/rapidsai/pre-commit-hooks rev: v1.2.1 hooks: + - id: verify-alpha-spec + args: + - --fix + - --mode + - release - id: verify-copyright args: [--fix, --spdx] files: | @@ -83,7 +88,5 @@ repos: entry: python ci/utils/update_doc_versions.py language: system files: docs/cuopt/source/versions1.json - - default_language_version: - python: python3 + python: python3 diff --git a/cpp/include/cuopt/linear_programming/pdlp/solver_settings.hpp b/cpp/include/cuopt/linear_programming/pdlp/solver_settings.hpp index ea697e1e1..76388504e 100644 --- a/cpp/include/cuopt/linear_programming/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/linear_programming/pdlp/solver_settings.hpp @@ -212,7 +212,7 @@ class pdlp_solver_settings_t { method_t method{method_t::Concurrent}; bool inside_mip{false}; // For concurrent termination - volatile int* concurrent_halt{nullptr}; + std::atomic* concurrent_halt{nullptr}; static constexpr f_t minimal_absolute_tolerance = 1.0e-12; private: diff --git a/cpp/src/dual_simplex/branch_and_bound.cpp b/cpp/src/dual_simplex/branch_and_bound.cpp index 77acca8f7..6161f4d3f 100644 --- a/cpp/src/dual_simplex/branch_and_bound.cpp +++ b/cpp/src/dual_simplex/branch_and_bound.cpp @@ -1135,6 +1135,7 @@ void branch_and_bound_t::diving_thread(const csr_matrix_t& A if (get_upper_bound() < start_node->node.lower_bound) { continue; } bool recompute_bounds_and_basis = true; + i_t nodes_explored = 0; search_tree_t subtree(std::move(start_node->node)); std::deque*> stack; stack.push_front(&subtree.root); @@ -1152,6 +1153,8 @@ void branch_and_bound_t::diving_thread(const csr_matrix_t& A if (toc(exploration_stats_.start_time) > settings_.time_limit) { return; } + if (nodes_explored >= 1000) { break; } + node_solve_info_t status = solve_node(node_ptr, subtree, leaf_problem, @@ -1165,6 +1168,8 @@ void branch_and_bound_t::diving_thread(const csr_matrix_t& A start_node->upper, log); + nodes_explored++; + recompute_bounds_and_basis = !has_children(status); if (status == node_solve_info_t::TIME_LIMIT) { diff --git a/cpp/src/dual_simplex/branch_and_bound.hpp b/cpp/src/dual_simplex/branch_and_bound.hpp index 7891711f7..38438cc9e 100644 --- a/cpp/src/dual_simplex/branch_and_bound.hpp +++ b/cpp/src/dual_simplex/branch_and_bound.hpp @@ -113,7 +113,7 @@ class branch_and_bound_t { f_t get_lower_bound(); i_t get_heap_size(); bool enable_concurrent_lp_root_solve() const { return enable_concurrent_lp_root_solve_; } - volatile int* get_root_concurrent_halt() { return &root_concurrent_halt_; } + std::atomic* get_root_concurrent_halt() { return &root_concurrent_halt_; } void set_root_concurrent_halt(int value) { root_concurrent_halt_ = value; } lp_status_t solve_root_relaxation(simplex_solver_settings_t const& lp_settings); @@ -170,7 +170,7 @@ class branch_and_bound_t { std::vector edge_norms_; std::atomic root_crossover_solution_set_{false}; bool enable_concurrent_lp_root_solve_{false}; - volatile int root_concurrent_halt_{0}; + std::atomic root_concurrent_halt_{0}; // Pseudocosts pseudo_costs_t pc_; diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index 98be9d4cb..a1cc049e7 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -145,8 +145,8 @@ struct simplex_solver_settings_t { std::function heuristic_preemption_callback; std::function&, std::vector&, f_t)> set_simplex_solution_callback; mutable logger_t log; - volatile int* concurrent_halt; // if nullptr ignored, if !nullptr, 0 if solver should - // continue, 1 if solver should halt + std::atomic* concurrent_halt; // if nullptr ignored, if !nullptr, 0 if solver should + // continue, 1 if solver should halt }; } // namespace cuopt::linear_programming::dual_simplex diff --git a/cpp/src/linear_programming/solve.cu b/cpp/src/linear_programming/solve.cu index ed141a0c4..ab418bf5a 100644 --- a/cpp/src/linear_programming/solve.cu +++ b/cpp/src/linear_programming/solve.cu @@ -306,7 +306,7 @@ void setup_device_symbols(rmm::cuda_stream_view stream_view) detail::set_pdlp_hyper_parameters(stream_view); } -volatile int global_concurrent_halt; +std::atomic global_concurrent_halt{0}; template optimization_problem_solution_t convert_dual_simplex_sol( diff --git a/cpp/src/mip/diversity/diversity_manager.cuh b/cpp/src/mip/diversity/diversity_manager.cuh index 4a78f6cff..9f3b4c90f 100644 --- a/cpp/src/mip/diversity/diversity_manager.cuh +++ b/cpp/src/mip/diversity/diversity_manager.cuh @@ -95,7 +95,7 @@ class diversity_manager_t { // mutex for the simplex solution update std::mutex relaxed_solution_mutex; // atomic for signalling pdlp to stop - volatile int global_concurrent_halt{0}; + std::atomic global_concurrent_halt{0}; rins_t rins; diff --git a/cpp/src/mip/relaxed_lp/relaxed_lp.cuh b/cpp/src/mip/relaxed_lp/relaxed_lp.cuh index 01931a3dd..0094f5982 100644 --- a/cpp/src/mip/relaxed_lp/relaxed_lp.cuh +++ b/cpp/src/mip/relaxed_lp/relaxed_lp.cuh @@ -17,14 +17,14 @@ namespace cuopt::linear_programming::detail { struct relaxed_lp_settings_t { - double tolerance = 1e-4; - double time_limit = 1.0; - bool check_infeasibility = true; - bool return_first_feasible = false; - bool save_state = true; - bool per_constraint_residual = true; - bool has_initial_primal = true; - volatile int* concurrent_halt = nullptr; + double tolerance = 1e-4; + double time_limit = 1.0; + bool check_infeasibility = true; + bool return_first_feasible = false; + bool save_state = true; + bool per_constraint_residual = true; + bool has_initial_primal = true; + std::atomic* concurrent_halt = nullptr; }; template diff --git a/cpp/src/utilities/logger.cpp b/cpp/src/utilities/logger.cpp index a16c49c11..217f9c64c 100644 --- a/cpp/src/utilities/logger.cpp +++ b/cpp/src/utilities/logger.cpp @@ -137,9 +137,26 @@ void reset_default_logger() default_logger().flush_on(rapids_logger::level_enum::debug); } +// Guard object whose destructor resets the logger +struct logger_config_guard { + ~logger_config_guard() { cuopt::reset_default_logger(); } +}; + +// Weak reference to detect if any init_logger_t instance is still alive +static std::weak_ptr g_active_guard; +static std::mutex g_guard_mutex; + init_logger_t::init_logger_t(std::string log_file, bool log_to_console) { - // until this function is called, the default sink is the buffer sink + std::lock_guard lock(g_guard_mutex); + + auto existing_guard = g_active_guard.lock(); + if (existing_guard) { + // Reuse existing configuration, just hold a reference to keep it alive + guard_ = existing_guard; + return; + } + cuopt::default_logger().sinks().clear(); // re-initialize sinks @@ -164,8 +181,11 @@ init_logger_t::init_logger_t(std::string log_file, bool log_to_console) for (const auto& entry : buffered_messages) { cuopt::default_logger().log(entry.level, entry.msg.c_str()); } -} -init_logger_t::~init_logger_t() { cuopt::reset_default_logger(); } + // Create guard and store weak reference for future instances to find + auto guard = std::make_shared(); + g_active_guard = guard; + guard_ = guard; +} } // namespace cuopt diff --git a/cpp/src/utilities/logger.hpp b/cpp/src/utilities/logger.hpp index 13c5e36e3..08556a4c7 100644 --- a/cpp/src/utilities/logger.hpp +++ b/cpp/src/utilities/logger.hpp @@ -33,11 +33,13 @@ rapids_logger::logger& default_logger(); */ void reset_default_logger(); +// Ref-counted logger initializer class init_logger_t { + // Using shared_ptr for ref-counting + std::shared_ptr guard_; + public: init_logger_t(std::string log_file, bool log_to_console); - - ~init_logger_t(); }; } // namespace cuopt diff --git a/python/cuopt/cuopt/linear_programming/pyproject.toml b/python/cuopt/cuopt/linear_programming/pyproject.toml index c11cd3a58..24907d83f 100644 --- a/python/cuopt/cuopt/linear_programming/pyproject.toml +++ b/python/cuopt/cuopt/linear_programming/pyproject.toml @@ -20,7 +20,7 @@ license = { text = "Apache-2.0" } requires-python = ">=3.10" dependencies = [ "numpy>=1.23.5,<3.0a0", - "rapids-logger==0.2.*,>=0.0.0a0", + "rapids-logger==0.2.*", ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../../../dependencies.yaml and run `rapids-dependency-file-generator`. classifiers = [ "Intended Audience :: Developers", @@ -39,7 +39,7 @@ Source = "https://github.com/nvidia/cuopt" test = [ "pytest-cov", "pytest<8", - "rapids-logger==0.2.*,>=0.0.0a0", + "rapids-logger==0.2.*", ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../../../dependencies.yaml and run `rapids-dependency-file-generator`. [tool.setuptools] @@ -83,5 +83,5 @@ requires = [ "cython>=3.0.3", "ninja", "numpy>=1.23.5,<3.0a0", - "rapids-logger==0.2.*,>=0.0.0a0", + "rapids-logger==0.2.*", ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../../../dependencies.yaml and run `rapids-dependency-file-generator`.