25template<
typename ValueType,
bool RawMode>
29 config.set(
"model",
true);
30 context = std::make_unique<z3::context>(config);
31 solver = std::make_unique<z3::optimize>(*context);
32 expressionAdapter = std::make_unique<storm::adapters::Z3ExpressionAdapter>(*this->manager, *context);
35template<
typename ValueType,
bool RawMode>
40template<
typename ValueType,
bool RawMode>
41Z3LpSolver<ValueType, RawMode>::Z3LpSolver(OptimizationDirection
const& optDir) : Z3LpSolver(
"", optDir) {
45template<
typename ValueType,
bool RawMode>
50template<
typename ValueType,
bool RawMode>
51Z3LpSolver<ValueType, RawMode>::~Z3LpSolver() {
55template<
typename ValueType,
bool RawMode>
56void Z3LpSolver<ValueType, RawMode>::update()
const {
58 lastCheckObjectiveValue.reset(
nullptr);
59 lastCheckModel.reset(
nullptr);
60 this->currentModelHasBeenOptimized =
false;
63template<
typename ValueType,
bool RawMode>
64typename Z3LpSolver<ValueType, RawMode>::Variable Z3LpSolver<ValueType, RawMode>::addVariable(std::string
const& name, VariableType
const& type,
65 std::optional<ValueType>
const& lowerBound,
66 std::optional<ValueType>
const& upperBound,
67 ValueType objectiveFunctionCoefficient) {
68 STORM_LOG_ASSERT(isIncremental || !this->
manager->hasVariable(name),
"Variable with name " << name <<
" already exists.");
70 if (type == VariableType::Binary) {
71 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() >= this->manager->integer(0)));
72 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() <= this->manager->integer(1)));
75 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() >= this->manager->rational(*lowerBound)));
78 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() <= this->manager->rational(*upperBound)));
81 optimizationSummands.push_back(this->
manager->rational(objectiveFunctionCoefficient) * newVariable);
84 if constexpr (RawMode) {
85 rawIndexToVariableMap.push_back(newVariable);
86 return rawIndexToVariableMap.size() - 1;
92template<
typename ValueType,
bool RawMode>
93void Z3LpSolver<ValueType, RawMode>::addConstraint(std::string
const& name, Constraint
const& constraint) {
94 if constexpr (RawMode) {
96 STORM_LOG_ASSERT(constraint.lhsVariableIndices.size() == constraint.lhsCoefficients.size(),
"Number of variables and coefficients do not match.");
97 std::vector<storm::expressions::Expression> lhsSummands;
98 lhsSummands.reserve(constraint.lhsVariableIndices.size());
99 auto varIt = constraint.lhsVariableIndices.cbegin();
100 auto varItEnd = constraint.lhsVariableIndices.cend();
101 auto coefIt = constraint.lhsCoefficients.cbegin();
102 for (; varIt != varItEnd; ++varIt, ++coefIt) {
103 lhsSummands.push_back(rawIndexToVariableMap[*varIt] * this->
manager->rational(*coefIt));
105 if (lhsSummands.empty()) {
110 solver->add(expressionAdapter->translateExpression(constraintExpr));
112 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
114 "Illegal constraint uses inequality operator.");
115 solver->add(expressionAdapter->translateExpression(constraint));
119template<
typename ValueType,
bool RawMode>
120void Z3LpSolver<ValueType, RawMode>::addIndicatorConstraint(std::string
const& name, Variable indicatorVariable,
bool indicatorValue,
121 Constraint
const& constraint) {
122 if constexpr (RawMode) {
123 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Indicator constraints not implemented in RawMode.");
126 STORM_LOG_THROW(indicatorVariable.hasIntegerType(), storm::exceptions::InvalidArgumentException,
127 "Variable " << indicatorVariable.getName() <<
" is not binary.");
128 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
130 "Illegal constraint uses inequality operator.");
134 auto indicatorConstraint = (indicatorVariable.getExpression() == invertedIndicatorVal) || constraint;
135 solver->add(expressionAdapter->translateExpression(indicatorConstraint));
139template<
typename ValueType,
bool RawMode>
140void Z3LpSolver<ValueType, RawMode>::optimize()
const {
149 if (!optimizationSummands.empty()) {
152 z3::optimize::handle optFuncHandle = this->getOptimizationDirection() == OptimizationDirection::Minimize
153 ? solver->minimize(expressionAdapter->translateExpression(optimizationFunction))
154 : solver->maximize(expressionAdapter->translateExpression(optimizationFunction));
156 z3::check_result chkRes = solver->check();
157 STORM_LOG_THROW(chkRes != z3::unknown, storm::exceptions::InvalidStateException,
"Unable to solve LP problem with Z3: Check result is unknown.");
162 lastCheckInfeasible = (chkRes == z3::unsat);
163 if (lastCheckInfeasible) {
164 lastCheckUnbounded =
false;
167 lastCheckObjectiveValue = std::make_unique<z3::expr>(solver->upper(optFuncHandle));
169 STORM_LOG_ASSERT(lastCheckObjectiveValue->is_app(),
"Failed to convert Z3 expression. Encountered unknown expression type.");
170 lastCheckUnbounded = (lastCheckObjectiveValue->decl().decl_kind() != Z3_OP_ANUM);
171 if (lastCheckUnbounded) {
172 lastCheckObjectiveValue.reset(
nullptr);
175 STORM_LOG_ASSERT(std::string(Z3_get_numeral_string(*context, *lastCheckObjectiveValue)) ==
176 std::string(Z3_get_numeral_string(*context, solver->lower(optFuncHandle))),
177 "Lower and Upper Approximation of z3LPSolver result do not match.");
178 lastCheckModel = std::make_unique<z3::model>(solver->get_model());
183 this->currentModelHasBeenOptimized =
true;
186template<
typename ValueType,
bool RawMode>
187bool Z3LpSolver<ValueType, RawMode>::isInfeasible()
const {
188 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
189 "Illegal call to Z3LpSolver<ValueType, RawMode>::isInfeasible: model has not been optimized.");
190 return lastCheckInfeasible;
193template<
typename ValueType,
bool RawMode>
194bool Z3LpSolver<ValueType, RawMode>::isUnbounded()
const {
195 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
196 "Illegal call to Z3LpSolver<ValueType, RawMode>::isUnbounded: model has not been optimized.");
197 return lastCheckUnbounded;
200template<
typename ValueType,
bool RawMode>
201bool Z3LpSolver<ValueType, RawMode>::isOptimal()
const {
202 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
203 "Illegal call to Z3LpSolver<ValueType, RawMode>::isOptimal: model has not been optimized.");
204 return !lastCheckInfeasible && !lastCheckUnbounded;
207template<
typename ValueType,
bool RawMode>
209 if (!this->isOptimal()) {
210 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from infeasible model.");
211 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unbounded model.");
212 STORM_LOG_THROW(
false, storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unoptimized model.");
216 if constexpr (RawMode) {
217 STORM_LOG_ASSERT(variable < rawIndexToVariableMap.size(),
"Requested variable out of range.");
218 z3::expr z3Var = this->expressionAdapter->translateExpression(rawIndexToVariableMap[variable]);
219 return this->expressionAdapter->translateExpression(lastCheckModel->eval(z3Var,
true));
221 STORM_LOG_ASSERT(variable.getManager() == this->getManager(),
"Requested variable is managed by a different manager.");
222 z3::expr z3Var = this->expressionAdapter->translateExpression(variable);
223 return this->expressionAdapter->translateExpression(lastCheckModel->eval(z3Var,
true));
227template<
typename ValueType,
bool RawMode>
228ValueType Z3LpSolver<ValueType, RawMode>::getContinuousValue(Variable
const& variable)
const {
234 "Expected a rational literal while obtaining the value of a continuous variable. Got " << value <<
"instead.");
238template<
typename ValueType,
bool RawMode>
239int_fast64_t Z3LpSolver<ValueType, RawMode>::getIntegerValue(Variable
const& variable)
const {
242 "Expected an integer literal while obtaining the value of an integer variable. Got " << value <<
"instead.");
246template<
typename ValueType,
bool RawMode>
247bool Z3LpSolver<ValueType, RawMode>::getBinaryValue(Variable
const& variable)
const {
251 "Expected an integer literal while obtaining the value of a binary variable. Got " << value <<
"instead.");
253 STORM_LOG_THROW((val == 0 || val == 1), storm::exceptions::ExpressionEvaluationException,
254 "Tried to get a binary value for a variable that is neither 0 nor 1.");
258template<
typename ValueType,
bool RawMode>
259ValueType Z3LpSolver<ValueType, RawMode>::getObjectiveValue()
const {
260 if (!this->isOptimal()) {
261 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from infeasible model.");
262 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unbounded model.");
263 STORM_LOG_THROW(
false, storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unoptimized model.");
265 STORM_LOG_ASSERT(lastCheckObjectiveValue,
"Objective value has not been stored.");
272 "Expected a rational literal while obtaining the objective result. Got " << result <<
"instead.");
276template<
typename ValueType,
bool RawMode>
277void Z3LpSolver<ValueType, RawMode>::writeModelToFile(std::string
const& filename)
const {
278 std::ofstream stream;
280 stream << Z3_optimize_to_string(*context, *solver);
284template<
typename ValueType,
bool RawMode>
285void Z3LpSolver<ValueType, RawMode>::push() {
286 STORM_LOG_THROW(!RawMode, storm::exceptions::NotImplementedException,
"Incremental solving is not supported in Raw mode.");
287 incrementaOptimizationSummandIndicators.push_back(optimizationSummands.size());
291template<
typename ValueType,
bool RawMode>
292void Z3LpSolver<ValueType, RawMode>::pop() {
293 STORM_LOG_THROW(!RawMode, storm::exceptions::NotImplementedException,
"Incremental solving is not supported in Raw mode.");
294 STORM_LOG_ASSERT(!incrementaOptimizationSummandIndicators.empty(),
"Tried to pop() without push()ing first.");
297 optimizationSummands.resize(incrementaOptimizationSummandIndicators.back());
298 incrementaOptimizationSummandIndicators.pop_back();
299 isIncremental =
true;
302template<
typename ValueType,
bool RawMode>
303void Z3LpSolver<ValueType, RawMode>::setMaximalMILPGap(ValueType
const&,
bool) {
308template<
typename ValueType,
bool RawMode>
309ValueType Z3LpSolver<ValueType, RawMode>::getMILPGap(
bool relative)
const {
314template<
typename ValueType,
bool RawMode>
317 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
318 "requires this support.");
321template<
typename ValueType,
bool RawMode>
324 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
325 "requires this support.");
328template<
typename ValueType,
bool RawMode>
331 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
332 "requires this support.");
335template<
typename ValueType,
bool RawMode>
338 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
339 "requires this support.");
342template<
typename ValueType,
bool RawMode>
345template<
typename ValueType,
bool RawMode>
347 std::optional<ValueType>
const&, std::optional<ValueType>
const&,
350 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
351 "requires this support.");
354template<
typename ValueType,
bool RawMode>
357 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
358 "requires this support.");
361template<
typename ValueType,
bool RawMode>
364 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
365 "requires this support.");
368template<
typename ValueType,
bool RawMode>
371 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
372 "requires this support.");
375template<
typename ValueType,
bool RawMode>
378 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
379 "requires this support.");
382template<
typename ValueType,
bool RawMode>
385 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
386 "requires this support.");
389template<
typename ValueType,
bool RawMode>
392 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
393 "requires this support.");
396template<
typename ValueType,
bool RawMode>
399 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
400 "requires this support.");
403template<
typename ValueType,
bool RawMode>
406 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
407 "requires this support.");
410template<
typename ValueType,
bool RawMode>
413 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
414 "requires this support.");
417template<
typename ValueType,
bool RawMode>
420 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
421 "requires this support.");
424template<
typename ValueType,
bool RawMode>
427 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
428 "requires this support.");
431template<
typename ValueType,
bool RawMode>
434 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
435 "requires this support.");
438template<
typename ValueType,
bool RawMode>
441 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
442 "requires this support.");
445template<
typename ValueType,
bool RawMode>
448 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
449 "requires this support.");
452template<
typename ValueType,
bool RawMode>
455 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
456 "requires this support.");
459template<
typename ValueType,
bool RawMode>
462 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
463 "requires this support.");
466template<
typename ValueType,
bool RawMode>
469 "This version of storm was compiled without Z3 or the version of Z3 does not support optimization. Yet, a method was called that "
470 "requires this support.");
IntegerLiteralExpression const & asIntegerLiteralExpression() const
RationalLiteralExpression const & asRationalLiteralExpression() const
virtual bool isRationalLiteralExpression() const
virtual bool isIntegerLiteralExpression() const
BaseExpression const & getBaseExpression() const
Retrieves the base expression underlying this expression object.
int_fast64_t getValue() const
Retrieves the value of the integer literal.
storm::RationalNumber getValue() const
Retrieves the value of the double literal.
storm::expressions::Expression getExpression() const
Retrieves an expression that represents the variable.
An interface that captures the functionality of an LP solver.
A class that implements the LpSolver interface using Z3.
virtual ValueType getObjectiveValue() const override
Retrieves the value of the objective function.
typename LpSolver< ValueType, RawMode >::Variable Variable
virtual void update() const override
Updates the model to make the variables that have been declared since the last call to update usable.
virtual int_fast64_t getIntegerValue(Variable const &variable) const override
Retrieves the value of the integer 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
typename LpSolver< ValueType, RawMode >::Constraint Constraint
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 ValueType getContinuousValue(Variable const &variable) const override
Retrieves the value of the continuous variable with the given name.
Z3LpSolver()
Constructs a solver without a 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 ValueType getMILPGap(bool relative) const override
Returns the obtained gap after a call to optimize().
virtual void setMaximalMILPGap(ValueType const &gap, bool relative) override
Specifies the maximum difference between lower- and upper objective bounds that triggers termination.
virtual void push() override
Pushes a backtracking point on the solver's stack.
virtual void addConstraint(std::string const &name, Constraint const &constraint) override
Adds a the given constraint to the LP problem.
Z3LpSolver(std::string const &name, OptimizationDirection const &optDir)
Constructs a solver with the given name and optimization direction.
virtual bool isOptimal() const override
Retrieves whether the model was found to be optimal, i.e.
typename LpSolver< ValueType, RawMode >::VariableType VariableType
virtual ~Z3LpSolver()
Destructs a solver by freeing the pointers to Z3's structures.
virtual bool isInfeasible() const override
Retrieves whether the model was found to be infeasible.
virtual void pop() override
Pops a backtracking point from the solver's stack.
virtual bool getBinaryValue(Variable const &variable) const override
Retrieves the value of the binary variable with the given name.
virtual void optimize() const override
Optimizes the LP problem previously constructed.
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
Expression makeBinaryRelationExpression(Expression const &first, Expression const &second, RelationType const &reltype)
Expression sum(std::vector< storm::expressions::Expression > const &expressions)
void closeFile(std::ofstream &stream)
Close the given file after writing.
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
SettingsManager const & manager()
Retrieves the settings manager.
bool isZero(ValueType const &a)
TargetType convertNumber(SourceType const &number)