|
16 | 16 | */ |
17 | 17 |
|
18 | 18 | #include <cuopt/error.hpp> |
| 19 | +#include <cuopt/logger.hpp> |
19 | 20 | #include <mps_parser/writer.hpp> |
20 | 21 |
|
21 | 22 | #include <cuopt/linear_programming/optimization_problem.hpp> |
@@ -273,6 +274,20 @@ i_t optimization_problem_t<i_t, f_t>::get_nnz() const |
273 | 274 | return A_.size(); |
274 | 275 | } |
275 | 276 |
|
| 277 | +template <typename i_t, typename f_t> |
| 278 | +i_t optimization_problem_t<i_t, f_t>::get_n_integers() const |
| 279 | +{ |
| 280 | + i_t n_integers = 0; |
| 281 | + if (get_n_variables() != 0) { |
| 282 | + auto enum_variable_types = cuopt::host_copy(get_variable_types()); |
| 283 | + |
| 284 | + for (size_t i = 0; i < enum_variable_types.size(); ++i) { |
| 285 | + if (enum_variable_types[i] == var_t::INTEGER) { n_integers++; } |
| 286 | + } |
| 287 | + } |
| 288 | + return n_integers; |
| 289 | +} |
| 290 | + |
276 | 291 | template <typename i_t, typename f_t> |
277 | 292 | raft::handle_t const* optimization_problem_t<i_t, f_t>::get_handle_ptr() const noexcept |
278 | 293 | { |
@@ -583,6 +598,84 @@ void optimization_problem_t<i_t, f_t>::write_to_mps(const std::string& mps_file_ |
583 | 598 | cuopt::mps_parser::write_mps(data_model_view, mps_file_path); |
584 | 599 | } |
585 | 600 |
|
| 601 | +template <typename i_t, typename f_t> |
| 602 | +void optimization_problem_t<i_t, f_t>::print_scaling_information() const |
| 603 | +{ |
| 604 | + std::vector<f_t> constraint_matrix_values = cuopt::host_copy(get_constraint_matrix_values()); |
| 605 | + std::vector<f_t> constraint_rhs = cuopt::host_copy(get_constraint_bounds()); |
| 606 | + std::vector<f_t> objective_coefficients = cuopt::host_copy(get_objective_coefficients()); |
| 607 | + std::vector<f_t> variable_lower_bounds = cuopt::host_copy(get_variable_lower_bounds()); |
| 608 | + std::vector<f_t> variable_upper_bounds = cuopt::host_copy(get_variable_upper_bounds()); |
| 609 | + std::vector<f_t> constraint_lower_bounds = cuopt::host_copy(get_constraint_lower_bounds()); |
| 610 | + std::vector<f_t> constraint_upper_bounds = cuopt::host_copy(get_constraint_upper_bounds()); |
| 611 | + |
| 612 | + auto findMaxAbs = [](const std::vector<f_t>& vec) -> f_t { |
| 613 | + if (vec.empty()) { return 0.0; } |
| 614 | + const f_t inf = std::numeric_limits<f_t>::infinity(); |
| 615 | + |
| 616 | + const size_t sz = vec.size(); |
| 617 | + f_t max_abs_val = 0.0; |
| 618 | + for (size_t i = 0; i < sz; ++i) { |
| 619 | + const f_t val = std::abs(vec[i]); |
| 620 | + if (val < inf) { max_abs_val = std::max(max_abs_val, val); } |
| 621 | + } |
| 622 | + return max_abs_val; |
| 623 | + }; |
| 624 | + |
| 625 | + auto findMinAbs = [](const std::vector<f_t>& vec) -> f_t { |
| 626 | + if (vec.empty()) { return 0.0; } |
| 627 | + const size_t sz = vec.size(); |
| 628 | + const f_t inf = std::numeric_limits<f_t>::infinity(); |
| 629 | + f_t min_abs_val = inf; |
| 630 | + for (size_t i = 0; i < sz; ++i) { |
| 631 | + const f_t val = std::abs(vec[i]); |
| 632 | + if (val > 0.0) { min_abs_val = std::min(min_abs_val, val); } |
| 633 | + } |
| 634 | + return min_abs_val < inf ? min_abs_val : 0.0; |
| 635 | + }; |
| 636 | + |
| 637 | + f_t A_max = findMaxAbs(constraint_matrix_values); |
| 638 | + f_t A_min = findMinAbs(constraint_matrix_values); |
| 639 | + f_t b_max = findMaxAbs(constraint_rhs); |
| 640 | + f_t b_min = findMinAbs(constraint_rhs); |
| 641 | + f_t c_max = findMaxAbs(objective_coefficients); |
| 642 | + f_t c_min = findMinAbs(objective_coefficients); |
| 643 | + f_t x_lower_max = findMaxAbs(variable_lower_bounds); |
| 644 | + f_t x_lower_min = findMinAbs(variable_lower_bounds); |
| 645 | + f_t x_upper_max = findMaxAbs(variable_upper_bounds); |
| 646 | + f_t x_upper_min = findMinAbs(variable_upper_bounds); |
| 647 | + f_t cstr_lower_max = findMaxAbs(constraint_lower_bounds); |
| 648 | + f_t cstr_lower_min = findMinAbs(constraint_lower_bounds); |
| 649 | + f_t cstr_upper_max = findMaxAbs(constraint_upper_bounds); |
| 650 | + f_t cstr_upper_min = findMinAbs(constraint_upper_bounds); |
| 651 | + |
| 652 | + f_t rhs_max = std::max(b_max, std::max(cstr_lower_max, cstr_upper_max)); |
| 653 | + f_t rhs_min = std::min(b_min, std::min(cstr_lower_min, cstr_upper_min)); |
| 654 | + |
| 655 | + f_t bound_max = std::max(x_upper_max, x_lower_max); |
| 656 | + f_t bound_min = std::min(x_upper_min, x_lower_min); |
| 657 | + |
| 658 | + CUOPT_LOG_INFO("Problem scaling:"); |
| 659 | + CUOPT_LOG_INFO("Objective coefficents range: [%.0e, %.0e]", c_min, c_max); |
| 660 | + CUOPT_LOG_INFO("Constraint matrix coefficients range: [%.0e, %.0e]", A_min, A_max); |
| 661 | + CUOPT_LOG_INFO("Constraint rhs / bounds range: [%.0e, %.0e]", rhs_min, rhs_max); |
| 662 | + CUOPT_LOG_INFO("Variable bounds range: [%.0e, %.0e]", bound_min, bound_max); |
| 663 | + |
| 664 | + auto safelog10 = [](f_t x) { return x > 0 ? std::log10(x) : 0.0; }; |
| 665 | + |
| 666 | + f_t obj_range = safelog10(c_max) - safelog10(c_min); |
| 667 | + f_t A_range = safelog10(A_max) - safelog10(A_min); |
| 668 | + f_t rhs_range = safelog10(rhs_max) - safelog10(rhs_min); |
| 669 | + f_t bound_range = safelog10(bound_max) - safelog10(bound_min); |
| 670 | + |
| 671 | + if (obj_range >= 6.0 || A_range >= 6.0 || rhs_range >= 6.0 || bound_range >= 6.0) { |
| 672 | + CUOPT_LOG_INFO( |
| 673 | + "Warning: input problem contains a large range of coefficients: consider reformulating to " |
| 674 | + "avoid numerical difficulties."); |
| 675 | + } |
| 676 | + CUOPT_LOG_INFO(""); |
| 677 | +} |
| 678 | + |
586 | 679 | // NOTE: Explicitly instantiate all types here in order to avoid linker error |
587 | 680 | #if MIP_INSTANTIATE_FLOAT |
588 | 681 | template class optimization_problem_t<int, float>; |
|
0 commit comments