1717
1818#include < utilities/scope_guard.hpp>
1919
20+ #include < array>
21+
2022constexpr bool fj_only_run = false ;
2123
2224namespace cuopt ::linear_programming::detail {
@@ -33,11 +35,123 @@ size_t sub_mip_recombiner_config_t::max_n_of_vars_from_other =
3335template <typename i_t , typename f_t >
3436std::vector<recombiner_enum_t > recombiner_t <i_t , f_t >::enabled_recombiners;
3537
38+ namespace {
39+ const char * mip_scaling_call_order_to_string (mip_scaling_call_order_t call_order)
40+ {
41+ switch (call_order) {
42+ case mip_scaling_call_order_t ::BEFORE_BOUNDS_UPDATE : return " before_bounds_update" ;
43+ case mip_scaling_call_order_t ::AFTER_TRIVIAL_PRESOLVE : return " after_trivial_presolve" ;
44+ }
45+ return " unknown" ;
46+ }
47+ } // namespace
48+
49+ template <typename i_t , typename f_t >
50+ std::vector<mip_scaling_benchmark_config_t <f_t >>
51+ diversity_manager_t <i_t , f_t >::get_mip_scaling_config_matrix()
52+ {
53+ std::vector<mip_scaling_benchmark_config_t <f_t >> configs;
54+ configs.reserve (16 );
55+
56+ const std::array<mip_scaling_call_order_t , 2 > call_orders = {
57+ mip_scaling_call_order_t ::BEFORE_BOUNDS_UPDATE ,
58+ mip_scaling_call_order_t ::AFTER_TRIVIAL_PRESOLVE };
59+ const std::array<int , 2 > iteration_counts = {1 , 3 };
60+
61+ for (auto call_order : call_orders) {
62+ for (auto iteration_count : iteration_counts) {
63+ for (bool use_big_m_skip_rows : {false , true }) {
64+ for (bool use_power_of_two_scaling : {true , false }) {
65+ mip_scaling_benchmark_config_t <f_t > config{};
66+ config.call_order = call_order;
67+ config.row_scaling_num_iterations = iteration_count;
68+ config.row_scaling_k_min = -20 ;
69+ config.row_scaling_k_max = 20 ;
70+ config.use_big_m_skip_rows = use_big_m_skip_rows;
71+ config.use_power_of_two_scaling = use_power_of_two_scaling;
72+ config.minimum_scaled_magnitude = static_cast <f_t >(1.0e-5 );
73+ configs.push_back (config);
74+ }
75+ }
76+ }
77+ }
78+ return configs;
79+ }
80+
81+ template <typename i_t , typename f_t >
82+ void diversity_manager_t <i_t , f_t >::configure_mip_scaling_from_config_id()
83+ {
84+ auto configs = get_mip_scaling_config_matrix ();
85+ if (configs.empty ()) { return ; }
86+
87+ int max_config = static_cast <int >(configs.size ());
88+ const char * env_max_config = std::getenv (" CUOPT_MAX_CONFIG" );
89+ if (env_max_config != nullptr ) {
90+ try {
91+ const int parsed_max_config = std::stoi (env_max_config);
92+ if (parsed_max_config > 0 ) {
93+ max_config = std::min (parsed_max_config, max_config);
94+ } else {
95+ CUOPT_LOG_WARN (" CUOPT_MAX_CONFIG must be > 0. Falling back to default matrix size." );
96+ }
97+ } catch (const std::exception& e) {
98+ CUOPT_LOG_WARN (" Failed to parse CUOPT_MAX_CONFIG environment variable: %s" , e.what ());
99+ }
100+ }
101+
102+ int config_id = 0 ;
103+ const char * env_config_id = std::getenv (" CUOPT_CONFIG_ID" );
104+ if (env_config_id != nullptr ) {
105+ try {
106+ config_id = std::stoi (env_config_id);
107+ } catch (const std::exception& e) {
108+ CUOPT_LOG_WARN (" Failed to parse CUOPT_CONFIG_ID environment variable: %s" , e.what ());
109+ config_id = 0 ;
110+ }
111+ }
112+
113+ const int selected_config_id =
114+ ((config_id % max_config) + max_config) % max_config; // keep it in [0, max_config)
115+ if (selected_config_id != config_id) {
116+ CUOPT_LOG_WARN (" Config ID %d out of range [0, %d). Using wrapped config ID %d." ,
117+ config_id,
118+ max_config,
119+ selected_config_id);
120+ }
121+ mip_scaling_config = configs[selected_config_id];
122+ CUOPT_LOG_INFO (
123+ " MIP scaling config selected: id=%d/%d order=%s iters=%d k=[%d,%d] "
124+ " big_m=%d pow2=%d min_scaled_val=%e" ,
125+ selected_config_id,
126+ max_config,
127+ mip_scaling_call_order_to_string (mip_scaling_config.call_order ),
128+ mip_scaling_config.row_scaling_num_iterations ,
129+ mip_scaling_config.row_scaling_k_min ,
130+ mip_scaling_config.row_scaling_k_max ,
131+ mip_scaling_config.use_big_m_skip_rows ,
132+ mip_scaling_config.use_power_of_two_scaling ,
133+ static_cast <double >(mip_scaling_config.minimum_scaled_magnitude ));
134+ }
135+
136+ template <typename i_t , typename f_t >
137+ void diversity_manager_t <i_t , f_t >::apply_mip_scaling_config()
138+ {
139+ auto scaling_config = context.scaling .get_config ();
140+ scaling_config.row_scaling_num_iterations = mip_scaling_config.row_scaling_num_iterations ;
141+ scaling_config.row_scaling_k_min = mip_scaling_config.row_scaling_k_min ;
142+ scaling_config.row_scaling_k_max = mip_scaling_config.row_scaling_k_max ;
143+ scaling_config.use_big_m_skip_rows = mip_scaling_config.use_big_m_skip_rows ;
144+ scaling_config.use_power_of_two_scaling = mip_scaling_config.use_power_of_two_scaling ;
145+ scaling_config.minimum_scaled_magnitude = mip_scaling_config.minimum_scaled_magnitude ;
146+ context.scaling .set_config (scaling_config);
147+ }
148+
36149template <typename i_t , typename f_t >
37150diversity_manager_t <i_t , f_t >::diversity_manager_t (mip_solver_context_t <i_t , f_t >& context_)
38151 : context(context_),
39152 branch_and_bound_ptr (nullptr ),
40153 problem_ptr(context.problem_ptr),
154+ mip_scaling_config(),
41155 diversity_config(),
42156 population(" population" ,
43157 context,
@@ -75,30 +189,8 @@ diversity_manager_t<i_t, f_t>::diversity_manager_t(mip_solver_context_t<i_t, f_t
75189 mab_ls(mab_ls_config_t <i_t , f_t >::n_of_arms, cuopt::seed_generator::get_seed(), ls_alpha, "ls"),
76190 ls_hash_map(*context.problem_ptr)
77191{
78- // Read configuration ID from environment variable
79- int max_config = -1 ;
80- // Read max configuration value from environment variable
81- const char * env_max_config = std::getenv (" CUOPT_MAX_CONFIG" );
82- if (env_max_config != nullptr ) {
83- try {
84- max_config = std::stoi (env_max_config);
85- CUOPT_LOG_INFO (" Using maximum configuration value from environment: %d" , max_config);
86- } catch (const std::exception& e) {
87- CUOPT_LOG_WARN (" Failed to parse CUOPT_MAX_CONFIG environment variable: %s" , e.what ());
88- }
89- }
90- if (max_config > 1 ) {
91- [[maybe_unused]] int config_id = -1 ; // Default value
92- const char * env_config_id = std::getenv (" CUOPT_CONFIG_ID" );
93- if (env_config_id != nullptr ) {
94- try {
95- config_id = std::stoi (env_config_id);
96- CUOPT_LOG_INFO (" Using configuration ID from environment: %d" , config_id);
97- } catch (const std::exception& e) {
98- CUOPT_LOG_WARN (" Failed to parse CUOPT_CONFIG_ID environment variable: %s" , e.what ());
99- }
100- }
101- }
192+ configure_mip_scaling_from_config_id ();
193+ apply_mip_scaling_config ();
102194}
103195
104196// this function is to specialize the local search with config from diversity manager
@@ -177,7 +269,13 @@ bool diversity_manager_t<i_t, f_t>::run_presolve(f_t time_limit)
177269 raft::common::nvtx::range fun_scope (" run_presolve" );
178270 CUOPT_LOG_INFO (" Running presolve!" );
179271 timer_t presolve_timer (time_limit);
180- if (context.settings .mip_scaling ) { context.scaling .scale_problem (); }
272+ auto run_scaling_if = [this ](mip_scaling_call_order_t expected_order) {
273+ if (context.settings .mip_scaling && mip_scaling_config.call_order == expected_order) {
274+ context.scaling .scale_problem ();
275+ }
276+ };
277+
278+ run_scaling_if (mip_scaling_call_order_t ::BEFORE_BOUNDS_UPDATE );
181279 auto term_crit = ls.constraint_prop .bounds_update .solve (*problem_ptr);
182280 if (ls.constraint_prop .bounds_update .infeas_constraints_count > 0 ) {
183281 stats.presolve_time = timer.elapsed_time ();
@@ -217,6 +315,7 @@ bool diversity_manager_t<i_t, f_t>::run_presolve(f_t time_limit)
217315 if (!check_bounds_sanity (*problem_ptr)) { return false ; }
218316 }
219317 }
318+ run_scaling_if (mip_scaling_call_order_t ::AFTER_TRIVIAL_PRESOLVE );
220319 }
221320 stats.presolve_time = presolve_timer.elapsed_time ();
222321 lp_optimal_solution.resize (problem_ptr->n_variables , problem_ptr->handle_ptr ->get_stream ());
0 commit comments