Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unfeasible problem analyzer #1527

Merged
merged 18 commits into from
Sep 14, 2023
Merged
47 changes: 26 additions & 21 deletions src/solver/infeasible-problem-analysis/constraint.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <cassert>

#include "constraint.h"
#include <sstream>

namespace Antares
{
Expand Down Expand Up @@ -38,6 +39,21 @@ double Constraint::getSlackValue() const
{
return mSlackValue;
}
std::vector<std::string> split(const std::string& s, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}

std::string StringBetweenAngleBrackets(const std::string& str){
return split(split(str, '<')[1], '>')[0];
}

std::string Constraint::getAreaName() const
{
Expand All @@ -47,7 +63,7 @@ std::string Constraint::getAreaName() const
{
return "<none>";
}
return mItems.at(2);
return StringBetweenAngleBrackets(mItems.at(1));
}

std::string Constraint::getTimeStepInYear() const
Expand All @@ -56,44 +72,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;
}
Expand All @@ -106,9 +112,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 "<unknown>";
}
Expand Down
7 changes: 4 additions & 3 deletions src/solver/infeasible-problem-analysis/problem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ namespace Optimization
{
InfeasibleProblemAnalysis::InfeasibleProblemAnalysis(const std::string& solverName, const PROBLEME_SIMPLEXE_NOMME* ProbSpx)
{
mSolver = std::unique_ptr<MPSolver>(convert_to_MPSolver(solverName, ProbSpx));
mSolver
= std::unique_ptr<MPSolver>(ProblemSimplexeNommeConverter(solverName, ProbSpx).Convert());
}

void InfeasibleProblemAnalysis::addSlackVariables()
Expand All @@ -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)
{
Expand Down
3 changes: 2 additions & 1 deletion src/solver/infeasible-problem-analysis/problem.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class InfeasibleProblemAnalysis

std::unique_ptr<operations_research::MPSolver> mSolver;
std::vector<const operations_research::MPVariable*> mSlackVariables;
const std::string mPattern = ".+::.+";
const std::string constraint_name_pattern = "^AreaHydroLevel::|::hourly::|::daily::|::weekly::|^FictiveLoads::";

};
} // namespace Optimization
} // namespace Antares
4 changes: 3 additions & 1 deletion src/solver/optimisation/opt_appel_solveur_lineaire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage(

std::vector<double>& Pi = ProblemeAResoudre->Pi;
std::vector<int>& 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++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
{
Expand Down
14 changes: 5 additions & 9 deletions src/solver/optimisation/opt_rename_problem.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,25 @@ const std::string AREA_SEP = "$$";
class TargetVectorUpdater
{
public:
TargetVectorUpdater(bool isRenamingProcessed, std::vector<std::string>& target) :
target_(target), isRenamingProcessed_(isRenamingProcessed)
TargetVectorUpdater(std::vector<std::string>& 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<std::string>& target_;
bool isRenamingProcessed_;
};

class Namer
{
public:
Namer(std::vector<std::string>& target, bool namedProblems) :
targetUpdater_(namedProblems, target)
Namer(std::vector<std::string>& target) :
targetUpdater_(target)
{
}

Expand Down
2 changes: 2 additions & 0 deletions src/solver/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
19 changes: 6 additions & 13 deletions src/solver/utils/mps_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,16 @@ constexpr size_t OPT_APPEL_SOLVEUR_BUFFER_SIZE = 256;
#include <algorithm>
#include "filename.h"
#include "../optimisation/opt_constants.h"
#include "name_translator.h"

using namespace Yuni;

#define SEP IO::Separator

static char** VectorOfStringToCharPP(std::vector<std::string>& in, std::vector<char*>& 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;
Expand Down Expand Up @@ -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:
Expand All @@ -114,9 +106,10 @@ void OPT_EcrireJeuDeDonneesLineaireAuFormatMPS(PROBLEME_SIMPLEXE_NOMME* Prob,

auto mps = std::make_shared<PROBLEME_MPS>();
{
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());
}

Expand Down
28 changes: 28 additions & 0 deletions src/solver/utils/name_translator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "name_translator.h"
#include <algorithm>
#include <iterator>

char** RealName::translate(const std::vector<std::string>& src,
std::vector<char*>& pointerVec)
{
std::transform(src.begin(),
src.end(),
std::back_inserter(pointerVec),
[](const std::string& str) { return str.empty() ? nullptr : const_cast<char*>(str.data()); });
return pointerVec.data();
}

char** NullName::translate(const std::vector<std::string>& src,
std::vector<char*>& pointerVec)
{
pointerVec.assign(src.size(), nullptr);
return pointerVec.data();
}

std::unique_ptr<NameTranslator> NameTranslator::create(bool useRealNames)
{
if (useRealNames)
return std::make_unique<RealName>();
else
return std::make_unique<NullName>();
}
25 changes: 25 additions & 0 deletions src/solver/utils/name_translator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <vector>
#include <string>
#include <memory>

class NameTranslator
{
public:
virtual char** translate(const std::vector<std::string>& src,
std::vector<char*>& pointerVec) = 0;
static std::unique_ptr<NameTranslator> create(bool useRealNames);
};

class RealName : public NameTranslator
{
char** translate(const std::vector<std::string>& src,
std::vector<char*>& pointerVec) override;
};

class NullName : public NameTranslator
{
char** translate(const std::vector<std::string>& src,
std::vector<char*>& pointerVec) override;
};
6 changes: 4 additions & 2 deletions src/solver/utils/named_problem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ namespace Optimization
PROBLEME_SIMPLEXE_NOMME::PROBLEME_SIMPLEXE_NOMME(const std::vector<std::string>& NomDesVariables,
const std::vector<std::string>& NomDesContraintes,
std::vector<int>& StatutDesVariables,
std::vector<int>& StatutDesContraintes) :
std::vector<int>& StatutDesContraintes,
bool UseNamedProblems) :

NomDesVariables(NomDesVariables),
NomDesContraintes(NomDesContraintes),
StatutDesVariables(StatutDesVariables),
StatutDesContraintes(StatutDesContraintes)
StatutDesContraintes(StatutDesContraintes),
useNamedProblems_(UseNamedProblems)
{
}

Expand Down
Loading