22#ifdef STORM_HAVE_SOPLEX
24using namespace soplex;
26soplex::Rational to_soplex_rational(storm::RationalNumber
const& in) {
30storm::RationalNumber from_soplex_rational(soplex::Rational
const& r) {
34template<
typename ValueType,
bool RawMode>
36 if (std::is_same_v<ValueType, storm::RationalNumber>) {
37 solver.setIntParam(SoPlex::READMODE, SoPlex::READMODE_RATIONAL);
38 solver.setIntParam(SoPlex::SOLVEMODE, SoPlex::SOLVEMODE_RATIONAL);
39 solver.setIntParam(SoPlex::CHECKMODE, SoPlex::CHECKMODE_RATIONAL);
40 solver.setIntParam(SoPlex::SYNCMODE, SoPlex::SYNCMODE_AUTO);
41 solver.setRealParam(SoPlex::FEASTOL, 0.0);
42 solver.setRealParam(SoPlex::OPTTOL, 0.0);
44 solver.setIntParam(SoPlex::VERBOSITY, 0);
47template<
typename ValueType,
bool RawMode>
52template<
typename ValueType,
bool RawMode>
53SoplexLpSolver<ValueType, RawMode>::SoplexLpSolver(OptimizationDirection
const& optDir) : SoplexLpSolver(
"", optDir) {
57template<
typename ValueType,
bool RawMode>
58SoplexLpSolver<ValueType, RawMode>::~SoplexLpSolver() {}
60template<
typename ValueType,
bool RawMode>
61void SoplexLpSolver<ValueType, RawMode>::update()
const {
65template<
typename ValueType,
bool RawMode>
66typename SoplexLpSolver<ValueType, RawMode>::Variable SoplexLpSolver<ValueType, RawMode>::addVariable(std::string
const& name, VariableType
const& type,
67 std::optional<ValueType>
const& lowerBound,
68 std::optional<ValueType>
const& upperBound,
69 ValueType objectiveFunctionCoefficient) {
70 STORM_LOG_THROW(type == VariableType::Continuous, storm::exceptions::NotSupportedException,
"Soplex LP Solver only supports variables of continuous type.");
72 if constexpr (RawMode) {
73 resultVar = nextVariableIndex;
75 resultVar = this->declareOrGetExpressionVariable(name, type);
78 STORM_LOG_ASSERT(variableToIndexMap.count(resultVar) == 0,
"Variable " << resultVar.getName() <<
" exists already in the model.");
79 this->variableToIndexMap.emplace(resultVar, nextVariableIndex);
83 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
84 soplex::Rational
const rat_inf(soplex::infinity);
85 solver.addColRational(soplex::LPColRational(to_soplex_rational(objectiveFunctionCoefficient), variables,
86 upperBound.has_value() ? to_soplex_rational(*upperBound) : rat_inf,
87 lowerBound.has_value() ? to_soplex_rational(*lowerBound) : -rat_inf));
89 solver.addColReal(soplex::LPColReal(objectiveFunctionCoefficient, variables, upperBound.has_value() ? *upperBound : soplex::infinity,
90 lowerBound.has_value() ? *lowerBound : -soplex::infinity));
95template<
typename ValueType,
bool RawMode>
96void SoplexLpSolver<ValueType, RawMode>::addConstraint(std::string
const& name, Constraint
const& constraint) {
97 if constexpr (!RawMode) {
98 STORM_LOG_TRACE(
"Adding constraint " << (name ==
"" ? std::to_string(nextConstraintIndex) : name) <<
" to SoplexLpSolver:\n"
99 <<
"\t" << constraint);
101 using SoplexValueType = std::conditional_t<std::is_same_v<ValueType, storm::RationalNumber>, soplex::Rational, soplex::Real>;
105 TypedDSVector row(0);
106 if constexpr (RawMode) {
107 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
108 rhs = to_soplex_rational(constraint.rhs);
110 rhs = constraint.rhs;
112 relationType = constraint.relationType;
113 row = TypedDSVector(constraint.lhsVariableIndices.size());
114 auto varIt = constraint.lhsVariableIndices.cbegin();
115 auto varItEnd = constraint.lhsVariableIndices.cend();
116 auto coefIt = constraint.lhsCoefficients.cbegin();
117 for (; varIt != varItEnd; ++varIt, ++coefIt) {
118 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
119 row.add(*varIt, to_soplex_rational(*coefIt));
121 row.add(*varIt, *coefIt);
125 STORM_LOG_THROW(constraint.getManager() == this->getManager(), storm::exceptions::InvalidArgumentException,
126 "Constraint was not built over the proper variables.");
127 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
136 relationType = constraint.getBaseExpression().asBinaryRelationExpression().getRelationType();
137 row = TypedDSVector(std::distance(leftCoefficients.
begin(), leftCoefficients.
end()));
138 for (
auto const& variableCoefficientPair : leftCoefficients) {
139 auto variableIndexPair = this->variableToIndexMap.find(variableCoefficientPair.first);
140 row.add(variableIndexPair->second, leftCoefficients.getCoefficient(variableIndexPair->first));
145 SoplexValueType l, r;
146 switch (relationType) {
148 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"SoPlex only supports nonstrict inequalities.");
151 l = -soplex::infinity;
155 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"SoPlex only supports nonstrict inequalities.");
159 r = soplex::infinity;
168 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
169 solver.addRowRational(LPRowRational(l, row, r));
171 solver.addRowReal(LPRow(l, row, r));
175template<
typename ValueType,
bool RawMode>
176void SoplexLpSolver<ValueType, RawMode>::addIndicatorConstraint(std::string
const&, Variable,
bool, Constraint
const&) {
177 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"Indicator Constraints not supported for SoPlex.");
180template<
typename ValueType,
bool RawMode>
181void SoplexLpSolver<ValueType, RawMode>::optimize()
const {
185 if (this->getOptimizationDirection() == storm::solver::OptimizationDirection::Minimize) {
186 solver.setIntParam(SoPlex::OBJSENSE, SoPlex::OBJSENSE_MINIMIZE);
188 solver.setIntParam(SoPlex::OBJSENSE, SoPlex::OBJSENSE_MAXIMIZE);
191 status = solver.optimize();
193 if (status == soplex::SPxSolver::ERROR) {
194 STORM_LOG_THROW(
false, storm::exceptions::InternalException,
"Soplex failed.");
195 }
else if (status == soplex::SPxSolver::UNKNOWN) {
196 STORM_LOG_THROW(
false, storm::exceptions::InternalException,
"Soplex gives up on this problem.");
198 this->currentModelHasBeenOptimized =
true;
201template<
typename ValueType,
bool RawMode>
202bool SoplexLpSolver<ValueType, RawMode>::isInfeasible()
const {
203 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
204 "Illegal call to SoplexLpSolver<ValueType, RawMode>::isInfeasible: model has not been optimized.");
206 return (status == soplex::SPxSolver::INFEASIBLE);
209template<
typename ValueType,
bool RawMode>
210bool SoplexLpSolver<ValueType, RawMode>::isUnbounded()
const {
211 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
212 "Illegal call to SoplexLpSolver<ValueType, RawMode>::isUnbounded: model has not been optimized.");
214 return (status == soplex::SPxSolver::UNBOUNDED);
217template<
typename ValueType,
bool RawMode>
218bool SoplexLpSolver<ValueType, RawMode>::isOptimal()
const {
219 if (!this->currentModelHasBeenOptimized) {
222 return (status == soplex::SPxSolver::OPTIMAL);
225template<
typename ValueType,
bool RawMode>
226ValueType SoplexLpSolver<ValueType, RawMode>::getContinuousValue(Variable
const& variable)
const {
230 if constexpr (RawMode) {
233 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
234 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
235 varIndex = variableToIndexMap.at(variable);
237 STORM_LOG_ASSERT(varIndex < nextVariableIndex,
"Variable Index exceeds highest value.");
239 if (primalSolution.dim() == 0) {
240 primalSolution = TypedDVector(nextVariableIndex);
241 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
242 solver.getPrimalRational(primalSolution);
244 solver.getPrimal(primalSolution);
247 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
250 return primalSolution[varIndex];
255double SoplexLpSolver<double>::getObjectiveValue()
const {
257 return solver.objValueReal();
260template<
typename ValueType,
bool RawMode>
261ValueType SoplexLpSolver<ValueType, RawMode>::getObjectiveValue()
const {
266template<
typename ValueType,
bool RawMode>
267void SoplexLpSolver<ValueType, RawMode>::ensureSolved()
const {
268 if (!this->isOptimal()) {
269 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
"Unable to get Soplex solution from infeasible model.");
270 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
"Unable to get Soplex solution from unbounded model.");
271 STORM_LOG_THROW(
false, storm::exceptions::InvalidAccessException,
"Unable to get Soplex solution from unoptimized model.");
275template<
typename ValueType,
bool RawMode>
276void SoplexLpSolver<ValueType, RawMode>::writeModelToFile(std::string
const& filename)
const {
277 if constexpr (std::is_same_v<ValueType, storm::RationalNumber>) {
278 solver.writeFileRational(filename.c_str(),
nullptr,
nullptr,
nullptr);
280 solver.writeFileReal(filename.c_str(),
nullptr,
nullptr,
nullptr);
284template<
typename ValueType,
bool RawMode>
285void SoplexLpSolver<ValueType, RawMode>::push() {
286 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Push/Pop not supported on SoPlex.");
289template<
typename ValueType,
bool RawMode>
290void SoplexLpSolver<ValueType, RawMode>::pop() {
291 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Push/Pop not supported on SoPlex.");
295template<
typename ValueType,
bool RawMode>
298 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
299 "version of support with Soplex support.");
302template<
typename ValueType,
bool RawMode>
305 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
306 "version of support with Soplex support.");
309template<
typename ValueType,
bool RawMode>
312 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
313 "version of support with Soplex support.");
316template<
typename ValueType,
bool RawMode>
319template<
typename ValueType,
bool RawMode>
321 std::optional<ValueType>
const&,
322 std::optional<ValueType>
const&, ValueType) {
324 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
325 "version of support with Soplex support.");
328template<
typename ValueType,
bool RawMode>
331 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
332 "version of support with Soplex support.");
335template<
typename ValueType,
bool RawMode>
338 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
339 "version of support with Soplex support.");
342template<
typename ValueType,
bool RawMode>
345 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
346 "version of support with Soplex support.");
349template<
typename ValueType,
bool RawMode>
352 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
353 "version of support with Soplex support.");
356template<
typename ValueType,
bool RawMode>
359 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
360 "version of support with Soplex support.");
363template<
typename ValueType,
bool RawMode>
366 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
367 "version of support with Soplex support.");
370template<
typename ValueType,
bool RawMode>
373 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
374 "version of support with Soplex support.");
377template<
typename ValueType,
bool RawMode>
380 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
381 "version of support with Soplex support.");
384template<
typename ValueType,
bool RawMode>
387 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
388 "version of support with Soplex support.");
391template<
typename ValueType,
bool RawMode>
394 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
395 "version of support with Soplex support.");
398template<
typename ValueType,
bool RawMode>
401 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
402 "version of support with Soplex support.");
405template<
typename ValueType,
bool RawMode>
408 "This version of storm was compiled without support for Soplex. Yet, a method was called that requires this support. Please choose a "
409 "version of support with Soplex support.");
413template<
typename ValueType,
bool RawMode>
415 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"SoPlex does not support integer variables.");
418template<
typename ValueType,
bool RawMode>
420 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"SoPlex does not support binary variables.");
423template<
typename ValueType,
bool RawMode>
425 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"SoPlex does not support integer variables.");
428template<
typename ValueType,
bool RawMode>
430 STORM_LOG_THROW(
false, storm::exceptions::NotSupportedException,
"SoPlex does not support integer variables.");
VariableCoefficients getLinearCoefficients(Expression const &expression)
Computes the (double) coefficients of all identifiers appearing in the expression if the expression w...
An interface that captures the functionality of an LP solver.
typename LpSolver< ValueType, RawMode >::Variable Variable
virtual void pop() override
Pops a backtracking point from the solver's stack.
virtual ValueType getMILPGap(bool relative) const override
Returns the obtained gap after a call to optimize().
virtual ValueType getObjectiveValue() const override
Retrieves the value of the objective function.
virtual int_fast64_t getIntegerValue(Variable const &name) const override
Retrieves the value of the integer variable with the given name.
virtual void addIndicatorConstraint(std::string const &name, Variable indicatorVariable, bool indicatorValue, Constraint const &constraint) override
Adds the given indicator constraint to the LP problem: "If indicatorVariable == indicatorValue,...
virtual bool isInfeasible() const override
Retrieves whether the model was found to be infeasible.
SoplexLpSolver(std::string const &name, OptimizationDirection const &optDir)
Constructs a solver with the given name and model sense.
typename LpSolver< ValueType, RawMode >::VariableType VariableType
virtual bool isOptimal() const override
Retrieves whether the model was found to be optimal, i.e.
virtual void writeModelToFile(std::string const &filename) const override
Writes the current LP problem to the given file.
virtual bool isUnbounded() const override
Retrieves whether the model was found to be infeasible.
virtual void push() override
Pushes a backtracking point on the solver's stack.
virtual ~SoplexLpSolver()
Destructs a solver by freeing the pointers to Gurobi's structures.
virtual ValueType getContinuousValue(Variable const &name) const override
Retrieves the value of the continuous variable with the given name.
virtual Variable addVariable(std::string const &name, VariableType const &type, std::optional< ValueType > const &lowerBound=std::nullopt, std::optional< ValueType > const &upperBound=std::nullopt, ValueType objectiveFunctionCoefficient=0) override
virtual void addConstraint(std::string const &name, Constraint const &constraint) override
Adds a the given constraint to the LP problem.
virtual void update() const override
Updates the model to make the variables that have been declared since the last call to update usable.
virtual void optimize() const override
Optimizes the LP problem previously constructed.
virtual void setMaximalMILPGap(ValueType const &gap, bool relative) override
Specifies the maximum difference between lower- and upper objective bounds that triggers termination.
typename LpSolver< ValueType, RawMode >::Constraint Constraint
virtual bool getBinaryValue(Variable const &name) const override
Retrieves the value of the binary variable with the given name.
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
RelationType
An enum type specifying the different relations applicable.
TargetType convertNumber(SourceType const &number)
std::map< storm::expressions::Variable, double >::const_iterator end() const
void separateVariablesFromConstantPart(VariableCoefficients &rhs)
Brings all variables of the right-hand side coefficients to the left-hand side by negating them and m...
std::map< storm::expressions::Variable, double >::const_iterator begin() const
double getConstantPart() const