-
Notifications
You must be signed in to change notification settings - Fork 0
Pre presolve heuristics - review test #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,95 @@ | ||||||
| /* clang-format off */ | ||||||
| /* | ||||||
| * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||||||
| * SPDX-License-Identifier: Apache-2.0 | ||||||
| */ | ||||||
| /* clang-format on */ | ||||||
|
|
||||||
| #pragma once | ||||||
|
|
||||||
| #include <mip_heuristics/problem/problem.cuh> | ||||||
| #include <mip_heuristics/solution/solution.cuh> | ||||||
|
|
||||||
| #include <cuopt/linear_programming/mip/solver_settings.hpp> | ||||||
|
|
||||||
| #include <utilities/logger.hpp> | ||||||
|
|
||||||
| #include <thrust/fill.h> | ||||||
|
|
||||||
| #include <chrono> | ||||||
| #include <functional> | ||||||
| #include <limits> | ||||||
| #include <vector> | ||||||
|
|
||||||
| namespace cuopt::linear_programming::detail { | ||||||
|
|
||||||
| template <typename f_t> | ||||||
| using early_incumbent_callback_t = | ||||||
| std::function<void(f_t objective, const std::vector<f_t>& assignment)>; | ||||||
|
|
||||||
| // CRTP base for early heuristics that run on the original (or papilo-presolved) problem | ||||||
| // during presolve to find incumbents as early as possible. | ||||||
| // Derived classes implement start() and stop(). | ||||||
| template <typename i_t, typename f_t, typename Derived> | ||||||
| class early_heuristic_t { | ||||||
| public: | ||||||
| early_heuristic_t(const optimization_problem_t<i_t, f_t>& op_problem, | ||||||
| const typename mip_solver_settings_t<i_t, f_t>::tolerances_t& tolerances, | ||||||
| early_incumbent_callback_t<f_t> incumbent_callback) | ||||||
| : incumbent_callback_(std::move(incumbent_callback)) | ||||||
| { | ||||||
| problem_ptr_ = std::make_unique<problem_t<i_t, f_t>>(op_problem, tolerances, false); | ||||||
| problem_ptr_->preprocess_problem(); | ||||||
|
|
||||||
| solution_ptr_ = std::make_unique<solution_t<i_t, f_t>>(*problem_ptr_); | ||||||
| thrust::fill(problem_ptr_->handle_ptr->get_thrust_policy(), | ||||||
| solution_ptr_->assignment.begin(), | ||||||
| solution_ptr_->assignment.end(), | ||||||
| f_t{0}); | ||||||
| solution_ptr_->clamp_within_bounds(); | ||||||
| } | ||||||
|
|
||||||
| bool solution_found() const { return solution_found_; } | ||||||
| f_t get_best_objective() const { return best_objective_; } | ||||||
| void set_best_objective(f_t obj) { best_objective_ = obj; } | ||||||
| const std::vector<f_t>& get_best_assignment() const { return best_assignment_; } | ||||||
|
|
||||||
| protected: | ||||||
| ~early_heuristic_t() = default; | ||||||
|
|
||||||
| // NOT thread-safe | ||||||
| void try_update_best(f_t user_obj, const std::vector<f_t>& assignment) | ||||||
| { | ||||||
| if (user_obj >= best_objective_) { return; } | ||||||
| best_objective_ = user_obj; | ||||||
|
|
||||||
| auto* handle_ptr = problem_ptr_->handle_ptr; | ||||||
| RAFT_CUDA_TRY(cudaSetDevice(handle_ptr->get_device())); | ||||||
| rmm::device_uvector<f_t> d_assignment(assignment.size(), handle_ptr->get_stream()); | ||||||
| raft::copy(d_assignment.data(), assignment.data(), assignment.size(), handle_ptr->get_stream()); | ||||||
| problem_ptr_->post_process_assignment(d_assignment); | ||||||
| auto user_assignment = cuopt::host_copy(d_assignment, handle_ptr->get_stream()); | ||||||
|
|
||||||
| best_assignment_ = user_assignment; | ||||||
| solution_found_ = true; | ||||||
| double elapsed = | ||||||
| std::chrono::duration<double>(std::chrono::steady_clock::now() - start_time_).count(); | ||||||
| CUOPT_LOG_INFO("Early heuristics (%s) lowered the primal bound. Objective %g. Time %.2f", | ||||||
| Derived::name(), | ||||||
| user_obj, | ||||||
| elapsed); | ||||||
| if (incumbent_callback_) { incumbent_callback_(user_obj, user_assignment); } | ||||||
| } | ||||||
|
|
||||||
| std::unique_ptr<problem_t<i_t, f_t>> problem_ptr_; | ||||||
| std::unique_ptr<solution_t<i_t, f_t>> solution_ptr_; | ||||||
|
|
||||||
| bool solution_found_{false}; | ||||||
| f_t best_objective_{std::numeric_limits<f_t>::infinity()}; | ||||||
| std::vector<f_t> best_assignment_; | ||||||
|
|
||||||
| early_incumbent_callback_t<f_t> incumbent_callback_; | ||||||
| std::chrono::steady_clock::time_point start_time_; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The member Consider initializing it to 🛠️ Proposed fix- std::chrono::steady_clock::time_point start_time_;
+ std::chrono::steady_clock::time_point start_time_{std::chrono::steady_clock::now()};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| }; | ||||||
|
|
||||||
| } // namespace cuopt::linear_programming::detail | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* clang-format off */ | ||
| /* | ||
| * SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| /* clang-format on */ | ||
|
|
||
| #include "early_cpufj.cuh" | ||
|
|
||
| #include <mip_heuristics/feasibility_jump/fj_cpu.cuh> | ||
| #include <mip_heuristics/mip_constants.hpp> | ||
| #include <utilities/logger.hpp> | ||
|
|
||
| namespace cuopt::linear_programming::detail { | ||
|
|
||
| template <typename i_t, typename f_t> | ||
| early_cpufj_t<i_t, f_t>::early_cpufj_t( | ||
| const optimization_problem_t<i_t, f_t>& op_problem, | ||
| const typename mip_solver_settings_t<i_t, f_t>::tolerances_t& tolerances, | ||
| early_incumbent_callback_t<f_t> incumbent_callback) | ||
| : early_heuristic_t<i_t, f_t, early_cpufj_t<i_t, f_t>>( | ||
| op_problem, tolerances, std::move(incumbent_callback)) | ||
| { | ||
| } | ||
|
|
||
| template <typename i_t, typename f_t> | ||
| early_cpufj_t<i_t, f_t>::~early_cpufj_t() | ||
| { | ||
| stop(); | ||
| } | ||
|
|
||
| template <typename i_t, typename f_t> | ||
| void early_cpufj_t<i_t, f_t>::start() | ||
| { | ||
| if (cpu_fj_thread_) { return; } | ||
|
|
||
| this->preemption_flag_.store(false); | ||
| this->start_time_ = std::chrono::steady_clock::now(); | ||
|
|
||
| cpu_fj_thread_ = std::make_unique<cpu_fj_thread_t<i_t, f_t>>(); | ||
| cpu_fj_thread_->fj_cpu = | ||
| init_fj_cpu_standalone(*this->problem_ptr_, *this->solution_ptr_, preemption_flag_); | ||
| cpu_fj_thread_->time_limit = std::numeric_limits<f_t>::infinity(); | ||
|
|
||
| cpu_fj_thread_->fj_cpu->log_prefix = "[Early CPUFJ] "; | ||
|
|
||
| cpu_fj_thread_->fj_cpu->improvement_callback = | ||
| [this](f_t solver_obj, const std::vector<f_t>& assignment, double) { | ||
| f_t user_obj = this->problem_ptr_->get_user_obj_from_solver_obj(solver_obj); | ||
| this->try_update_best(user_obj, assignment); | ||
| }; | ||
|
|
||
| cpu_fj_thread_->start_cpu_solver(); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| template <typename i_t, typename f_t> | ||
| void early_cpufj_t<i_t, f_t>::stop() | ||
| { | ||
| if (!cpu_fj_thread_) { return; } | ||
|
|
||
| preemption_flag_.store(true); | ||
| cpu_fj_thread_->stop_cpu_solver(); | ||
| cpu_fj_thread_->wait_for_cpu_solver(); | ||
|
|
||
| CUOPT_LOG_DEBUG("[Early CPUFJ] Stopped after %d iterations, solution_found=%d", | ||
| cpu_fj_thread_->fj_cpu ? cpu_fj_thread_->fj_cpu->iterations : 0, | ||
| this->solution_found_); | ||
|
|
||
| cpu_fj_thread_.reset(); | ||
| } | ||
|
|
||
| #if MIP_INSTANTIATE_FLOAT | ||
| template class early_cpufj_t<int, float>; | ||
| #endif | ||
|
|
||
| #if MIP_INSTANTIATE_DOUBLE | ||
| template class early_cpufj_t<int, double>; | ||
| #endif | ||
|
|
||
| } // namespace cuopt::linear_programming::detail | ||
Uh oh!
There was an error while loading. Please reload this page.