From f778faf291cfd5565b338aaa629277cead31fd22 Mon Sep 17 00:00:00 2001 From: Jason Marechal Date: Fri, 17 Jan 2025 15:53:33 +0100 Subject: [PATCH] Handle save/restore in benders --- src/cpp/benders/benders_core/BendersBase.cpp | 4 +- src/cpp/benders/benders_core/CMakeLists.txt | 4 ++ .../benders_core/SimulationOptions.cpp | 1 + src/cpp/benders/benders_core/SolverIO.cpp | 37 ++++++++++++++++ .../benders/benders_core/SubproblemWorker.cpp | 17 +++++--- src/cpp/benders/benders_core/Worker.cpp | 43 ++++++++++--------- src/cpp/benders/benders_core/WorkerMaster.cpp | 25 +++++------ .../benders/benders_core/SolverIO.h | 14 ++++++ .../benders/benders_core/SubproblemWorker.h | 4 +- .../benders/benders_core/Worker.h | 21 +++++---- .../benders/benders_core/WorkerMaster.h | 3 +- src/cpp/benders/benders_mpi/BendersMPI.cpp | 2 +- .../benders_sequential/BendersSequential.cpp | 2 +- 13 files changed, 117 insertions(+), 60 deletions(-) create mode 100644 src/cpp/benders/benders_core/SolverIO.cpp create mode 100644 src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SolverIO.h diff --git a/src/cpp/benders/benders_core/BendersBase.cpp b/src/cpp/benders/benders_core/BendersBase.cpp index 09d16300f..5f8f3b51e 100644 --- a/src/cpp/benders/benders_core/BendersBase.cpp +++ b/src/cpp/benders/benders_core/BendersBase.cpp @@ -774,7 +774,7 @@ void BendersBase::AddSubproblem( subproblem_map[kvp.first] = std::make_shared( kvp.second, GetSubproblemPath(kvp.first), SubproblemWeight(_data.nsubproblem, kvp.first), _options.SOLVER_NAME, - _options.LOG_LEVEL, solver_log_manager_, _logger); + _options.LOG_LEVEL, solver_log_manager_, _logger, _options.PROBLEMS_FORMAT); } void BendersBase::free_subproblems() { @@ -953,7 +953,7 @@ void BendersBase::ResetMasterFromLastIteration() { reset_master(master_variable_map_, LastMasterPath(), get_solver_name(), get_log_level(), _data.nsubproblem, solver_log_manager_, - IsResumeMode(), _logger); + IsResumeMode(), _logger, Options().PROBLEMS_FORMAT); } bool BendersBase::MasterIsEmpty() const { return master_is_empty_; } diff --git a/src/cpp/benders/benders_core/CMakeLists.txt b/src/cpp/benders/benders_core/CMakeLists.txt index 851549ecb..3a3b631fe 100644 --- a/src/cpp/benders/benders_core/CMakeLists.txt +++ b/src/cpp/benders/benders_core/CMakeLists.txt @@ -18,7 +18,9 @@ target_sources(benders_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/LastIterationReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/LastIterationWriter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MasterUpdateBase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ProblemFormatStream.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SimulationOptions.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SolverIO.cpp ${CMAKE_CURRENT_SOURCE_DIR}/StartUp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/SubproblemWorker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Worker.cpp @@ -40,7 +42,9 @@ target_sources(benders_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/LastIterationWriter.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/MasterUpdate.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/ProblemFormat.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/ProblemFormatStream.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/SimulationOptions.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/SolverIO.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/StartUp.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/SubproblemWorker.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/VariablesGroup.h diff --git a/src/cpp/benders/benders_core/SimulationOptions.cpp b/src/cpp/benders/benders_core/SimulationOptions.cpp index 1a7288a1c..92a80ab01 100644 --- a/src/cpp/benders/benders_core/SimulationOptions.cpp +++ b/src/cpp/benders/benders_core/SimulationOptions.cpp @@ -5,6 +5,7 @@ #include #include "antares-xpansion/xpansion_interfaces/LogUtils.h" +#include "antares-xpansion/benders/benders_core/ProblemFormatStream.h" Json::Value SimulationOptions::get_value_from_json( const std::filesystem::path &file_name) { Json::Value _input; diff --git a/src/cpp/benders/benders_core/SolverIO.cpp b/src/cpp/benders/benders_core/SolverIO.cpp new file mode 100644 index 000000000..a2230a641 --- /dev/null +++ b/src/cpp/benders/benders_core/SolverIO.cpp @@ -0,0 +1,37 @@ + +#include +#include +#include + +void SolverIO::write(SolverAbstract* solver, + const std::filesystem::path& path) const { + switch (format_) { + case ProblemsFormat::MPS_FILE: + solver->write_prob_mps(path); + break; + case ProblemsFormat::SAVED_FILE: + solver->save_prob(path); + break; + default: + throw LogUtils::XpansionError( + fmt::format("Unknown file format {} for problem file: {}", format_, path.string()), LOGLOCATION); + } +} +void SolverIO::read(SolverAbstract* solver, + const std::filesystem::path& path) const { + switch (format_) { + case ProblemsFormat::MPS_FILE: + solver->read_prob_mps(path); + break; + case ProblemsFormat::SAVED_FILE: + solver->restore_prob(path); + break; + default: + throw LogUtils::XpansionError( + fmt::format("Unknown file format {} for problem file: {}", format_, path.string()), LOGLOCATION); + } +} +void SolverIO::configure(const std::string& solver_name, ProblemsFormat format) { + solver_config_ = solver_name; + format_ = format; +} diff --git a/src/cpp/benders/benders_core/SubproblemWorker.cpp b/src/cpp/benders/benders_core/SubproblemWorker.cpp index a156b34d7..fdd7f855f 100644 --- a/src/cpp/benders/benders_core/SubproblemWorker.cpp +++ b/src/cpp/benders/benders_core/SubproblemWorker.cpp @@ -1,5 +1,7 @@ #include "antares-xpansion/benders/benders_core/SubproblemWorker.h" +#include + #include "antares-xpansion/helpers/solver_utils.h" /*! @@ -10,12 +12,15 @@ * \param problem_name : Name of the problem * */ -SubproblemWorker::SubproblemWorker( - VariableMap const &variable_map, const std::filesystem::path &path_to_mps, - double const &slave_weight, const std::string &solver_name, - const int log_level, SolverLogManager &solver_log_manager, Logger logger) - : Worker(std::move(logger)) { - init(variable_map, path_to_mps, solver_name, log_level, solver_log_manager); +SubproblemWorker::SubproblemWorker(VariableMap const &variable_map, + const std::filesystem::path &path_to_mps, + double const &slave_weight, + const std::string &solver_name, + const int log_level, + SolverLogManager &solver_log_manager, + Logger logger, ProblemsFormat format) + : Worker(variable_map, path_to_mps, std::move(logger)) { + init(solver_name, log_level, solver_log_manager, format); int mps_ncols(_solver->get_ncols()); DblVector obj_func_coeffs(mps_ncols); diff --git a/src/cpp/benders/benders_core/Worker.cpp b/src/cpp/benders/benders_core/Worker.cpp index 02440893b..2fc1b781a 100644 --- a/src/cpp/benders/benders_core/Worker.cpp +++ b/src/cpp/benders/benders_core/Worker.cpp @@ -1,8 +1,9 @@ #include "antares-xpansion/benders/benders_core/Worker.h" -#include "antares-xpansion/xpansion_interfaces/LogUtils.h" +#include #include "antares-xpansion/helpers/solver_utils.h" +#include "antares-xpansion/xpansion_interfaces/LogUtils.h" /*! * \brief Free the problem */ @@ -34,11 +35,9 @@ void Worker::get_value(double &lb) const { * * \param problem_name : name of the problem */ -void Worker::init(VariableMap const &variable_map, - const std::filesystem::path &path_to_mps, - std::string const &solver_name, int log_level, - SolverLogManager&solver_log_manager) { - _path_to_mps = path_to_mps; +void Worker::init(const std::string &solver_name, int log_level, + SolverLogManager &solver_log_manager, ProblemsFormat format) { + solver_io_.configure(solver_name, format); SolverFactory factory(logger_); if (_is_master) { @@ -51,11 +50,9 @@ void Worker::init(VariableMap const &variable_map, _solver->set_threads(1); _solver->set_output_log_level(log_level); - read_prob(_solver.get(), path_to_mps); + read_prob(_solver.get(), _path_to_mps); - _name_to_id = variable_map; - - for (auto const &kvp : variable_map) { + for (auto const &kvp : _name_to_id) { _id_to_name[kvp.second] = kvp.first; } } @@ -85,7 +82,7 @@ void Worker::solve(int &lp_status, const std::string &outputroot, msg << "written in " << error_file_path.string() << std::endl; logger_->display_message(msg.str()); - _solver->write_prob_mps(error_file_path); + writeProb(error_file_path); Output::ProblemData data; data.name = _path_to_mps.filename().string(); data.path = error_file_path; @@ -100,8 +97,7 @@ void Worker::solve(int &lp_status, const std::string &outputroot, } if (_is_master) { - _solver->write_prob_mps(std::filesystem::path(outputroot) / - output_master_mps_file_name); + writeProb(std::filesystem::path(outputroot) / output_master_mps_file_name); } } /*! @@ -150,13 +146,18 @@ int Worker::Getncols() const { return _solver->get_ncols(); } * @param problem * @param path */ -void Worker::read_prob(SolverAbstract * problem, +void Worker::read_prob(SolverAbstract *problem, const std::filesystem::path &path) const { - if (path.extension() == ".mps") { - problem->read_prob_mps(path); - } else if (path.extension() == ".svf") {//Brittle - problem->restore_prob(path); - } else { - throw LogUtils::XpansionError("Unknown file extension for problem file: " + path.string(), LOGLOCATION); - } + solver_io_.read(_solver.get(), path); +} +std::shared_ptr Worker::solver() const { return _solver; } + +Worker::Worker(VariableMap variable_map, std::filesystem::path path_to_mps, + Logger logger) + : _path_to_mps{std::move(path_to_mps)}, + _name_to_id{std::move(variable_map)}, + logger_{std::move(logger)} {} + +void Worker::writeProb(const std::filesystem::path &out) const { + solver_io_.write(_solver.get(), out); } diff --git a/src/cpp/benders/benders_core/WorkerMaster.cpp b/src/cpp/benders/benders_core/WorkerMaster.cpp index 95acb737c..9d0990cf8 100644 --- a/src/cpp/benders/benders_core/WorkerMaster.cpp +++ b/src/cpp/benders/benders_core/WorkerMaster.cpp @@ -1,12 +1,7 @@ #include "antares-xpansion/benders/benders_core/WorkerMaster.h" - #include "antares-xpansion/helpers/solver_utils.h" -WorkerMaster::WorkerMaster(Logger logger) : Worker(logger) { - _is_master = true; -} - /*! * \brief Constructor of a Master Problem * @@ -19,17 +14,19 @@ 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) - : Worker(std::move(logger)), - subproblems_count(subproblems_count), - _mps_has_alpha(mps_has_alpha) { +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, ProblemsFormat format) + : Worker(variable_map, path_to_mps, std::move(logger)), + subproblems_count{subproblems_count}, + _mps_has_alpha{mps_has_alpha} +{ _is_master = true; - init(variable_map, path_to_mps, solver_name, log_level, solver_log_manager); + init(solver_name, log_level, solver_log_manager, format); if (!_mps_has_alpha) { _set_upper_bounds(); } diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SolverIO.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SolverIO.h new file mode 100644 index 000000000..6dabf663c --- /dev/null +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SolverIO.h @@ -0,0 +1,14 @@ +#pragma once + +#include "ProblemFormat.h" +#include "antares-xpansion/multisolver_interface/SolverAbstract.h" +#include "antares-xpansion/multisolver_interface/SolverConfig.h" + +class SolverIO { + SolverConfig solver_config_{"Coin"}; + ProblemsFormat format_; + public: + void configure(const std::string& solver_name, ProblemsFormat format); + void write(SolverAbstract* solver, const std::filesystem::path& path) const; + void read(SolverAbstract* solver, const std::filesystem::path& path) const; +}; diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SubproblemWorker.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SubproblemWorker.h index 1369b2a8d..347481a6a 100644 --- a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SubproblemWorker.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/SubproblemWorker.h @@ -14,13 +14,13 @@ typedef std::map SubproblemsMapPtr; class SubproblemWorker : public Worker { public: - explicit SubproblemWorker(Logger logger) : Worker(logger) {} + using Worker::Worker; SubproblemWorker(VariableMap const &variable_map, const std::filesystem::path &path_to_mps, double const &slave_weight, const std::string &solver_name, const int log_level, SolverLogManager&solver_log_manager, - Logger logger); + Logger logger, ProblemsFormat format); virtual ~SubproblemWorker() = default; void get_solution(std::vector &solution) const; diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/Worker.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/Worker.h index 73ae873ee..7bdf3e432 100644 --- a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/Worker.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/Worker.h @@ -2,12 +2,11 @@ #include +#include "SolverIO.h" +#include "antares-xpansion/multisolver_interface/Solver.h" #include "antares-xpansion/xpansion_interfaces/ILogger.h" #include "antares-xpansion/xpansion_interfaces/OutputWriter.h" #include "common.h" -#include "antares-xpansion/multisolver_interface/Solver.h" -class Worker; -typedef std::shared_ptr WorkerPtr; /*! * \class Worker @@ -15,14 +14,12 @@ typedef std::shared_ptr WorkerPtr; * * This class opens and sets a problem from a mps and a mapping variable map */ - class Worker { public: - explicit Worker(Logger logger) : logger_(std::move(logger)) {} - void init(VariableMap const &variable_map, - const std::filesystem::path &path_to_mps, - std::string const &solver_name, int log_level, - SolverLogManager&solver_log_manager); + Worker(VariableMap variable_map, std::filesystem::path path_to_mps, + Logger logger); + void init(const std::string &solver_name, int log_level, + SolverLogManager &solver_log_manager, ProblemsFormat format); virtual ~Worker() = default; void get_value(double &lb) const; @@ -31,7 +28,7 @@ class Worker { void free(); void write_basis(const std::filesystem::path &filename) const; - virtual SolverAbstract::Ptr solver() const { return _solver; } + [[nodiscard]] virtual std::shared_ptr solver() const; public: std::filesystem::path _path_to_mps; @@ -65,7 +62,7 @@ class Worker { int Getncols() const; public: - SolverAbstract::Ptr _solver = + std::shared_ptr _solver = nullptr; /*!< Problem stocked in the instance Worker*/ bool _is_master = false; @@ -74,4 +71,6 @@ class Worker { private: void read_prob(SolverAbstract * problem, const std::filesystem::path &path) const; + SolverIO solver_io_; + void writeProb(const std::filesystem::path& out) const; }; 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..4e755e526 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 @@ -11,13 +11,12 @@ typedef std::shared_ptr WorkerMasterPtr; class WorkerMaster : public Worker { public: - explicit WorkerMaster(Logger logger); 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, - bool mps_has_alpha, Logger logger); + bool mps_has_alpha, Logger logger, ProblemsFormat format); ~WorkerMaster() override = default; void get(Point &x0, double &overall_subpb_cost_under_approx, diff --git a/src/cpp/benders/benders_mpi/BendersMPI.cpp b/src/cpp/benders/benders_mpi/BendersMPI.cpp index 00012f048..b51c64bd9 100644 --- a/src/cpp/benders/benders_mpi/BendersMPI.cpp +++ b/src/cpp/benders/benders_mpi/BendersMPI.cpp @@ -58,7 +58,7 @@ void BendersMpi::BuildMasterProblem() { reset_master(master_variable_map_, get_master_path(), get_solver_name(), get_log_level(), _data.nsubproblem, solver_log_manager_, - IsResumeMode(), _logger); + IsResumeMode(), _logger, Options().PROBLEMS_FORMAT); } } /*! diff --git a/src/cpp/benders/benders_sequential/BendersSequential.cpp b/src/cpp/benders/benders_sequential/BendersSequential.cpp index 060e6b238..6c295d653 100644 --- a/src/cpp/benders/benders_sequential/BendersSequential.cpp +++ b/src/cpp/benders/benders_sequential/BendersSequential.cpp @@ -29,7 +29,7 @@ void BendersSequential::InitializeProblems() { reset_master(master_variable_map_, get_master_path(), get_solver_name(), get_log_level(), _data.nsubproblem, solver_log_manager_, - IsResumeMode(), _logger); + IsResumeMode(), _logger, Options().PROBLEMS_FORMAT); for (const auto &problem : coupling_map_) { const auto subProblemFilePath = GetSubproblemPath(problem.first);