From a9770753f6df3ae2730ed8abf0a20e8c3bd33d6e Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:47:33 +0200 Subject: [PATCH] ANT-2223 (#941) ## - [x] search unsp variables for all areas - [x] compute LOLD - [ ] ~need more details on candidate capacity / area~ --- .../benders_by_batch/BendersByBatch.cpp | 4 +- src/cpp/benders/benders_core/BendersBase.cpp | 18 ++ .../benders_core/BendersMathLogger.cpp | 8 +- src/cpp/benders/benders_core/CMakeLists.txt | 6 + .../CriterionComputation.cpp | 10 +- .../OuterLoopInputDataReader.cpp | 6 +- .../benders/benders_core/SubproblemWorker.cpp | 5 +- .../VariablesGroup.cpp | 15 +- src/cpp/benders/benders_core/common.cpp | 2 +- .../benders/benders_core/BendersBase.h | 48 ++-- .../benders_core/CriterionComputation.h | 78 +++++ .../benders_core}/OuterLoopInputDataReader.h | 6 +- .../benders/benders_core}/VariablesGroup.h | 4 +- .../benders/benders_core/common.h | 20 +- src/cpp/benders/benders_mpi/BendersMPI.cpp | 96 +++++-- .../benders_mpi/BendersMpiOuterLoop.cpp | 111 +------- .../benders/benders_mpi/OuterLoopBenders.cpp | 16 +- .../benders/benders_mpi/BendersMPI.h | 10 +- .../benders/benders_mpi/BendersMpiOuterLoop.h | 24 +- .../benders/benders_mpi/OuterLoopBenders.h | 19 +- src/cpp/benders/factories/BendersFactory.cpp | 267 ++++++++++++------ .../benders/factories/BendersFactory.h | 44 ++- src/cpp/benders/outer_loop/CMakeLists.txt | 7 +- src/cpp/benders/outer_loop/OuterLoop.cpp | 11 +- .../benders/outer_loop/OuterLoopBiLevel.cpp | 6 +- .../benders/outer_loop/CriterionComputation.h | 23 -- .../benders/outer_loop/OuterLoop.h | 12 +- .../benders/outer_loop/OuterLoopBiLevel.h | 9 +- .../xpansion_interfaces/ILogger.h | 2 +- tests/cpp/outer_loop/outer_loop_test.cpp | 60 ++-- 30 files changed, 570 insertions(+), 377 deletions(-) rename src/cpp/benders/{outer_loop => benders_core}/CriterionComputation.cpp (89%) rename src/cpp/benders/{outer_loop => benders_core}/OuterLoopInputDataReader.cpp (96%) rename src/cpp/benders/{outer_loop => benders_core}/VariablesGroup.cpp (68%) create mode 100644 src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/CriterionComputation.h rename src/cpp/benders/{outer_loop/include/antares-xpansion/benders/outer_loop => benders_core/include/antares-xpansion/benders/benders_core}/OuterLoopInputDataReader.h (95%) rename src/cpp/benders/{outer_loop/include/antares-xpansion/benders/outer_loop => benders_core/include/antares-xpansion/benders/benders_core}/VariablesGroup.h (89%) delete mode 100644 src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/CriterionComputation.h diff --git a/src/cpp/benders/benders_by_batch/BendersByBatch.cpp b/src/cpp/benders/benders_by_batch/BendersByBatch.cpp index 5ebac7a81..0680aeb06 100644 --- a/src/cpp/benders/benders_by_batch/BendersByBatch.cpp +++ b/src/cpp/benders/benders_by_batch/BendersByBatch.cpp @@ -48,9 +48,7 @@ void BendersByBatch::InitializeProblems() { } } - // if (Rank() == rank_0) { - // SetSubproblemsVariablesIndex(); - // } + BroadCastVariablesIndices(); init_problems_ = false; } void BendersByBatch::BroadcastSingleSubpbCostsUnderApprox() { diff --git a/src/cpp/benders/benders_core/BendersBase.cpp b/src/cpp/benders/benders_core/BendersBase.cpp index 2ef266243..04e1a806f 100644 --- a/src/cpp/benders/benders_core/BendersBase.cpp +++ b/src/cpp/benders/benders_core/BendersBase.cpp @@ -71,6 +71,7 @@ void BendersBase::CloseCsvFile() { _csv_file.close(); } } + void BendersBase::PrintCurrentIterationCsv() { if (relevantIterationData_.last._valid) { auto ite = _data.it - 1; @@ -393,6 +394,7 @@ void BendersBase::GetSubproblemCut(SubProblemDataMap &subproblem_data_map) { }, shouldParallelize()); } + void BendersBase::SolveSubproblem( SubProblemDataMap &subproblem_data_map, PlainData::SubProblemData &subproblem_data, const std::string &name, @@ -408,6 +410,17 @@ void BendersBase::SolveSubproblem( subproblem_data.subproblem_timer = subproblem_timer.elapsed(); } +// Search for variables in sub problems that satisfy patterns +// var_indices is a vector(for each patterns p) of vector (var indices related +// to p) +void BendersBase::SetSubproblemsVariablesIndices() { + if (!subproblem_map.empty()) { + auto subproblem = subproblem_map.begin(); + + criterions_computation_->SearchVariables( + subproblem->second->_solver->get_col_names()); + } +} /*! * \brief Add cut to Master Problem and store the cut in a set * @@ -1037,3 +1050,8 @@ void BendersBase::SetBilevelBestub(double bilevel_best_ub) { _data.outer_loop_current_iteration_data.outer_loop_bilevel_best_ub = bilevel_best_ub; } +void BendersBase::setCriterionsComputation( + std::shared_ptr + criterionsComputation) { + criterions_computation_ = criterionsComputation; +} diff --git a/src/cpp/benders/benders_core/BendersMathLogger.cpp b/src/cpp/benders/benders_core/BendersMathLogger.cpp index 3d3186e85..28e137a20 100644 --- a/src/cpp/benders/benders_core/BendersMathLogger.cpp +++ b/src/cpp/benders/benders_core/BendersMathLogger.cpp @@ -280,7 +280,7 @@ MathLoggerImplementation::MathLoggerImplementation( implementation_ = std::make_shared(file_path, width, type); break; - case BENDERSMETHOD::BENDERS_EXTERNAL_LOOP: + case BENDERSMETHOD::BENDERS_OUTERLOOP: implementation_ = std::make_shared(file_path, width, type); break; @@ -288,7 +288,7 @@ MathLoggerImplementation::MathLoggerImplementation( implementation_ = std::make_shared(file_path, width, type); break; - case BENDERSMETHOD::BENDERS_BY_BATCH_EXTERNAL_LOOP: + case BENDERSMETHOD::BENDERS_BY_BATCH_OUTERLOOP: implementation_ = std::make_shared( file_path, width, type); break; @@ -305,14 +305,14 @@ MathLoggerImplementation::MathLoggerImplementation(const BENDERSMETHOD& method, case BENDERSMETHOD::BENDERS: implementation_ = std::make_shared(width, type); break; - case BENDERSMETHOD::BENDERS_EXTERNAL_LOOP: + case BENDERSMETHOD::BENDERS_OUTERLOOP: implementation_ = std::make_shared(width, type); break; case BENDERSMETHOD::BENDERS_BY_BATCH: implementation_ = std::make_shared(width, type); break; - case BENDERSMETHOD::BENDERS_BY_BATCH_EXTERNAL_LOOP: + case BENDERSMETHOD::BENDERS_BY_BATCH_OUTERLOOP: implementation_ = std::make_shared(width, type); break; diff --git a/src/cpp/benders/benders_core/CMakeLists.txt b/src/cpp/benders/benders_core/CMakeLists.txt index c2cec7274..0e5dd396a 100644 --- a/src/cpp/benders/benders_core/CMakeLists.txt +++ b/src/cpp/benders/benders_core/CMakeLists.txt @@ -22,6 +22,9 @@ target_sources(benders_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Worker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/WorkerMaster.cpp ${CMAKE_CURRENT_SOURCE_DIR}/common.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CriterionComputation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/OuterLoopInputDataReader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/VariablesGroup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/BendersBase.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/BendersMathLogger.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/BendersStructsDatas.h @@ -37,6 +40,9 @@ target_sources(benders_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/Worker.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/WorkerMaster.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/common.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/CriterionComputation.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/benders_core/VariablesGroup.h ) add_library(antaresXpansion::benders_core ALIAS benders_core) diff --git a/src/cpp/benders/outer_loop/CriterionComputation.cpp b/src/cpp/benders/benders_core/CriterionComputation.cpp similarity index 89% rename from src/cpp/benders/outer_loop/CriterionComputation.cpp rename to src/cpp/benders/benders_core/CriterionComputation.cpp index 85ba550e7..72d65fc97 100644 --- a/src/cpp/benders/outer_loop/CriterionComputation.cpp +++ b/src/cpp/benders/benders_core/CriterionComputation.cpp @@ -1,6 +1,6 @@ -#include "antares-xpansion/benders/outer_loop/CriterionComputation.h" +#include "antares-xpansion/benders/benders_core/CriterionComputation.h" -namespace Outerloop { +namespace Benders::Criterion { void CriterionComputation::ComputeOuterLoopCriterion( double subproblem_weight, const std::vector &sub_problem_solution, @@ -26,11 +26,9 @@ void CriterionComputation::ComputeOuterLoopCriterion( } } - - void CriterionComputation::SearchVariables( const std::vector &variables) { - Outerloop::VariablesGroup variablesGroup( + Benders::Criterion::VariablesGroup variablesGroup( variables, outer_loop_input_data_.OuterLoopData()); var_indices_ = variablesGroup.Indices(); } @@ -46,4 +44,4 @@ CriterionComputation::CriterionComputation( const OuterLoopInputData &outer_loop_input_data) : outer_loop_input_data_(outer_loop_input_data) {} -} // namespace Outerloop \ No newline at end of file +} // namespace Benders::Criterion \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/OuterLoopInputDataReader.cpp b/src/cpp/benders/benders_core/OuterLoopInputDataReader.cpp similarity index 96% rename from src/cpp/benders/outer_loop/OuterLoopInputDataReader.cpp rename to src/cpp/benders/benders_core/OuterLoopInputDataReader.cpp index fd854fcee..cf58717c6 100644 --- a/src/cpp/benders/outer_loop/OuterLoopInputDataReader.cpp +++ b/src/cpp/benders/benders_core/OuterLoopInputDataReader.cpp @@ -1,10 +1,10 @@ -#include "antares-xpansion/benders/outer_loop/OuterLoopInputDataReader.h" +#include "include/antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h" #include #include "antares-xpansion/xpansion_interfaces/StringManip.h" -using namespace Outerloop; +using namespace Benders::Criterion; /** * prefix could be := PositiveUnsuppliedEnergy:: or something else necessarily @@ -144,7 +144,7 @@ struct convert { } rhs.SetCriterion(criterion.as()); - rhs.ResetPattern("PositiveUnsuppliedEnergy::", body.as()); + rhs.ResetPattern(PositiveUnsuppliedEnergy, body.as()); return true; } }; diff --git a/src/cpp/benders/benders_core/SubproblemWorker.cpp b/src/cpp/benders/benders_core/SubproblemWorker.cpp index 471c37991..a156b34d7 100644 --- a/src/cpp/benders/benders_core/SubproblemWorker.cpp +++ b/src/cpp/benders/benders_core/SubproblemWorker.cpp @@ -13,9 +13,8 @@ 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(logger) { + 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); int mps_ncols(_solver->get_ncols()); diff --git a/src/cpp/benders/outer_loop/VariablesGroup.cpp b/src/cpp/benders/benders_core/VariablesGroup.cpp similarity index 68% rename from src/cpp/benders/outer_loop/VariablesGroup.cpp rename to src/cpp/benders/benders_core/VariablesGroup.cpp index 38298ea5e..b724d4a30 100644 --- a/src/cpp/benders/outer_loop/VariablesGroup.cpp +++ b/src/cpp/benders/benders_core/VariablesGroup.cpp @@ -1,5 +1,16 @@ -#include "antares-xpansion/benders/outer_loop/VariablesGroup.h" -using namespace Outerloop; +#include "include/antares-xpansion/benders/benders_core/VariablesGroup.h" + +#include + +using namespace Benders::Criterion; + +/** + * @file VariablesGroup.cpp + * @brief Implementation of the VariablesGroup class. + * + * This file contains the implementation of the VariablesGroup class, + * which is responsible for grouping variables based on provided input patterns. + */ VariablesGroup::VariablesGroup( const std::vector& all_variables, diff --git a/src/cpp/benders/benders_core/common.cpp b/src/cpp/benders/benders_core/common.cpp index 00b3e3f0d..6ff942024 100644 --- a/src/cpp/benders/benders_core/common.cpp +++ b/src/cpp/benders/benders_core/common.cpp @@ -48,7 +48,7 @@ CouplingMap build_input(const std::filesystem::path &structure_path) { CouplingMap coupling_map; std::ifstream summary(structure_path, std::ios::in); if (!summary) { - std::cout << "Cannot open file summary " << structure_path << std::endl; + std::cout << "Cannot open structure file " << structure_path << std::endl; return coupling_map; } std::string line; diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/BendersBase.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/BendersBase.h index 26b7c6b47..296caa903 100644 --- a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/BendersBase.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/BendersBase.h @@ -7,14 +7,15 @@ #include "BendersMathLogger.h" #include "BendersStructsDatas.h" -#include "antares-xpansion/xpansion_interfaces/ILogger.h" -#include "antares-xpansion/xpansion_interfaces/OutputWriter.h" +#include "CriterionComputation.h" #include "SimulationOptions.h" #include "SubproblemCut.h" #include "SubproblemWorker.h" -#include "antares-xpansion/helpers/Timer.h" #include "Worker.h" #include "WorkerMaster.h" +#include "antares-xpansion/helpers/Timer.h" +#include "antares-xpansion/xpansion_interfaces/ILogger.h" +#include "antares-xpansion/xpansion_interfaces/OutputWriter.h" #include "common.h" /** * std execution policies don't share a base type so we can't just select @@ -93,15 +94,18 @@ class BendersBase { void SetBilevelBestub(double bilevel_best_ub); void UpdateOuterLoopSolution(); - protected: - bool exception_raised_ = false; - - public: bool isExceptionRaised() const; [[nodiscard]] std::filesystem::path OuterloopOptionsFile() const; void UpdateOverallCosts(); + Logger _logger; + Writer _writer; + std::shared_ptr mathLoggerDriver_; + void setCriterionsComputation( + std::shared_ptr + criterionsComputation); protected: + bool exception_raised_ = false; CurrentIterationData _data; WorkerMasterDataVect workerMasterDataVect_; // BendersCuts best_iteration_cuts_; @@ -152,14 +156,6 @@ class BendersBase { void AddSubproblem(const std::pair &kvp); [[nodiscard]] virtual WorkerMasterPtr get_master() const; void MatchProblemToId(); - /** - * for the nth variable name, Subproblems shares the same prefix , only the - suffix is different - * ex variable at index = 0 is named in: - - * subproblems-1-1 --> NTCDirect::link::hour<0> - * subproblems-3-5 --> NTCDirect::link::hour<672> - */ void AddSubproblemName(const std::string &name); [[nodiscard]] std::string get_master_name() const; [[nodiscard]] std::string get_solver_name() const; @@ -227,6 +223,22 @@ class BendersBase { PlainData::SubProblemData &subproblem_data, const std::string &name, const std::shared_ptr &worker); + // TODO to be rethink + std::shared_ptr + criterions_computation_; + /** + * for the nth variable name, Subproblems shares the same prefix , only the + suffix is different + * ex variable at index = 0 is named in: + + * subproblems-1-1 --> NTCDirect::link::hour<0> + * subproblems-3-5 --> + NTCDirect::link::hour<672> + */ + // Search for variables in sub problems that satisfy patterns + // var_indices is a vector(for each patterns p) of vector (var indices related + // to p) + void SetSubproblemsVariablesIndices(); private: void print_master_and_cut(std::ostream &file, int ite, @@ -246,8 +258,6 @@ class BendersBase { Output::Iteration iteration(const WorkerMasterData &masterDataPtr_l) const; LogData FinalLogData() const; void FillWorkerMasterData(WorkerMasterData &workerMasterData); - - private: bool master_is_empty_ = true; BendersBaseOptions _options; unsigned int _totalNbProblems = 0; @@ -263,9 +273,5 @@ class BendersBase { Timer benders_timer; Output::SolutionData outer_loop_solution_data_; - public: - Logger _logger; - Writer _writer; - std::shared_ptr mathLoggerDriver_; }; using pBendersBase = std::shared_ptr; diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/CriterionComputation.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/CriterionComputation.h new file mode 100644 index 000000000..aa601d23c --- /dev/null +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/CriterionComputation.h @@ -0,0 +1,78 @@ +#pragma once + +#include "OuterLoopInputDataReader.h" +#include "VariablesGroup.h" +namespace Benders::Criterion { + +class CriterionComputation { + public: + /** + * @brief Constructs a CriterionComputation object. + * + * This constructor initializes the CriterionComputation instance with the + * provided outer loop input data. + * + * @param outer_loop_input_data The input data to be used for criterion + * computation. + */ + explicit CriterionComputation( + const OuterLoopInputData &outer_loop_input_data); + + /** + * @brief Searches for relevant variables based on the provided variable + * names. + * + * This method initializes a VariablesGroup with the provided variable names + * and retrieves the indices of these variables for later computation. + * + * @param variables A vector of strings representing the variable names to + * search for. + */ + void SearchVariables(const std::vector &variables); + + /** + * @brief Computes the outer loop criterion based on subproblem solutions. + * + * This method calculates the outer loop criteria and pattern values + * based on the provided subproblem weight and solution. It updates the + * outerLoopCriterions and outerLoopPatternsValues vectors accordingly. + * + * @param subproblem_weight The weight of the subproblem affecting the + * criteria. + * @param sub_problem_solution A vector containing the solutions of the + * subproblem. + * @param outerLoopCriterions A reference to a vector where the computed + * criteria will be stored. + * @param outerLoopPatternsValues A reference to a vector where the computed + * pattern values will be stored. + */ + void ComputeOuterLoopCriterion( + double subproblem_weight, const std::vector &sub_problem_solution, + std::vector &outerLoopCriterions, + std::vector &outerLoopPatternsValues); + + /** + * @brief Retrieves the variable indices. + * + * This method returns a reference to the vector containing the indices of + * the variables associated with this CriterionComputation instance. + * + * @return A reference to the vector of variable indices. + */ + std::vector> &getVarIndices(); + + /** + * @brief Retrieves the outer loop input data. + * + * This method returns a constant reference to the outer loop input data + * associated with this CriterionComputation instance. + * + * @return A constant reference to the OuterLoopInputData object. + */ + const OuterLoopInputData &getOuterLoopInputData() const; + + private: + std::vector> var_indices_; + const OuterLoopInputData outer_loop_input_data_; +}; +} // namespace Benders::Criterion \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopInputDataReader.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h similarity index 95% rename from src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopInputDataReader.h rename to src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h index edaa7d1c3..bd4dfe762 100644 --- a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopInputDataReader.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h @@ -7,7 +7,9 @@ #include "antares-xpansion/helpers/LoggerUtils.h" #include "yaml-cpp/yaml.h" -namespace Outerloop { +namespace Benders::Criterion { +static constexpr const char *const PositiveUnsuppliedEnergy = + "PositiveUnsuppliedEnergy::"; class OuterLoopInputFileError : public LogUtils::XpansionError { @@ -113,4 +115,4 @@ class OuterLoopInputFromYaml : public IOuterLoopInputDataReader { OuterLoopInputData outerLoopInputData_; }; -} // namespace Outerloop \ No newline at end of file +} // namespace Benders::Criterion \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/VariablesGroup.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/VariablesGroup.h similarity index 89% rename from src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/VariablesGroup.h rename to src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/VariablesGroup.h index d68efdfc3..4f82153d5 100644 --- a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/VariablesGroup.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/VariablesGroup.h @@ -4,7 +4,7 @@ #include #include "OuterLoopInputDataReader.h" -namespace Outerloop { +namespace Benders::Criterion { class VariablesGroup { public: explicit VariablesGroup(const std::vector& all_variables, @@ -17,4 +17,4 @@ class VariablesGroup { const std::vector& outer_loop_single_input_data_; std::vector> indices_; }; -} // namespace Outerloop \ No newline at end of file +} // namespace Benders::Criterion \ No newline at end of file diff --git a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/common.h b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/common.h index 66f21d6b6..2d393f97e 100644 --- a/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/common.h +++ b/src/cpp/benders/benders_core/include/antares-xpansion/benders/benders_core/common.h @@ -53,10 +53,26 @@ typedef std::list mps_coupling_list; enum class BENDERSMETHOD { BENDERS, BENDERS_BY_BATCH, - BENDERS_EXTERNAL_LOOP, - BENDERS_BY_BATCH_EXTERNAL_LOOP + BENDERS_OUTERLOOP, + BENDERS_BY_BATCH_OUTERLOOP }; +constexpr inline std::string_view bendersmethod_to_string( + BENDERSMETHOD method) { + switch (method) { + case BENDERSMETHOD::BENDERS: + return "Benders"; + case BENDERSMETHOD::BENDERS_BY_BATCH: + return "Benders by batch"; + case BENDERSMETHOD::BENDERS_OUTERLOOP: + return "Outerloop around Benders"; + case BENDERSMETHOD::BENDERS_BY_BATCH_OUTERLOOP: + return "Outerloop around Benders by batch"; + default: + return "Unknown"; + } +} + struct Predicate { bool operator()(PointPtr const &lhs, PointPtr const &rhs) const { return *lhs < *rhs; diff --git a/src/cpp/benders/benders_mpi/BendersMPI.cpp b/src/cpp/benders/benders_mpi/BendersMPI.cpp index 8b2134c97..90f962f59 100644 --- a/src/cpp/benders/benders_mpi/BendersMPI.cpp +++ b/src/cpp/benders/benders_mpi/BendersMPI.cpp @@ -1,10 +1,12 @@ + #include "antares-xpansion/benders/benders_mpi/BendersMPI.h" #include #include -#include "antares-xpansion/benders/outer_loop/CriterionComputation.h" +#include "antares-xpansion/benders/benders_core/CriterionComputation.h" +#include "antares-xpansion/benders/benders_core/CustomVector.h" #include "antares-xpansion/helpers/Timer.h" BendersMpi::BendersMpi(BendersBaseOptions const &options, Logger logger, @@ -40,8 +42,17 @@ void BendersMpi::InitializeProblems() { } current_problem_id++; } + BroadCastVariablesIndices(); + init_problems_ = false; +} +void BendersMpi::BroadCastVariablesIndices() { + if (_world.rank() == rank_0) { + SetSubproblemsVariablesIndices(); + } + BroadCast(criterions_computation_->getVarIndices(), rank_0); } + void BendersMpi::BuildMasterProblem() { if (_world.rank() == rank_0) { reset_master(master_variable_map_, get_master_path(), @@ -137,10 +148,6 @@ void BendersMpi::gather_subproblems_cut_package_and_build_cuts( } void BendersMpi::GatherCuts(const SubProblemDataMap &subproblem_data_map, const Timer &walltime) { - BuildGatheredCuts(subproblem_data_map, walltime); -} -void BendersMpi::BuildGatheredCuts(const SubProblemDataMap &subproblem_data_map, - const Timer &walltime) { std::vector gathered_subproblem_map; mpi::gather(_world, subproblem_data_map, gathered_subproblem_map, rank_0); SetSubproblemsWalltime(walltime.elapsed()); @@ -151,6 +158,73 @@ void BendersMpi::BuildGatheredCuts(const SubProblemDataMap &subproblem_data_map, // only rank_0 receive non-emtpy gathered_subproblem_map master_build_cuts(gathered_subproblem_map); + + ComputeSubproblemsContributionToOuterLoopCriterion(subproblem_data_map); + if (_world.rank() == rank_0) { + outer_loop_criterion_.push_back( + _data.outer_loop_current_iteration_data.outer_loop_criterion); + UpdateMaxCriterionArea(); + } +} + +void BendersMpi::SolveSubproblem( + SubProblemDataMap &subproblem_data_map, + PlainData::SubProblemData &subproblem_data, const std::string &name, + const std::shared_ptr &worker) { + BendersBase::SolveSubproblem(subproblem_data_map, subproblem_data, name, + worker); + + std::vector solution; + worker->get_solution(solution); + criterions_computation_->ComputeOuterLoopCriterion( + SubproblemWeight(_data.nsubproblem, name), solution, + subproblem_data.outer_loop_criterions, + subproblem_data.outer_loop_patterns_values); +} + +void BendersMpi::UpdateMaxCriterionArea() { + auto criterions_begin = + _data.outer_loop_current_iteration_data.outer_loop_criterion.cbegin(); + auto criterions_end = + _data.outer_loop_current_iteration_data.outer_loop_criterion.cend(); + auto max_criterion_it = std::max_element(criterions_begin, criterions_end); + if (max_criterion_it != criterions_end) { + _data.outer_loop_current_iteration_data.max_criterion = *max_criterion_it; + auto max_criterion_index = + std::distance(criterions_begin, max_criterion_it); + _data.outer_loop_current_iteration_data.max_criterion_area = + criterions_computation_->getOuterLoopInputData() + .OuterLoopData()[max_criterion_index] + .Pattern() + .GetBody(); + } +} + +void BendersMpi::ComputeSubproblemsContributionToOuterLoopCriterion( + const SubProblemDataMap &subproblem_data_map) { + const auto vars_size = criterions_computation_->getVarIndices().size(); + std::vector outer_loop_criterion_per_sub_problem_per_pattern( + vars_size, {}); + _data.outer_loop_current_iteration_data.outer_loop_criterion.resize(vars_size, + 0.); + std::vector outer_loop_patterns_values_per_sub_problem_per_pattern( + vars_size, {}); + _data.outer_loop_current_iteration_data.outer_loop_patterns_values.resize( + vars_size, 0.); + + for (const auto &[subproblem_name, subproblem_data] : subproblem_data_map) { + AddVectors(outer_loop_criterion_per_sub_problem_per_pattern, + subproblem_data.outer_loop_criterions); + AddVectors(outer_loop_patterns_values_per_sub_problem_per_pattern, + subproblem_data.outer_loop_patterns_values); + } + + Reduce(outer_loop_criterion_per_sub_problem_per_pattern, + _data.outer_loop_current_iteration_data.outer_loop_criterion, + std::plus(), rank_0); + Reduce(outer_loop_patterns_values_per_sub_problem_per_pattern, + _data.outer_loop_current_iteration_data.outer_loop_patterns_values, + std::plus(), rank_0); } SubProblemDataMap BendersMpi::get_subproblem_cut_package() { @@ -163,22 +237,10 @@ void BendersMpi::master_build_cuts( std::vector gathered_subproblem_map) { SetSubproblemCost(0); - // if (Rank() == rank_0) { - // TODO decoment to save all cuts - // workerMasterDataVect_.push_back({_data.x_cut, {}}); - // may be unuseful - // current_iteration_cuts_.x_cut = _data.x_cut; - // } for (const auto &subproblem_data_map : gathered_subproblem_map) { for (auto &&[sub_problem_name, subproblem_data] : subproblem_data_map) { - // save current cuts - // workerMasterDataVect_.back().subsProblemDataMap[sub_problem_name] = - // subproblem_data; - // current_iteration_cuts_.subsProblemDataMap[sub_problem_name] = - // subproblem_data; SetSubproblemCost(GetSubproblemCost() + subproblem_data.subproblem_cost); - // compute delta_cut >= options.CUT_MASTER_TOL; BoundSimplexIterations(subproblem_data.simplex_iter); } } diff --git a/src/cpp/benders/benders_mpi/BendersMpiOuterLoop.cpp b/src/cpp/benders/benders_mpi/BendersMpiOuterLoop.cpp index aa52a87e3..e532f45b2 100644 --- a/src/cpp/benders/benders_mpi/BendersMpiOuterLoop.cpp +++ b/src/cpp/benders/benders_mpi/BendersMpiOuterLoop.cpp @@ -1,122 +1,15 @@ #include "antares-xpansion/benders/benders_mpi/BendersMpiOuterLoop.h" -#include "antares-xpansion/benders/benders_core/CustomVector.h" namespace Outerloop { -void BendersMpiOuterLoop::SolveSubproblem( - SubProblemDataMap& subproblem_data_map, - PlainData::SubProblemData& subproblem_data, const std::string& name, - const std::shared_ptr& worker) { - BendersBase::SolveSubproblem(subproblem_data_map, subproblem_data, name, - worker); - std::vector solution; - worker->get_solution(solution); - criterion_computation_.ComputeOuterLoopCriterion( - SubproblemWeight(_data.nsubproblem, name), solution, - subproblem_data.outer_loop_criterions, - subproblem_data.outer_loop_patterns_values); -} BendersMpiOuterLoop::BendersMpiOuterLoop( const BendersBaseOptions& options, Logger logger, Writer writer, mpi::environment& env, mpi::communicator& world, - std::shared_ptr mathLoggerDriver, - CriterionComputation& criterion_computation) - : BendersMpi(options, logger, writer, env, world, mathLoggerDriver), - criterion_computation_(criterion_computation) { - if (_world.rank() == rank_0) { - const auto& headers = - criterion_computation_.getOuterLoopInputData().PatternBodies(); - mathLoggerDriver_->add_logger( - std::filesystem::path(Options().OUTPUTROOT) / "LOLD.txt", headers, - &OuterLoopCurrentIterationData::outer_loop_criterion); - mathLoggerDriver_->add_logger( - std::filesystem::path(Options().OUTPUTROOT) / - (criterion_computation_.getOuterLoopInputData().PatternsPrefix() + - ".txt"), - headers, &OuterLoopCurrentIterationData::outer_loop_patterns_values); - } -} - -// Search for variables in sub problems that satify patterns -// var_indices is a vector(for each patterns p) of vector (var indices related -// to p) -void BendersMpiOuterLoop::SetSubproblemsVariablesIndex() { - if (!subproblem_map.empty()) { - auto subproblem = subproblem_map.begin(); - - criterion_computation_.SearchVariables( - subproblem->second->_solver->get_col_names()); - } -} - -void BendersMpiOuterLoop::UpdateOuterLoopMaxCriterionArea() { - auto criterions_begin = - _data.outer_loop_current_iteration_data.outer_loop_criterion.cbegin(); - auto criterions_end = - _data.outer_loop_current_iteration_data.outer_loop_criterion.cend(); - auto max_criterion_it = std::max_element(criterions_begin, criterions_end); - if (max_criterion_it != criterions_end) { - _data.outer_loop_current_iteration_data.max_criterion = *max_criterion_it; - auto max_criterion_index = - std::distance(criterions_begin, max_criterion_it); - _data.outer_loop_current_iteration_data.max_criterion_area = - criterion_computation_.getOuterLoopInputData() - .OuterLoopData()[max_criterion_index] - .Pattern() - .GetBody(); - } -} - -void BendersMpiOuterLoop::InitializeProblems() { - BendersMpi::InitializeProblems(); + std::shared_ptr mathLoggerDriver) + : BendersMpi(options, logger, writer, env, world, mathLoggerDriver) {} - if (_world.rank() == rank_0) { - SetSubproblemsVariablesIndex(); - } - BroadCast(criterion_computation_.getVarIndices(), rank_0); - init_problems_ = false; -} - -void BendersMpiOuterLoop::ComputeSubproblemsContributionToOuterLoopCriterion( - const SubProblemDataMap& subproblem_data_map) { - const auto vars_size = criterion_computation_.getVarIndices().size(); - std::vector outer_loop_criterion_per_sub_problem_per_pattern( - vars_size, {}); - _data.outer_loop_current_iteration_data.outer_loop_criterion.resize(vars_size, - 0.); - std::vector outer_loop_patterns_values_per_sub_problem_per_pattern( - vars_size, {}); - _data.outer_loop_current_iteration_data.outer_loop_patterns_values.resize( - vars_size, 0.); - - for (const auto& [subproblem_name, subproblem_data] : subproblem_data_map) { - AddVectors(outer_loop_criterion_per_sub_problem_per_pattern, - subproblem_data.outer_loop_criterions); - AddVectors(outer_loop_patterns_values_per_sub_problem_per_pattern, - subproblem_data.outer_loop_patterns_values); - } - - Reduce(outer_loop_criterion_per_sub_problem_per_pattern, - _data.outer_loop_current_iteration_data.outer_loop_criterion, - std::plus(), rank_0); - Reduce(outer_loop_patterns_values_per_sub_problem_per_pattern, - _data.outer_loop_current_iteration_data.outer_loop_patterns_values, - std::plus(), rank_0); -} - -void BendersMpiOuterLoop::GatherCuts( - const SubProblemDataMap& subproblem_data_map, const Timer& walltime) { - BendersMpi::GatherCuts(subproblem_data_map, walltime); - - ComputeSubproblemsContributionToOuterLoopCriterion(subproblem_data_map); - if (_world.rank() == rank_0) { - outer_loop_criterion_.push_back( - _data.outer_loop_current_iteration_data.outer_loop_criterion); - UpdateOuterLoopMaxCriterionArea(); - } -} void BendersMpiOuterLoop::launch() { ++_data.outer_loop_current_iteration_data.benders_num_run; BendersMpi::launch(); diff --git a/src/cpp/benders/benders_mpi/OuterLoopBenders.cpp b/src/cpp/benders/benders_mpi/OuterLoopBenders.cpp index a21366e5a..e86211e34 100644 --- a/src/cpp/benders/benders_mpi/OuterLoopBenders.cpp +++ b/src/cpp/benders/benders_mpi/OuterLoopBenders.cpp @@ -2,11 +2,12 @@ namespace Outerloop { OuterLoopBenders::OuterLoopBenders( - CriterionComputation& criterion_computation, + const std::vector& + outer_loop_data, std::shared_ptr master_updater, std::shared_ptr cuts_manager, pBendersBase benders, mpi::communicator& world) - : OuterLoop(criterion_computation), + : outer_loop_biLevel_(outer_loop_data), master_updater_(std::move(master_updater)), cuts_manager_(std::move(cuts_manager)), benders_(std::move(benders)), @@ -66,11 +67,6 @@ bool OuterLoopBenders::UpdateMaster() { return stop_update_master; } -OuterLoopBenders::~OuterLoopBenders() { - benders_->mathLoggerDriver_->Print(benders_->GetCurrentIterationData()); - benders_->SaveOuterLoopSolutionInOutputFile(); - benders_->free(); -} void OuterLoopBenders::OuterLoopCheckFeasibility() { std::vector obj_coeff; @@ -131,4 +127,10 @@ void OuterLoopBenders::OuterLoopBilevelChecks() { benders_->SetBilevelBestub(outer_loop_biLevel_.BilevelBestub()); } } +void OuterLoopBenders::Run() { + OuterLoop::Run(); + benders_->mathLoggerDriver_->Print(benders_->GetCurrentIterationData()); + benders_->SaveOuterLoopSolutionInOutputFile(); + benders_->free(); +} } // namespace Outerloop diff --git a/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMPI.h b/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMPI.h index 022b2cc08..efd786ffb 100644 --- a/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMPI.h +++ b/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMPI.h @@ -87,8 +87,14 @@ class BendersMpi : public BendersBase { void AllReduce(const T &in_value, T &out_value, Op op) const { mpi::all_reduce(_world, in_value, out_value, op); } - void BuildGatheredCuts(const SubProblemDataMap &subproblem_data_map, - const Timer &walltime); virtual void GatherCuts(const SubProblemDataMap &subproblem_data_map, const Timer &walltime); + void BroadCastVariablesIndices(); + virtual void ComputeSubproblemsContributionToOuterLoopCriterion( + const SubProblemDataMap &subproblem_data_map); + void SolveSubproblem( + SubProblemDataMap &subproblem_data_map, + PlainData::SubProblemData &subproblem_data, const std::string &name, + const std::shared_ptr &worker) override; + void UpdateMaxCriterionArea(); }; diff --git a/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMpiOuterLoop.h b/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMpiOuterLoop.h index f84ba0489..e86a8b83a 100644 --- a/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMpiOuterLoop.h +++ b/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/BendersMpiOuterLoop.h @@ -1,6 +1,6 @@ #pragma once #include "BendersMPI.h" -#include "antares-xpansion/benders/outer_loop/CriterionComputation.h" +#include "antares-xpansion/benders/benders_core/CriterionComputation.h" namespace Outerloop { class BendersMpiOuterLoop : public BendersMpi { @@ -9,30 +9,10 @@ class BendersMpiOuterLoop : public BendersMpi { BendersMpiOuterLoop(BendersBaseOptions const &options, Logger logger, Writer writer, mpi::environment &env, mpi::communicator &world, - std::shared_ptr mathLoggerDriver, - CriterionComputation &criterion_computation); + std::shared_ptr mathLoggerDriver); - protected: - void GatherCuts(const SubProblemDataMap &subproblem_data_map, - const Timer &walltime) override; - - public: void launch() override; - protected: - void InitializeProblems() override; - - virtual void ComputeSubproblemsContributionToOuterLoopCriterion( - const SubProblemDataMap &subproblem_data_map); - void SolveSubproblem( - SubProblemDataMap &subproblem_data_map, - PlainData::SubProblemData &subproblem_data, const std::string &name, - const std::shared_ptr &worker) override; - void SetSubproblemsVariablesIndex(); - void UpdateOuterLoopMaxCriterionArea(); - - private: - CriterionComputation &criterion_computation_; }; } // namespace Outerloop diff --git a/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/OuterLoopBenders.h b/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/OuterLoopBenders.h index 8bd090d74..9747f551e 100644 --- a/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/OuterLoopBenders.h +++ b/src/cpp/benders/benders_mpi/include/antares-xpansion/benders/benders_mpi/OuterLoopBenders.h @@ -1,8 +1,10 @@ #pragma once #include "antares-xpansion/benders/benders_core/BendersBase.h" +#include "antares-xpansion/benders/benders_core/CriterionComputation.h" #include "antares-xpansion/benders/benders_core/CutsManagement.h" #include "antares-xpansion/benders/outer_loop/IMasterUpdate.h" #include "antares-xpansion/benders/outer_loop/OuterLoop.h" +#include "antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h" #include "common_mpi.h" namespace Outerloop { @@ -14,11 +16,15 @@ class CriterionCouldNotBeSatisfied class OuterLoopBenders : public OuterLoop { public: - explicit OuterLoopBenders(CriterionComputation& criterion_computation, - std::shared_ptr master_updater, - std::shared_ptr cuts_manager, - pBendersBase benders, mpi::communicator& world); - // void Run() override; + explicit OuterLoopBenders( + const std::vector& + outer_loop_data, + std::shared_ptr master_updater, + std::shared_ptr cuts_manager, pBendersBase benders, + mpi::communicator& world); + + void Run() override; + void OuterLoopCheckFeasibility() override; void OuterLoopBilevelChecks() override; void RunAttachedAlgo() override; @@ -28,7 +34,7 @@ class OuterLoopBenders : public OuterLoop { double OuterLoopLambdaMin() const override; double OuterLoopLambdaMax() const override; bool UpdateMaster() override; - ~OuterLoopBenders() override; + ~OuterLoopBenders() override = default; private: std::shared_ptr master_updater_; @@ -38,5 +44,6 @@ class OuterLoopBenders : public OuterLoop { mpi::communicator& world_; bool is_bilevel_check_all_ = false; void InitExternalValues(bool is_bilevel_check_all, double lambda); + OuterLoopBiLevel outer_loop_biLevel_; }; } // namespace Outerloop \ No newline at end of file diff --git a/src/cpp/benders/factories/BendersFactory.cpp b/src/cpp/benders/factories/BendersFactory.cpp index 7eaf510df..34aad39b1 100644 --- a/src/cpp/benders/factories/BendersFactory.cpp +++ b/src/cpp/benders/factories/BendersFactory.cpp @@ -5,13 +5,11 @@ #include "antares-xpansion/benders/benders_by_batch/BendersByBatch.h" #include "antares-xpansion/benders/benders_mpi/BendersMpiOuterLoop.h" -#include "antares-xpansion/benders/benders_sequential/BendersSequential.h" #include "antares-xpansion/xpansion_interfaces/ILogger.h" #include "antares-xpansion/xpansion_interfaces/LogUtils.h" #include "antares-xpansion/benders/factories/LoggerFactories.h" #include "antares-xpansion/benders/benders_core/MasterUpdate.h" #include "antares-xpansion/benders/benders_mpi/OuterLoopBenders.h" -#include "antares-xpansion/xpansion_interfaces/OutputWriter.h" #include "antares-xpansion/benders/benders_core/StartUp.h" #include "antares-xpansion/helpers/Timer.h" #include "antares-xpansion/benders/benders_core/Worker.h" @@ -21,167 +19,262 @@ BENDERSMETHOD DeduceBendersMethod(size_t coupling_map_size, size_t batch_size, bool external_loop) { if (batch_size == 0 || batch_size == coupling_map_size - 1) { if (external_loop) { - return BENDERSMETHOD::BENDERS_EXTERNAL_LOOP; + return BENDERSMETHOD::BENDERS_OUTERLOOP; } else { return BENDERSMETHOD::BENDERS; } } else { if (external_loop) { - return BENDERSMETHOD::BENDERS_BY_BATCH_EXTERNAL_LOOP; + return BENDERSMETHOD::BENDERS_BY_BATCH_OUTERLOOP; } else { return BENDERSMETHOD::BENDERS_BY_BATCH; } } } -pBendersBase BendersMainFactory::PrepareForExecution( - BendersLoggerBase& benders_loggers, const SimulationOptions& options, - bool external_loop, - Outerloop::CriterionComputation* criterion_computation) const { +pBendersBase BendersMainFactory::PrepareForExecution(bool external_loop) { pBendersBase benders; - Logger logger; std::shared_ptr math_log_driver; - - BendersBaseOptions benders_options(options.get_benders_options()); + BendersBaseOptions benders_options(options_.get_benders_options()); benders_options.EXTERNAL_LOOP_OPTIONS.DO_OUTER_LOOP = external_loop; - auto log_reports_name = - std::filesystem::path(options.OUTPUTROOT) / "reportbenders.txt"; - - auto math_logs_file = - std::filesystem::path(options.OUTPUTROOT) / "benders_solver.log"; - Writer writer; const auto coupling_map = build_input(benders_options.STRUCTURE_FILE); - const auto method = DeduceBendersMethod(coupling_map.size(), - options.BATCH_SIZE, external_loop); + method_ = DeduceBendersMethod(coupling_map.size(), options_.BATCH_SIZE, + external_loop); + auto benders_log_console = benders_options.LOG_LEVEL > 0; if (pworld_->rank() == 0) { - auto benders_log_console = benders_options.LOG_LEVEL > 0; auto logger_factory = - FileAndStdoutLoggerFactory(log_reports_name, benders_log_console); - auto math_log_factory = - MathLoggerFactory(method, benders_log_console, math_logs_file); + FileAndStdoutLoggerFactory(LogReportsName(), benders_log_console); + logger_ = logger_factory.get_logger(); + - logger = logger_factory.get_logger(); - math_log_driver = math_log_factory.get_logger(); - writer = build_json_writer(options.JSON_FILE, options.RESUME); + writer_ = build_json_writer(options_.JSON_FILE, options_.RESUME); if (Benders::StartUp startup; - startup.StudyAlreadyAchievedCriterion(options, writer, logger)) + startup.StudyAlreadyAchievedCriterion(options_, writer_, logger_)) return nullptr; } else { - logger = build_void_logger(); - writer = build_void_writer(); + logger_ = build_void_logger(); + writer_ = build_void_writer(); math_log_driver = MathLoggerFactory::get_void_logger(); } - benders_loggers.AddLogger(logger); - benders_loggers.AddLogger(math_log_driver); - switch (method) { + auto outer_loop_input_data = ProcessCriterionInput(coupling_map); + criterion_computation_ = + std::make_shared( + outer_loop_input_data); + if (pworld_->rank() == 0) { + math_log_driver = BuildMathLogger(benders_log_console); + } + + benders_loggers_.AddLogger(logger_); + benders_loggers_.AddLogger(math_log_driver); + switch (method_) { case BENDERSMETHOD::BENDERS: - benders = std::make_shared(benders_options, logger, writer, + benders = std::make_shared(benders_options, logger_, writer_, *penv_, *pworld_, math_log_driver); break; - case BENDERSMETHOD::BENDERS_EXTERNAL_LOOP: + case BENDERSMETHOD::BENDERS_OUTERLOOP: benders = std::make_shared( - benders_options, logger, writer, *penv_, *pworld_, math_log_driver, - *criterion_computation); + benders_options, logger_, writer_, *penv_, *pworld_, math_log_driver); break; case BENDERSMETHOD::BENDERS_BY_BATCH: - case BENDERSMETHOD::BENDERS_BY_BATCH_EXTERNAL_LOOP: + case BENDERSMETHOD::BENDERS_BY_BATCH_OUTERLOOP: benders = std::make_shared( - benders_options, logger, writer, *penv_, *pworld_, math_log_driver); + benders_options, logger_, writer_, *penv_, *pworld_, math_log_driver); break; } benders->set_input_map(coupling_map); - std::ostringstream oss_l = start_message(options, benders->BendersName()); + std::ostringstream oss_l = start_message(options_, benders->BendersName()); oss_l << std::endl; - benders_loggers.display_message(oss_l.str()); + benders_loggers_.display_message(oss_l.str()); if (benders_options.LOG_LEVEL > 1) { - auto solver_log = std::filesystem::path(options.OUTPUTROOT) / + auto solver_log = std::filesystem::path(options_.OUTPUTROOT) / (std::string("solver_log_proc_") + std::to_string(pworld_->rank()) + ".txt"); benders->set_solver_log_file(solver_log); } - writer->write_log_level(options.LOG_LEVEL); - writer->write_master_name(options.MASTER_NAME); - writer->write_solver_name(options.SOLVER_NAME); + + writer_->write_log_level(options_.LOG_LEVEL); + writer_->write_master_name(options_.MASTER_NAME); + writer_->write_solver_name(options_.SOLVER_NAME); + benders->setCriterionsComputation(criterion_computation_); + return benders; } -int BendersMainFactory::RunBenders() const { - // Read options, needed to have options.OUTPUTROOT - BendersLoggerBase benders_loggers; +std::shared_ptr BendersMainFactory::BuildMathLogger( + bool benders_log_console) const { + const std::filesystem::path output_root(options_.OUTPUTROOT); + auto math_logs_file = output_root / "benders_solver.log"; + + auto math_log_factory = + MathLoggerFactory(method_, benders_log_console, math_logs_file); + + auto math_log_driver = math_log_factory.get_logger(); + + const auto& headers = + criterion_computation_->getOuterLoopInputData().PatternBodies(); + math_log_driver->add_logger( + output_root / "LOLD.txt", headers, + &OuterLoopCurrentIterationData::outer_loop_criterion); + math_log_driver->add_logger( + output_root / + (criterion_computation_->getOuterLoopInputData().PatternsPrefix() + + ".txt"), + headers, &OuterLoopCurrentIterationData::outer_loop_patterns_values); + return math_log_driver; +} + +int BendersMainFactory::RunBenders() { try { - SimulationOptions options(options_file_); - auto benders = PrepareForExecution(benders_loggers, options, false); + auto benders = PrepareForExecution(false); if (benders) { benders->launch(); - - std::stringstream str; - str << "Optimization results available in : " << options.JSON_FILE - << std::endl; - benders_loggers.display_message(str.str()); - - str.str(""); - str << "Benders ran in " << benders->execution_time() << " s" - << std::endl; - benders_loggers.display_message(str.str()); + EndMessage(benders->execution_time()); } } catch (std::exception& e) { std::ostringstream msg; msg << "error: " << e.what() << std::endl; - benders_loggers.display_message(msg.str()); + benders_loggers_.display_message(msg.str()); mpi::environment::abort(1); } catch (...) { std::ostringstream msg; msg << "Exception of unknown type!" << std::endl; - benders_loggers.display_message(msg.str()); + benders_loggers_.display_message(msg.str()); mpi::environment::abort(1); } return 0; } -int BendersMainFactory::RunExternalLoop() const { - BendersLoggerBase benders_loggers; - try { - SimulationOptions options(options_file_); - auto outer_loop_input_data = Outerloop::OuterLoopInputFromYaml().Read( - std::filesystem::path(options.INPUTROOT) / - options.OUTER_LOOP_OPTION_FILE); - Outerloop::CriterionComputation criterion_computation( - outer_loop_input_data); - auto benders = PrepareForExecution(benders_loggers, options, true, - &criterion_computation); +void BendersMainFactory::EndMessage(const double execution_time) { + std::ostringstream str; + str << "Optimization results available in : " << options_.JSON_FILE + << std::endl; + benders_loggers_.display_message(str.str()); + + str.str(""); + + str << bendersmethod_to_string(method_) << " ran in " << execution_time + << " s" << std::endl; + benders_loggers_.display_message(str.str()); +} + +Benders::Criterion::OuterLoopInputData +BendersMainFactory::ProcessCriterionInput(const CouplingMap& couplingMap) { + const auto fpath = std::filesystem::path(options_.INPUTROOT) / + options_.OUTER_LOOP_OPTION_FILE; + // if adequacy_criterion.yml is provided read it + if (std::filesystem::exists(fpath)) { + return Benders::Criterion::OuterLoopInputFromYaml().Read(fpath); + } + // else compute criterion for all areas! + else { + return GetInputFromSubProblem(couplingMap); + } +} +Benders::Criterion::OuterLoopInputData +BendersMainFactory::GetInputFromSubProblem(const CouplingMap& couplingMap) { + auto first_subproblem_pair = std::find_if_not( + couplingMap.begin(), couplingMap.end(), + [this](const auto& in) { return in.first == options_.MASTER_NAME; }); + if (first_subproblem_pair == couplingMap.end()) { + std::ostringstream stream; + auto log_location = LOGLOCATION; + stream << "Could not find any Subproblem in structure file " + << options_.STRUCTURE_FILE << std::endl; + benders_loggers_.display_message(log_location + stream.str()); + throw InvalidStructureFile( + PrefixMessage(LogUtils::LOGLEVEL::FATAL, "Benders"), stream.str(), + log_location); + } else { + const auto first_subproblem_name = first_subproblem_pair->first; + return PatternsFromSupbProblem(first_subproblem_name); + } +} + +Benders::Criterion::OuterLoopInputData +BendersMainFactory::PatternsFromSupbProblem( + const std::string& first_subproblem_name) const { + SolverAbstract::Ptr solver = BuildSolver(first_subproblem_name); + const auto all_variables_name = solver->get_col_names(); + std::set unique_areas = UniqueAreas(all_variables_name); + Benders::Criterion::OuterLoopInputData ret; + ret.SetCriterionCountThreshold(1); + + for (const auto& area : unique_areas) { + Benders::Criterion::OuterLoopSingleInputData singleInputData( + Benders::Criterion::PositiveUnsuppliedEnergy, area, 1); + ret.AddSingleData(singleInputData); + } + + solver->free(); + return ret; +} + +std::set BendersMainFactory::UniqueAreas( + const std::vector& all_variables_name) const { + std::set unique_areas; + std::regex area_regex( + "area<([^>]+)>"); // Regular expression to match area<...> + + for (const auto& str : all_variables_name) { + std::smatch match; + if (std::regex_search(str, match, area_regex)) { + unique_areas.insert(match[1]); // Insert the matched area into the set + } + } + return unique_areas; +} + +SolverAbstract::Ptr BendersMainFactory::BuildSolver( + const std::string& first_subproblem_name) const { + SolverFactory factory(logger_); + auto solver_log_manager = SolverLogManager(LogReportsName()); + auto solver = factory.create_solver( + options_.SOLVER_NAME, SOLVER_TYPE::CONTINUOUS, solver_log_manager); + solver->read_prob_mps(std::filesystem::path(options_.INPUTROOT) / + first_subproblem_name); + solver->set_threads(1); + return solver; +} + +int BendersMainFactory::RunExternalLoop() { + try { + auto benders = PrepareForExecution(true); double tau = 0.5; - double epsilon_lambda = 0.1; + const auto& criterion_input_data = + criterion_computation_->getOuterLoopInputData(); std::shared_ptr master_updater = std::make_shared( - benders, tau, outer_loop_input_data.StoppingThreshold()); + benders, tau, criterion_input_data.StoppingThreshold()); std::shared_ptr cuts_manager = std::make_shared(); - Outerloop::OuterLoopBenders ext_loop(criterion_computation, master_updater, - cuts_manager, benders, *pworld_); + Outerloop::OuterLoopBenders ext_loop(criterion_input_data.OuterLoopData(), + master_updater, cuts_manager, benders, + *pworld_); ext_loop.Run(); - - } catch (std::exception& e) { + EndMessage(ext_loop.Runtime()); + + } catch (std::exception& e) { std::ostringstream msg; msg << "error: " << e.what() << std::endl; - benders_loggers.display_message(msg.str()); + benders_loggers_.display_message(msg.str()); mpi::environment::abort(1); } catch (...) { std::ostringstream msg; msg << "Exception of unknown type!" << std::endl; - benders_loggers.display_message(msg.str()); + benders_loggers_.display_message(msg.str()); mpi::environment::abort(1); } return 0; @@ -197,22 +290,28 @@ BendersMainFactory::BendersMainFactory(int argc, char** argv, usage(argc); } - options_file_ = std::filesystem::path(argv_[1]); + options_.read(std::filesystem::path(argv_[1])); } BendersMainFactory::BendersMainFactory( int argc, char** argv, const std::filesystem::path& options_file, mpi::environment& env, mpi::communicator& world, const SOLVER& solver) - : argv_(argv), options_file_(options_file), + : argv_(argv), penv_(&env), pworld_(&world), - solver_(solver) { + solver_(solver), + options_(options_file) { // First check usage (options are given) if (world.rank() == 0) { usage(argc); } } -int BendersMainFactory::Run() const { + +std::filesystem::path BendersMainFactory::LogReportsName() const { + return std::filesystem::path(options_.OUTPUTROOT) / "reportbenders.txt"; +} + +int BendersMainFactory::Run() { if (solver_ == SOLVER::BENDERS) { return RunBenders(); } else { diff --git a/src/cpp/benders/factories/include/antares-xpansion/benders/factories/BendersFactory.h b/src/cpp/benders/factories/include/antares-xpansion/benders/factories/BendersFactory.h index ff3e2f762..ab6e41016 100644 --- a/src/cpp/benders/factories/include/antares-xpansion/benders/factories/BendersFactory.h +++ b/src/cpp/benders/factories/include/antares-xpansion/benders/factories/BendersFactory.h @@ -1,22 +1,45 @@ #ifndef ANTARES_XPANSION_SRC_CPP_BENDERS_FACTORIES_INCLUDE_BENDERSFACTORY_H #define ANTARES_XPANSION_SRC_CPP_BENDERS_FACTORIES_INCLUDE_BENDERSFACTORY_H -#include "antares-xpansion/benders/benders_mpi/BendersMPI.h" -#include "antares-xpansion/benders/outer_loop/CriterionComputation.h" +#include "antares-xpansion/benders/benders_core/CriterionComputation.h" #include "antares-xpansion/benders/benders_core/common.h" +#include "antares-xpansion/benders/benders_mpi/BendersMPI.h" + +struct InvalidStructureFile + : public LogUtils::XpansionError { + using LogUtils::XpansionError::XpansionError; +}; class BendersMainFactory { private: char** argv_; - std::filesystem::path options_file_; boost::mpi::environment* penv_ = nullptr; boost::mpi::communicator* pworld_ = nullptr; SOLVER solver_ = SOLVER::BENDERS; - [[nodiscard]] int RunExternalLoop() const; - [[nodiscard]] int RunBenders() const; - pBendersBase PrepareForExecution( - BendersLoggerBase& benders_loggers, const SimulationOptions& options, - bool external_loop, - Outerloop::CriterionComputation* computation = nullptr) const; + SimulationOptions options_; + BendersLoggerBase benders_loggers_; + std::shared_ptr + criterion_computation_ = nullptr; + Logger logger_ = nullptr; + Writer writer_ = nullptr; + BENDERSMETHOD method_ = BENDERSMETHOD::BENDERS; + + [[nodiscard]] int RunExternalLoop(); + [[nodiscard]] int RunBenders(); + [[nodiscard]] std::shared_ptr BuildMathLogger( + bool benders_log_console) const; + pBendersBase PrepareForExecution(bool external_loop); + [[nodiscard]] Benders::Criterion::OuterLoopInputData ProcessCriterionInput( + const CouplingMap& couplingMap); + Benders::Criterion::OuterLoopInputData GetInputFromSubProblem( + const CouplingMap& couplingMap); + + Benders::Criterion::OuterLoopInputData PatternsFromSupbProblem( + const std::string& first_subproblem_name) const; + SolverAbstract::Ptr BuildSolver( + const std::string& first_subproblem_name) const; + std::set UniqueAreas( + const std::vector& all_variables_name) const; + void EndMessage(const double execution_time); public: explicit BendersMainFactory(int argc, char** argv, @@ -28,6 +51,7 @@ class BendersMainFactory { boost::mpi::environment& env, boost::mpi::communicator& world, const SOLVER& solver); - int Run() const; + int Run(); + std::filesystem::path LogReportsName() const; }; #endif // ANTARES_XPANSION_SRC_CPP_BENDERS_FACTORIES_INCLUDE_BENDERSFACTORY_H \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/CMakeLists.txt b/src/cpp/benders/outer_loop/CMakeLists.txt index c0987d271..804963ec3 100644 --- a/src/cpp/benders/outer_loop/CMakeLists.txt +++ b/src/cpp/benders/outer_loop/CMakeLists.txt @@ -20,17 +20,11 @@ endif () add_library(outer_loop_lib) target_sources(outer_loop_lib PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/CriterionComputation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/OuterLoop.cpp ${CMAKE_CURRENT_SOURCE_DIR}/OuterLoopBiLevel.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/OuterLoopInputDataReader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/VariablesGroup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/outer_loop/CriterionComputation.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/outer_loop/IMasterUpdate.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/outer_loop/OuterLoop.h ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/outer_loop/OuterLoopInputDataReader.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/antares-xpansion/benders/outer_loop/VariablesGroup.h ) @@ -41,6 +35,7 @@ target_include_directories(outer_loop_lib target_link_libraries(outer_loop_lib PUBLIC + antaresXpansion::benders_core antaresXpansion::helpers yaml-cpp::yaml-cpp ) diff --git a/src/cpp/benders/outer_loop/OuterLoop.cpp b/src/cpp/benders/outer_loop/OuterLoop.cpp index 3d908b2b8..a60a9d27c 100644 --- a/src/cpp/benders/outer_loop/OuterLoop.cpp +++ b/src/cpp/benders/outer_loop/OuterLoop.cpp @@ -1,7 +1,11 @@ #include "antares-xpansion/benders/outer_loop/OuterLoop.h" + +#include "antares-xpansion/helpers/Timer.h" + namespace Outerloop { void OuterLoop::Run() { + Timer time_counter; OuterLoopCheckFeasibility(); bool stop_update_master = false; @@ -16,12 +20,11 @@ void OuterLoop::Run() { stop_update_master = true; } } + runtime_ = time_counter.elapsed(); PrintLog(); } -OuterLoop::OuterLoop(CriterionComputation &criterion_computation) - : criterion_computation_(criterion_computation), - outer_loop_biLevel_( - criterion_computation.getOuterLoopInputData().OuterLoopData()) {} + +double OuterLoop::Runtime() const { return runtime_; } } // namespace Outerloop \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/OuterLoopBiLevel.cpp b/src/cpp/benders/outer_loop/OuterLoopBiLevel.cpp index dfb0eee38..d687b11e8 100644 --- a/src/cpp/benders/outer_loop/OuterLoopBiLevel.cpp +++ b/src/cpp/benders/outer_loop/OuterLoopBiLevel.cpp @@ -1,7 +1,9 @@ #include "antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h" namespace Outerloop { + OuterLoopBiLevel::OuterLoopBiLevel( - const std::vector &outer_loop_input_data) + const std::vector + &outer_loop_input_data) : outer_loop_input_data_(outer_loop_input_data) {} bool OuterLoopBiLevel::Update_bilevel_data_if_feasible( @@ -53,6 +55,7 @@ void OuterLoopBiLevel::Init(const std::vector &obj, found_feasible_ = false; } + void OuterLoopBiLevel::SetLambdaMaxToMaxInvestmentCosts( const std::vector &obj, const Point &max_invest, const VariableMap &master_variable) { @@ -61,5 +64,6 @@ void OuterLoopBiLevel::SetLambdaMaxToMaxInvestmentCosts( lambda_max_ += obj[var_id] * max_invest.at(var_name); } } + const Point &OuterLoopBiLevel::BilevelBestX() const { return bilevel_best_x_; } } // namespace Outerloop \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/CriterionComputation.h b/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/CriterionComputation.h deleted file mode 100644 index c2d7d4b55..000000000 --- a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/CriterionComputation.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "OuterLoopInputDataReader.h" -#include "VariablesGroup.h" -namespace Outerloop { -class CriterionComputation { - public: - explicit CriterionComputation( - const OuterLoopInputData &outer_loop_input_data); - void SearchVariables(const std::vector &variables); - // outer loop criterion per pattern - void ComputeOuterLoopCriterion( - double subproblem_weight, const std::vector &sub_problem_solution, - std::vector &outerLoopCriterions, - std::vector &outerLoopPatternsValues); - std::vector> &getVarIndices(); - const OuterLoopInputData &getOuterLoopInputData() const; - - private: - std::vector> var_indices_; - const OuterLoopInputData &outer_loop_input_data_; -}; -} // namespace Outerloop \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoop.h b/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoop.h index c8d447c00..b0ffcd008 100644 --- a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoop.h +++ b/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoop.h @@ -1,11 +1,8 @@ #pragma once -#include "CriterionComputation.h" -#include "OuterLoopBiLevel.h" namespace Outerloop { class OuterLoop { public: - explicit OuterLoop(CriterionComputation& criterion_computation_); - void Run(); + virtual void Run(); virtual void OuterLoopCheckFeasibility() = 0; virtual void OuterLoopBilevelChecks() = 0; virtual void RunAttachedAlgo() = 0; @@ -15,11 +12,14 @@ class OuterLoop { virtual bool isExceptionRaised() = 0; virtual double OuterLoopLambdaMin() const = 0; virtual double OuterLoopLambdaMax() const = 0; + virtual ~OuterLoop() = default; + public: + double Runtime() const; + protected: - CriterionComputation& criterion_computation_; - OuterLoopBiLevel outer_loop_biLevel_; + double runtime_ = 0.; }; } // namespace Outerloop \ No newline at end of file diff --git a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h b/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h index 5f18f9ed3..59971f2b5 100644 --- a/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h +++ b/src/cpp/benders/outer_loop/include/antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h @@ -1,5 +1,6 @@ #pragma once -#include "OuterLoopInputDataReader.h" +#include "antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h" + // TODO typedef std::map Point; typedef std::map VariableMap; @@ -8,7 +9,8 @@ namespace Outerloop { class OuterLoopBiLevel { public: explicit OuterLoopBiLevel( - const std::vector &outer_loop_input_data); + const std::vector + &outer_loop_input_data); bool Update_bilevel_data_if_feasible( const Point &x, const std::vector &outer_loop_criterion, double overall_cost, double invest_cost_at_x, double lambda); @@ -38,6 +40,7 @@ class OuterLoopBiLevel { double lambda_max_ = 0.0; double lambda_min_ = 0.0; double lambda_ = 0.0; - const std::vector &outer_loop_input_data_; + const std::vector + &outer_loop_input_data_; }; } // namespace Outerloop \ No newline at end of file diff --git a/src/cpp/xpansion_interfaces/include/antares-xpansion/xpansion_interfaces/ILogger.h b/src/cpp/xpansion_interfaces/include/antares-xpansion/xpansion_interfaces/ILogger.h index 447aea386..7d7cc1eb9 100644 --- a/src/cpp/xpansion_interfaces/include/antares-xpansion/xpansion_interfaces/ILogger.h +++ b/src/cpp/xpansion_interfaces/include/antares-xpansion/xpansion_interfaces/ILogger.h @@ -102,7 +102,7 @@ struct EmptyLogger : public ILoggerXpansion { }; /** - * this \class act like a log agregator + * this \class act like a log aggregator */ struct BendersLoggerBase : public ILoggerXpansion { void display_message(const std::string &str) override { diff --git a/tests/cpp/outer_loop/outer_loop_test.cpp b/tests/cpp/outer_loop/outer_loop_test.cpp index 03e0874e4..725472d49 100644 --- a/tests/cpp/outer_loop/outer_loop_test.cpp +++ b/tests/cpp/outer_loop/outer_loop_test.cpp @@ -1,18 +1,19 @@ -#include "antares-xpansion/benders/factories/LoggerFactories.h" #include "antares-xpansion/benders/benders_core/MasterUpdate.h" +#include "antares-xpansion/benders/benders_core/OuterLoopInputDataReader.h" +#include "antares-xpansion/benders/benders_core/VariablesGroup.h" #include "antares-xpansion/benders/benders_mpi/OuterLoopBenders.h" -#include "antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h" -#include "antares-xpansion/benders/outer_loop/OuterLoopInputDataReader.h" -#include "antares-xpansion/benders/outer_loop/VariablesGroup.h" +#include "antares-xpansion/benders/factories/LoggerFactories.h" #include "antares-xpansion/benders/factories/WriterFactories.h" -#include "gtest/gtest.h" +#include "antares-xpansion/benders/outer_loop/OuterLoopBiLevel.h" #include "antares-xpansion/multisolver_interface/environment.h" +#include "gtest/gtest.h" boost::mpi::environment* penv = nullptr; boost::mpi::communicator* pworld = nullptr; using namespace Outerloop; +using namespace Benders::Criterion; int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); @@ -112,15 +113,20 @@ TEST_P(MasterUpdateBaseTest, ConstraintIsAddedBendersMPI) { *pworld, math_log_driver); benders->set_input_map(coupling_map); - auto outer_loop_input_data = Outerloop::OuterLoopInputFromYaml().Read( - std::filesystem::path(bendersoptions.INPUTROOT) / OUTER_OPTIONS_FILE); - Outerloop::CriterionComputation criterion_computation(outer_loop_input_data); + auto outer_loop_input_data = + Benders::Criterion::OuterLoopInputFromYaml().Read( + std::filesystem::path(bendersoptions.INPUTROOT) / OUTER_OPTIONS_FILE); + auto criterion_computation = + std::make_shared( + outer_loop_input_data); + benders->setCriterionsComputation(criterion_computation); auto master_updater = std::make_shared( benders, 0.5, outer_loop_input_data.StoppingThreshold()); auto cut_manager = std::make_shared(); - Outerloop::OuterLoopBenders out_loop(criterion_computation, master_updater, - cut_manager, benders, *pworld); + Outerloop::OuterLoopBenders out_loop( + criterion_computation->getOuterLoopInputData().OuterLoopData(), + master_updater, cut_manager, benders, *pworld); out_loop.OuterLoopCheckFeasibility(); auto num_constraints_master_before = benders->MasterGetnrows(); @@ -292,28 +298,28 @@ class VariablesGroupTest : public ::testing::Test {}; TEST_F(VariablesGroupTest, EmptyVariablesListGivesEmptyIndices) { std::vector variables; - std::vector data; + std::vector data; - Outerloop::VariablesGroup var_grp(variables, data); + Benders::Criterion::VariablesGroup var_grp(variables, data); ASSERT_TRUE(var_grp.Indices().empty()); } TEST_F(VariablesGroupTest, EmptyPatternsListGivesEmptyIndices) { std::vector variables{ "PositiveUnsuppliedEnergy::area::hour<125>"}; - std::vector data; + std::vector data; - Outerloop::VariablesGroup var_grp(variables, data); + Benders::Criterion::VariablesGroup var_grp(variables, data); ASSERT_TRUE(var_grp.Indices().empty()); } TEST_F(VariablesGroupTest, SingleDataWithInvalidPrefixAndBody) { std::vector variables{ "PositiveUnsuppliedEnergy::area::hour<125>"}; - std::vector data{ - Outerloop::OuterLoopSingleInputData("Pref", "Body", 1534.0)}; + std::vector data{ + Benders::Criterion::OuterLoopSingleInputData("Pref", "Body", 1534.0)}; - Outerloop::VariablesGroup var_grp(variables, data); + Benders::Criterion::VariablesGroup var_grp(variables, data); const auto& vect_indices = var_grp.Indices(); ASSERT_EQ(vect_indices.size(), 1); ASSERT_TRUE(vect_indices[0].empty()); @@ -322,11 +328,11 @@ TEST_F(VariablesGroupTest, SingleDataWithInvalidPrefixAndBody) { TEST_F(VariablesGroupTest, SingleDataWithUnMatchedPrefix) { std::vector variables{ "PositiveUnsuppliedEnergy::area::hour<125>"}; - std::vector data{ - Outerloop::OuterLoopSingleInputData("UnsuppliedEnergy::", "test", - 1534.0)}; + std::vector data{ + Benders::Criterion::OuterLoopSingleInputData("UnsuppliedEnergy::", "test", + 1534.0)}; - Outerloop::VariablesGroup var_grp(variables, data); + Benders::Criterion::VariablesGroup var_grp(variables, data); const auto& vect_indices = var_grp.Indices(); ASSERT_EQ(vect_indices.size(), 1); ASSERT_TRUE(vect_indices[0].empty()); @@ -335,17 +341,17 @@ TEST_F(VariablesGroupTest, SingleDataWithUnMatchedPrefix) { TEST_F(VariablesGroupTest, SingleDataWithUnMatchedBody) { std::vector variables{ "PositiveUnsuppliedEnergy::area::hour<125>"}; - std::vector data{ - Outerloop::OuterLoopSingleInputData("PositiveUnsuppliedEnergy::", "Body", - 1534.0)}; + std::vector data{ + Benders::Criterion::OuterLoopSingleInputData( + "PositiveUnsuppliedEnergy::", "Body", 1534.0)}; - Outerloop::VariablesGroup var_grp(variables, data); + Benders::Criterion::VariablesGroup var_grp(variables, data); const auto& vect_indices = var_grp.Indices(); ASSERT_EQ(vect_indices.size(), 1); ASSERT_TRUE(vect_indices[0].empty()); } -static const std::vector data{ +static const std::vector data{ {"Blue::", "Earth", 1534.0}, {"Red::", "Mars", 65.0}}; TEST_F(VariablesGroupTest, With2ValidPatterns) { @@ -353,7 +359,7 @@ TEST_F(VariablesGroupTest, With2ValidPatterns) { "Gold::area::hour<9999>", "Blue::area::hour<125>", "Red::area::hour<1546>", "Blue::area::hour<3336>"}; - Outerloop::VariablesGroup var_grp(variables, data); + Benders::Criterion::VariablesGroup var_grp(variables, data); const auto& vect_indices = var_grp.Indices(); ASSERT_EQ(vect_indices.size(), 2); // 2 vars for the 1st pattern