diff --git a/src/solver/infeasible-problem-analysis/constraint.cpp b/src/solver/infeasible-problem-analysis/constraint.cpp index 9d26f951aa..ba8788ebcc 100644 --- a/src/solver/infeasible-problem-analysis/constraint.cpp +++ b/src/solver/infeasible-problem-analysis/constraint.cpp @@ -1,6 +1,9 @@ #include #include "constraint.h" +#include +#include +#include namespace Antares { @@ -39,6 +42,48 @@ double Constraint::getSlackValue() const return mSlackValue; } +class StringIsNotWellFormated : public std::runtime_error +{ +public: + StringIsNotWellFormated(const std::string& error_message) : std::runtime_error(error_message) + { + } +}; + +std::string StringBetweenAngleBrackets(const std::string& str) +{ + const auto& begin = str.begin(); + const auto& end = str.end(); + + auto left = std::find(begin, end, '<'); + + if (left == end) + { + std::ostringstream stream; + stream << std::string("Error the string: ") << std::quoted(str) + << " does not contains the left angle bracket " << std::quoted("<"); + throw StringIsNotWellFormated(stream.str()); + } + + auto right = std::find(begin, end, '>'); + if (right == end) + { + std::ostringstream stream; + stream << std::string("Error the string: ") << std::quoted(str) + << " does not contains the right angle bracket " << std::quoted(">"); + throw StringIsNotWellFormated(stream.str()); + } + + if (std::distance(left, right) <= 1) + { + std::ostringstream stream; + stream << std::string("Error the string: ") << std::quoted(str) << " must be of format " + << std::quoted("**"); + throw StringIsNotWellFormated(stream.str()); + } + return std::string(left + 1, right); +} + std::string Constraint::getAreaName() const { if ((getType() == ConstraintType::binding_constraint_hourly) @@ -47,7 +92,7 @@ std::string Constraint::getAreaName() const { return ""; } - return mItems.at(2); + return StringBetweenAngleBrackets(mItems.at(1)); } std::string Constraint::getTimeStepInYear() const @@ -56,44 +101,34 @@ std::string Constraint::getTimeStepInYear() const { case ConstraintType::binding_constraint_hourly: case ConstraintType::binding_constraint_daily: - return mItems.at(2); case ConstraintType::fictitious_load: case ConstraintType::hydro_reservoir_level: - return mItems.at(1); + return StringBetweenAngleBrackets (mItems.at(mItems.size()-2)); default: return "-1"; } } -static ConstraintType bindingConstraintPeriodicity(const std::string& in) +ConstraintType Constraint::getType() const { - if (in == "hourly") + assert(mItems.size() > 1); + if (mItems.at(1) == "hourly") { return ConstraintType::binding_constraint_hourly; } - if (in == "daily") + if (mItems.at(1) == "daily") { return ConstraintType::binding_constraint_daily; } - if (in == "weekly") + if (mItems.at(1) == "weekly") { return ConstraintType::binding_constraint_weekly; } - return ConstraintType::none; -} - -ConstraintType Constraint::getType() const -{ - assert(mItems.size() > 1); - if (mItems.at(0) == "bc") - { - return bindingConstraintPeriodicity(mItems.at(1)); - } - if (mItems.at(0) == "fict_load") + if (mItems.at(0) == "FictiveLoads") { return ConstraintType::fictitious_load; } - if (mItems.at(0) == "hydro_level") + if (mItems.at(0) == "AreaHydroLevel") { return ConstraintType::hydro_reservoir_level; } @@ -106,9 +141,8 @@ std::string Constraint::getBindingConstraintName() const { case ConstraintType::binding_constraint_hourly: case ConstraintType::binding_constraint_daily: - return mItems.at(3); case ConstraintType::binding_constraint_weekly: - return mItems.at(2); + return mItems.at(0); default: return ""; } diff --git a/src/solver/infeasible-problem-analysis/problem.cpp b/src/solver/infeasible-problem-analysis/problem.cpp index f1178aeedb..c6d399b568 100644 --- a/src/solver/infeasible-problem-analysis/problem.cpp +++ b/src/solver/infeasible-problem-analysis/problem.cpp @@ -13,7 +13,8 @@ namespace Optimization { InfeasibleProblemAnalysis::InfeasibleProblemAnalysis(const std::string& solverName, const PROBLEME_SIMPLEXE_NOMME* ProbSpx) { - mSolver = std::unique_ptr(convert_to_MPSolver(solverName, ProbSpx)); + mSolver + = std::unique_ptr(ProblemSimplexeNommeConverter(solverName, ProbSpx).Convert()); } void InfeasibleProblemAnalysis::addSlackVariables() @@ -25,11 +26,11 @@ void InfeasibleProblemAnalysis::addSlackVariables() */ const unsigned int selectedConstraintsInverseRatio = 3; mSlackVariables.reserve(mSolver->NumConstraints() / selectedConstraintsInverseRatio); - std::regex rgx(mPattern); + std::regex rgx(constraint_name_pattern); const double infinity = MPSolver::infinity(); for (MPConstraint* constraint : mSolver->constraints()) { - if (std::regex_match(constraint->name(), rgx)) + if (std::regex_search(constraint->name(), rgx)) { if (constraint->lb() != -infinity) { diff --git a/src/solver/infeasible-problem-analysis/problem.h b/src/solver/infeasible-problem-analysis/problem.h index 209f8eda7d..d0e277492a 100644 --- a/src/solver/infeasible-problem-analysis/problem.h +++ b/src/solver/infeasible-problem-analysis/problem.h @@ -25,7 +25,8 @@ class InfeasibleProblemAnalysis std::unique_ptr mSolver; std::vector mSlackVariables; - const std::string mPattern = ".+::.+"; + const std::string constraint_name_pattern = "^AreaHydroLevel::|::hourly::|::daily::|::weekly::|^FictiveLoads::"; + }; } // namespace Optimization } // namespace Antares diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp index f0e4f9fad3..68eff04d82 100644 --- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp +++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp @@ -301,7 +301,8 @@ bool OPT_AppelDuSimplexe(const OptimizationOptions& options, Optimization::PROBLEME_SIMPLEXE_NOMME Probleme(ProblemeAResoudre->NomDesVariables, ProblemeAResoudre->NomDesContraintes, ProblemeAResoudre->StatutDesVariables, - ProblemeAResoudre->StatutDesContraintes); + ProblemeAResoudre->StatutDesContraintes, + problemeHebdo->NamedProblems); auto solver = (MPSolver*)(ProblemeAResoudre->ProblemesSpx[(int)NumIntervalle]); @@ -375,6 +376,7 @@ bool OPT_AppelDuSimplexe(const OptimizationOptions& options, logs.info() << " Solver: Safe resolution failed"; } + Probleme.SetUseNamedProblems(true); Optimization::InfeasibleProblemAnalysis analysis(options.solverName, &Probleme); logs.notice() << " Solver: Starting infeasibility analysis..."; try diff --git a/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp b/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp index 69f2f97f5d..42da4c6329 100644 --- a/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp @@ -46,8 +46,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( std::vector& Pi = ProblemeAResoudre->Pi; std::vector& Colonne = ProblemeAResoudre->Colonne; - ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes, - problemeHebdo->NamedProblems); + ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes); int nbTermesContraintesPourLesCoutsDeDemarrage = 0; for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) { diff --git a/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp b/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp index d52fc1dbc2..7af466cc06 100644 --- a/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp @@ -171,8 +171,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaire(PROBLEME_HEBDO* pro ProblemeAResoudre->NombreDeContraintes = 0; ProblemeAResoudre->NombreDeTermesDansLaMatriceDesContraintes = 0; - ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes, - problemeHebdo->NamedProblems); + ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes); for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) { diff --git a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp index 764119e32b..60b5c508a5 100644 --- a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp +++ b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp @@ -43,7 +43,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra int nombreDePasDeTempsPourUneOptimisation = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; int nombreDeVariables = ProblemeAResoudre->NombreDeVariables; - VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables, problemeHebdo->NamedProblems); + VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables); for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) { variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index 5378fb1b8d..050f3e8c32 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -38,7 +38,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD int NombreDePasDeTempsPourUneOptimisation = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; int NombreDeVariables = 0; - VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables, problemeHebdo->NamedProblems); + VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables); for (int pdt = 0; pdt < NombreDePasDeTempsPourUneOptimisation; pdt++) { diff --git a/src/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/opt_rename_problem.h index 6c19a3e415..bd392a1ba5 100644 --- a/src/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/opt_rename_problem.h @@ -8,29 +8,25 @@ const std::string AREA_SEP = "$$"; class TargetVectorUpdater { public: - TargetVectorUpdater(bool isRenamingProcessed, std::vector& target) : - target_(target), isRenamingProcessed_(isRenamingProcessed) + TargetVectorUpdater(std::vector& target) : + target_(target) { } void UpdateTargetAtIndex(const std::string& full_name, unsigned int index) { - if (isRenamingProcessed_) - { - target_[index] = full_name; - } + target_[index] = full_name; } private: std::vector& target_; - bool isRenamingProcessed_; }; class Namer { public: - Namer(std::vector& target, bool namedProblems) : - targetUpdater_(namedProblems, target) + Namer(std::vector& target) : + targetUpdater_(target) { } diff --git a/src/solver/utils/CMakeLists.txt b/src/solver/utils/CMakeLists.txt index 5d4bfd160a..aa1a8026f2 100644 --- a/src/solver/utils/CMakeLists.txt +++ b/src/solver/utils/CMakeLists.txt @@ -7,6 +7,8 @@ set(SRC named_problem.cpp mps_utils.h mps_utils.cpp + name_translator.h + name_translator.cpp opt_period_string_generator.h opt_period_string_generator.cpp ) diff --git a/src/solver/utils/mps_utils.cpp b/src/solver/utils/mps_utils.cpp index 7d7cb52b1d..cc63f4922b 100644 --- a/src/solver/utils/mps_utils.cpp +++ b/src/solver/utils/mps_utils.cpp @@ -49,24 +49,16 @@ constexpr size_t OPT_APPEL_SOLVEUR_BUFFER_SIZE = 256; #include #include "filename.h" #include "../optimisation/opt_constants.h" +#include "name_translator.h" using namespace Yuni; #define SEP IO::Separator -static char** VectorOfStringToCharPP(std::vector& in, std::vector& pointerVec) -{ - std::transform(in.begin(), - in.end(), - std::back_inserter(pointerVec), - [](std::string& str) { return str.empty() ? nullptr : str.data(); }); - return pointerVec.data(); -} - class ProblemConverter { public: - void copyProbSimplexeToProbMps(PROBLEME_MPS* dest, PROBLEME_SIMPLEXE_NOMME* src) + void copyProbSimplexeToProbMps(PROBLEME_MPS* dest, PROBLEME_SIMPLEXE_NOMME* src, NameTranslator& nameTranslator) { // Variables dest->NbVar = src->NombreDeVariables; @@ -94,8 +86,8 @@ class ProblemConverter dest->SensDeLaContrainte = src->Sens; // Names - dest->LabelDeLaVariable = VectorOfStringToCharPP(src->NomDesVariables, mVariableNames); - dest->LabelDeLaContrainte = VectorOfStringToCharPP(src->NomDesContraintes, mConstraintNames); + dest->LabelDeLaVariable = nameTranslator.translate(src->VariableNames(), mVariableNames); + dest->LabelDeLaContrainte = nameTranslator.translate(src->ConstraintNames(), mConstraintNames); } private: @@ -114,9 +106,10 @@ void OPT_EcrireJeuDeDonneesLineaireAuFormatMPS(PROBLEME_SIMPLEXE_NOMME* Prob, auto mps = std::make_shared(); { + auto translator = NameTranslator::create(Prob->UseNamedProblems()); ProblemConverter converter; // This object must not be destroyed until SRSwritempsprob has been run - converter.copyProbSimplexeToProbMps(mps.get(), Prob); + converter.copyProbSimplexeToProbMps(mps.get(), Prob, *translator); SRSwritempsprob(mps.get(), tmpPath.c_str()); } diff --git a/src/solver/utils/name_translator.cpp b/src/solver/utils/name_translator.cpp new file mode 100644 index 0000000000..6c3374fee1 --- /dev/null +++ b/src/solver/utils/name_translator.cpp @@ -0,0 +1,28 @@ +#include "name_translator.h" +#include +#include + +char** RealName::translate(const std::vector& src, + std::vector& pointerVec) +{ + std::transform(src.begin(), + src.end(), + std::back_inserter(pointerVec), + [](const std::string& str) { return str.empty() ? nullptr : const_cast(str.data()); }); + return pointerVec.data(); +} + +char** NullName::translate(const std::vector& src, + std::vector& pointerVec) +{ + pointerVec.assign(src.size(), nullptr); + return pointerVec.data(); +} + +std::unique_ptr NameTranslator::create(bool useRealNames) +{ + if (useRealNames) + return std::make_unique(); + else + return std::make_unique(); +} diff --git a/src/solver/utils/name_translator.h b/src/solver/utils/name_translator.h new file mode 100644 index 0000000000..a179bf1caf --- /dev/null +++ b/src/solver/utils/name_translator.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +class NameTranslator +{ +public: + virtual char** translate(const std::vector& src, + std::vector& pointerVec) = 0; + static std::unique_ptr create(bool useRealNames); +}; + +class RealName : public NameTranslator +{ + char** translate(const std::vector& src, + std::vector& pointerVec) override; +}; + +class NullName : public NameTranslator +{ + char** translate(const std::vector& src, + std::vector& pointerVec) override; +}; diff --git a/src/solver/utils/named_problem.cpp b/src/solver/utils/named_problem.cpp index 7f22c0c02e..984e678bc6 100644 --- a/src/solver/utils/named_problem.cpp +++ b/src/solver/utils/named_problem.cpp @@ -10,12 +10,14 @@ namespace Optimization PROBLEME_SIMPLEXE_NOMME::PROBLEME_SIMPLEXE_NOMME(const std::vector& NomDesVariables, const std::vector& NomDesContraintes, std::vector& StatutDesVariables, - std::vector& StatutDesContraintes) : + std::vector& StatutDesContraintes, + bool UseNamedProblems) : NomDesVariables(NomDesVariables), NomDesContraintes(NomDesContraintes), StatutDesVariables(StatutDesVariables), - StatutDesContraintes(StatutDesContraintes) + StatutDesContraintes(StatutDesContraintes), + useNamedProblems_(UseNamedProblems) { } diff --git a/src/solver/utils/named_problem.h b/src/solver/utils/named_problem.h index 9c393b9a07..7e749e29ee 100644 --- a/src/solver/utils/named_problem.h +++ b/src/solver/utils/named_problem.h @@ -5,6 +5,8 @@ #include #include +#include +#include namespace Antares { @@ -16,15 +18,40 @@ struct PROBLEME_SIMPLEXE_NOMME : public PROBLEME_SIMPLEXE PROBLEME_SIMPLEXE_NOMME(const std::vector& NomDesVariables, const std::vector& NomDesContraintes, std::vector& StatutDesVariables, - std::vector& StatutDesContraintes); + std::vector& StatutDesContraintes, + bool UseNamedProblems); - std::vector NomDesVariables; - std::vector NomDesContraintes; +private: + const std::vector& NomDesVariables; + const std::vector& NomDesContraintes; + bool useNamedProblems_; + +public: std::vector& StatutDesVariables; std::vector& StatutDesContraintes; bool isMIP() const; bool basisExists() const; + + bool UseNamedProblems() const + { + return useNamedProblems_; + } + + void SetUseNamedProblems(bool useNamedProblems) + { + useNamedProblems_ = useNamedProblems; + } + + const std::vector& VariableNames() const + { + return NomDesVariables; + } + + const std::vector& ConstraintNames() const + { + return NomDesContraintes; + } }; } // namespace Optimization } // namespace Antares diff --git a/src/solver/utils/ortools_utils.cpp b/src/solver/utils/ortools_utils.cpp index d58025d968..e20c38d84e 100644 --- a/src/solver/utils/ortools_utils.cpp +++ b/src/solver/utils/ortools_utils.cpp @@ -10,102 +10,57 @@ using namespace operations_research; const char* const XPRESS_PARAMS = "THREADS 1"; -static void transferVariables(MPSolver* solver, - const double* bMin, - const double* bMax, - const double* costs, - int nbVar, - const std::vector& NomDesVariables) +// MPSolverParameters's copy constructor is private +static void setGenericParameters(MPSolverParameters& params) { - MPObjective* const objective = solver->MutableObjective(); - for (int idxVar = 0; idxVar < nbVar; ++idxVar) - { - double min_l = 0.0; - if (bMin != NULL) - { - min_l = bMin[idxVar]; - } - double max_l = bMax[idxVar]; - std::string varName; - if (NomDesVariables[idxVar].empty()) - { - varName = "x" + std::to_string(idxVar); - } - else - { - varName = NomDesVariables[idxVar]; - } - const MPVariable* var = solver->MakeNumVar(min_l, max_l, varName); - objective->SetCoefficient(var, costs[idxVar]); - } + params.SetIntegerParam(MPSolverParameters::SCALING, 0); + params.SetIntegerParam(MPSolverParameters::PRESOLVE, 0); } -static void transferRows(MPSolver* solver, - const double* rhs, - const char* sens, - int nbRow, - const std::vector& NomDesContraintes) +static bool solverSupportsWarmStart(const MPSolver::OptimizationProblemType solverType) { - for (int idxRow = 0; idxRow < nbRow; ++idxRow) + switch (solverType) { - double bMin = -MPSolver::infinity(), bMax = MPSolver::infinity(); - if (sens[idxRow] == '=') - { - bMin = bMax = rhs[idxRow]; - } - else if (sens[idxRow] == '<') - { - bMax = rhs[idxRow]; - } - else if (sens[idxRow] == '>') - { - bMin = rhs[idxRow]; - } - - std::string constraintName; - if (NomDesContraintes[idxRow].empty()) - { - constraintName = "c" + std::to_string(idxRow); - } - else - { - constraintName = NomDesContraintes[idxRow]; - } - - solver->MakeRowConstraint(bMin, bMax, constraintName); + case MPSolver::XPRESS_LINEAR_PROGRAMMING: + return true; + default: + return false; } } -static void transferMatrix(const MPSolver* solver, - const int* indexRows, - const int* terms, - const int* indexCols, - const double* coeffs, - int nbRow) +namespace Antares { - auto variables = solver->variables(); - auto constraints = solver->constraints(); - - for (int idxRow = 0; idxRow < nbRow; ++idxRow) +namespace Optimization +{ +ProblemSimplexeNommeConverter::ProblemSimplexeNommeConverter( + const std::string& solverName, + const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) : + solverName_(solverName), problemeSimplexe_(problemeSimplexe) +{ + if (problemeSimplexe_->UseNamedProblems()) { - MPConstraint* const ct = constraints[idxRow]; - int debutLigne = indexRows[idxRow]; - for (int idxCoef = 0; idxCoef < terms[idxRow]; ++idxCoef) - { - int pos = debutLigne + idxCoef; - ct->SetCoefficient(variables[indexCols[pos]], coeffs[pos]); - } + variableNameManager_.SetTarget(problemeSimplexe_->VariableNames()); + constraintNameManager_.SetTarget(problemeSimplexe_->ConstraintNames()); } } -// MPSolverParameters's copy constructor is private -static void setGenericParameters(MPSolverParameters& params) +MPSolver* ProblemSimplexeNommeConverter::Convert() { - params.SetIntegerParam(MPSolverParameters::SCALING, 0); - params.SetIntegerParam(MPSolverParameters::PRESOLVE, 0); + MPSolver* solver = MPSolverFactory(problemeSimplexe_, solverName_); + TuneSolverSpecificOptions(solver); + + // Create the variables and set objective cost. + CopyVariables(solver); + + // Create constraints and set coefs + CopyRows(solver); + + CopyMatrix(solver); + + return solver; } -static void tuneSolverSpecificOptions(MPSolver* solver) +void ProblemSimplexeNommeConverter::TuneSolverSpecificOptions(MPSolver* solver) const { if (!solver) return; @@ -122,53 +77,77 @@ static void tuneSolverSpecificOptions(MPSolver* solver) } } -static bool solverSupportsWarmStart(const MPSolver::OptimizationProblemType solverType) +void ProblemSimplexeNommeConverter::CopyMatrix(const MPSolver* solver) { - switch (solverType) + auto variables = solver->variables(); + auto constraints = solver->constraints(); + + for (int idxRow = 0; idxRow < problemeSimplexe_->NombreDeContraintes; ++idxRow) { - case MPSolver::XPRESS_LINEAR_PROGRAMMING: - return true; - default: - return false; + MPConstraint* const ct = constraints[idxRow]; + int debutLigne = problemeSimplexe_->IndicesDebutDeLigne[idxRow]; + for (int idxCoef = 0; idxCoef < problemeSimplexe_->NombreDeTermesDesLignes[idxRow]; + ++idxCoef) + { + int pos = debutLigne + idxCoef; + ct->SetCoefficient(variables[problemeSimplexe_->IndicesColonnes[pos]], + problemeSimplexe_->CoefficientsDeLaMatriceDesContraintes[pos]); + } } } -namespace Antares -{ -namespace Optimization +void ProblemSimplexeNommeConverter::UpdateCoefficient(unsigned idxVar, + MPSolver* solver, + MPObjective* const objective) { -MPSolver* convert_to_MPSolver( - const std::string& solverName, - const PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) + double min_l = 0.0; + if (problemeSimplexe_->Xmin != NULL) + { + min_l = problemeSimplexe_->Xmin[idxVar]; + } + double max_l = problemeSimplexe_->Xmax[idxVar]; + const MPVariable* var = solver->MakeNumVar(min_l, max_l, variableNameManager_.GetName(idxVar)); + objective->SetCoefficient(var, problemeSimplexe_->CoutLineaire[idxVar]); +} + +void ProblemSimplexeNommeConverter::CopyVariables(MPSolver* solver) + { - // Create the MPSolver - MPSolver* solver = MPSolverFactory(problemeSimplexe, solverName); + MPObjective* const objective = solver->MutableObjective(); - tuneSolverSpecificOptions(solver); + for (int idxVar = 0; idxVar < problemeSimplexe_->NombreDeVariables; ++idxVar) + { + UpdateCoefficient(idxVar, solver, objective); + } +} - // Create the variables and set objective cost. - transferVariables(solver, - problemeSimplexe->Xmin, - problemeSimplexe->Xmax, - problemeSimplexe->CoutLineaire, - problemeSimplexe->NombreDeVariables, - problemeSimplexe->NomDesVariables); +void ProblemSimplexeNommeConverter::UpdateContraints(unsigned idxRow, MPSolver* solver) +{ + double bMin = -MPSolver::infinity(), bMax = MPSolver::infinity(); + if (problemeSimplexe_->Sens[idxRow] == '=') + { + bMin = bMax = problemeSimplexe_->SecondMembre[idxRow]; + } + else if (problemeSimplexe_->Sens[idxRow] == '<') + { + bMax = problemeSimplexe_->SecondMembre[idxRow]; + } + else if (problemeSimplexe_->Sens[idxRow] == '>') + { + bMin = problemeSimplexe_->SecondMembre[idxRow]; + } - // Create constraints and set coefs - transferRows(solver, - problemeSimplexe->SecondMembre, - problemeSimplexe->Sens, - problemeSimplexe->NombreDeContraintes, - problemeSimplexe->NomDesContraintes); - transferMatrix(solver, - problemeSimplexe->IndicesDebutDeLigne, - problemeSimplexe->NombreDeTermesDesLignes, - problemeSimplexe->IndicesColonnes, - problemeSimplexe->CoefficientsDeLaMatriceDesContraintes, - problemeSimplexe->NombreDeContraintes); + solver->MakeRowConstraint(bMin, bMax, constraintNameManager_.GetName(idxRow)); +} - return solver; +void ProblemSimplexeNommeConverter::CopyRows(MPSolver* solver) +{ + for (int idxRow = 0; idxRow < problemeSimplexe_->NombreDeContraintes; ++idxRow) + { + UpdateContraints(idxRow, solver); + } } + } // namespace Optimization } // namespace Antares @@ -263,7 +242,7 @@ MPSolver* ORTOOLS_ConvertIfNeeded(const std::string& solverName, { if (solver == nullptr) { - return Antares::Optimization::convert_to_MPSolver(solverName, Probleme); + return Antares::Optimization::ProblemSimplexeNommeConverter(solverName, Probleme).Convert(); } else { diff --git a/src/solver/utils/ortools_utils.h b/src/solver/utils/ortools_utils.h index e3f0987834..3ec59ef13d 100644 --- a/src/solver/utils/ortools_utils.h +++ b/src/solver/utils/ortools_utils.h @@ -47,8 +47,56 @@ namespace Antares { namespace Optimization { -MPSolver* convert_to_MPSolver( - const std::string& solverName, - const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe); -} + +class Nomenclature +{ +public: + Nomenclature() = delete; + + explicit Nomenclature(char prefix) : prefix_(prefix) + { + } + + void SetTarget(const std::vector& target) + { + target_ = ⌖ + } + + std::string GetName(unsigned index) const + { + if (target_ == nullptr || target_->at(index).empty()) + { + return prefix_ + std::to_string(index); + } + return target_->at(index); + } + +private: + const std::vector* target_ = nullptr; + char prefix_; +}; + +class ProblemSimplexeNommeConverter +{ +public: + explicit ProblemSimplexeNommeConverter( + const std::string& solverName, + const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe); + + MPSolver* Convert(); + +private: + const std::string& solverName_; + const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe_; + Nomenclature variableNameManager_ = Nomenclature('x'); + Nomenclature constraintNameManager_ = Nomenclature('c'); + + void UpdateCoefficient(unsigned idxVar, MPSolver* solver, MPObjective* const objective); + void CopyVariables(MPSolver* solver); + void UpdateContraints(unsigned idxRow, MPSolver* solver); + void CopyRows(MPSolver* solver); + void TuneSolverSpecificOptions(MPSolver* solver) const; + void CopyMatrix(const MPSolver* solver); +}; +} // namespace Optimization } // namespace Antares