diff --git a/src/cpp/benders/benders_core/SubproblemWorker.cpp b/src/cpp/benders/benders_core/SubproblemWorker.cpp index 6df65b8bf..a156b34d7 100644 --- a/src/cpp/benders/benders_core/SubproblemWorker.cpp +++ b/src/cpp/benders/benders_core/SubproblemWorker.cpp @@ -2,19 +2,6 @@ #include "antares-xpansion/helpers/solver_utils.h" -// Tolerance to which a value is considered zero or integral -// TODO : Allow to parametrize this constant from the options file -int INTTOL = 1e-6; -static void roundingIfWithinTolerance(std::vector &values, - double tolerance) { - std::transform( - values.begin(), values.end(), values.begin(), [tolerance](double value) { - double rounded = std::round(value); - // Check if the value is within the tolerance of the rounded value - return (std::abs(value - rounded) <= tolerance) ? rounded : value; - }); -} - /*! * \brief Constructor of a Worker Slave * @@ -62,7 +49,7 @@ void SubproblemWorker::fix_to(Point const &x0) const { values[i] = x0.find(kvp.second)->second; ++i; } - roundingIfWithinTolerance(values, INTTOL); + solver_chgbounds(_solver, indexes, bndtypes, values); } diff --git a/src/cpp/benders/benders_core/WorkerMaster.cpp b/src/cpp/benders/benders_core/WorkerMaster.cpp index 95acb737c..17b76cb08 100644 --- a/src/cpp/benders/benders_core/WorkerMaster.cpp +++ b/src/cpp/benders/benders_core/WorkerMaster.cpp @@ -1,6 +1,5 @@ #include "antares-xpansion/benders/benders_core/WorkerMaster.h" - #include "antares-xpansion/helpers/solver_utils.h" WorkerMaster::WorkerMaster(Logger logger) : Worker(logger) { @@ -19,11 +18,12 @@ WorkerMaster::WorkerMaster(Logger logger) : Worker(logger) { * \param log_level : solver log level * \param subproblems_count : number of subproblems */ -WorkerMaster::WorkerMaster( - VariableMap const &variable_map, const std::filesystem::path &path_to_mps, - const std::string &solver_name, const int log_level, int subproblems_count, - SolverLogManager&solver_log_manager, - const bool mps_has_alpha, Logger logger) +WorkerMaster::WorkerMaster(VariableMap const &variable_map, + const std::filesystem::path &path_to_mps, + const std::string &solver_name, const int log_level, + int subproblems_count, + SolverLogManager &solver_log_manager, + const bool mps_has_alpha, Logger logger) : Worker(std::move(logger)), subproblems_count(subproblems_count), _mps_has_alpha(mps_has_alpha) { @@ -37,6 +37,41 @@ WorkerMaster::WorkerMaster( _set_nb_units_var_ids(); } +// Tolerance to which a value is considered zero or integral +// TODO : Allow to parametrize this constant from the options file +int INTTOL = 1e-6; +void WorkerMaster::roundXVarIfWithinTolerance(std::vector &values, + double tolerance) { + int nb_candidates = _id_to_name.size(); + + std::vector col_type(nb_candidates); + std::vector lb(nb_candidates); + std::vector ub(nb_candidates); + // Assumes that candidates are the first variables of the master + solver_getcolinfo(*_solver, col_type, lb, ub, 0, nb_candidates - 1); + for (auto const &kvp : _id_to_name) { + double value = values[kvp.first]; + // Case variable near 0 + if (std::abs(value) < tolerance) { + values[kvp.first] = 0; + } + // Case variable slighly above ub + else if (value > ub[kvp.first] && value < ub[kvp.first] + tolerance) { + values[kvp.first] = ub[kvp.first]; + } + // Case variable slighly lower than lb + else if (value < lb[kvp.first] && value > lb[kvp.first] - tolerance) { + values[kvp.first] = lb[kvp.first]; + } + // Case integer variable + else if (col_type[kvp.first] == 'I') { + int rounded = std::round(value); + values[kvp.first] = + std::abs(value - std::round(value)) <= tolerance ? rounded : value; + } + }; +} + /*! * \brief Return optimal variables of a problem * @@ -58,7 +93,11 @@ void WorkerMaster::get(Point &x_out, double &overall_subpb_cost_under_approx, } else { _solver->get_lp_sol(ptr.data(), nullptr, nullptr); } + assert(id_single_subpb_costs_under_approx_.back() + 1 == ptr.size()); + + roundXVarIfWithinTolerance(ptr, INTTOL); + for (auto const &kvp : _id_to_name) { x_out[kvp.second] = ptr[kvp.first]; } diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/WorkerMaster.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/WorkerMaster.h index 95cac1dc6..f3e3ab999 100644 --- a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/WorkerMaster.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/WorkerMaster.h @@ -15,8 +15,7 @@ class WorkerMaster : public Worker { WorkerMaster(VariableMap const &variable_map, const std::filesystem::path &path_to_mps, const std::string &solver_name, int log_level, - int subproblems_count, - SolverLogManager&solver_log_manager, + int subproblems_count, SolverLogManager &solver_log_manager, bool mps_has_alpha, Logger logger); ~WorkerMaster() override = default; @@ -36,7 +35,9 @@ class WorkerMaster : public Worker { virtual void DeactivateIntegrityConstraints() const; virtual void ActivateIntegrityConstraints() const; - [[nodiscard]] virtual std::vector get_id_nb_units() const { return _id_nb_units; }; + [[nodiscard]] virtual std::vector get_id_nb_units() const { + return _id_nb_units; + }; private: std::vector _id_nb_units; @@ -60,4 +61,6 @@ class WorkerMaster : public Worker { void _set_upper_bounds() const; void _set_alpha_var(); void _set_nb_units_var_ids(); + void roundXVarIfWithinTolerance(std::vector &values, + double tolerance); };