21#ifdef STORM_HAVE_Z3_OPTIMIZE
23template<
typename ValueType,
bool RawMode>
25 : LpSolver<
ValueType, RawMode>(optDir), isIncremental(false) {
27 config.set(
"model",
true);
28 context = std::unique_ptr<z3::context>(
new z3::context(config));
29 solver = std::unique_ptr<z3::optimize>(
new z3::optimize(*context));
30 expressionAdapter = std::unique_ptr<storm::adapters::Z3ExpressionAdapter>(
new storm::adapters::Z3ExpressionAdapter(*this->manager, *context));
33template<
typename ValueType,
bool RawMode>
38template<
typename ValueType,
bool RawMode>
39Z3LpSolver<ValueType, RawMode>::Z3LpSolver(OptimizationDirection
const& optDir) : Z3LpSolver(
"", optDir) {
43template<
typename ValueType,
bool RawMode>
48template<
typename ValueType,
bool RawMode>
49Z3LpSolver<ValueType, RawMode>::~Z3LpSolver() {
53template<
typename ValueType,
bool RawMode>
54void Z3LpSolver<ValueType, RawMode>::update()
const {
56 lastCheckObjectiveValue.reset(
nullptr);
57 lastCheckModel.reset(
nullptr);
58 this->currentModelHasBeenOptimized =
false;
61template<
typename ValueType,
bool RawMode>
62typename Z3LpSolver<ValueType, RawMode>::Variable Z3LpSolver<ValueType, RawMode>::addVariable(std::string
const& name, VariableType
const& type,
63 std::optional<ValueType>
const& lowerBound,
64 std::optional<ValueType>
const& upperBound,
65 ValueType objectiveFunctionCoefficient) {
66 STORM_LOG_ASSERT(isIncremental || !this->
manager->hasVariable(name),
"Variable with name " << name <<
" already exists.");
68 if (type == VariableType::Binary) {
69 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() >= this->manager->integer(0)));
70 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() <= this->manager->integer(1)));
73 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() >= this->manager->rational(*lowerBound)));
76 solver->add(expressionAdapter->translateExpression(newVariable.
getExpression() <= this->manager->rational(*upperBound)));
79 optimizationSummands.push_back(this->
manager->rational(objectiveFunctionCoefficient) * newVariable);
82 if constexpr (RawMode) {
83 rawIndexToVariableMap.push_back(newVariable);
84 return rawIndexToVariableMap.size() - 1;
90template<
typename ValueType,
bool RawMode>
91void Z3LpSolver<ValueType, RawMode>::addConstraint(std::string
const& name, Constraint
const& constraint) {
92 if constexpr (RawMode) {
94 STORM_LOG_ASSERT(constraint.lhsVariableIndices.size() == constraint.lhsCoefficients.size(),
"number of variables and coefficients do not match.");
95 std::vector<storm::expressions::Expression> lhsSummands;
96 lhsSummands.reserve(constraint.lhsVariableIndices.size());
97 auto varIt = constraint.lhsVariableIndices.cbegin();
98 auto varItEnd = constraint.lhsVariableIndices.cend();
99 auto coefIt = constraint.lhsCoefficients.cbegin();
100 for (; varIt != varItEnd; ++varIt, ++coefIt) {
101 lhsSummands.push_back(rawIndexToVariableMap[*varIt] * this->
manager->rational(*coefIt));
103 if (lhsSummands.empty()) {
104 lhsSummands.push_back(this->
manager->rational(storm::utility::zero<ValueType>()));
108 solver->add(expressionAdapter->translateExpression(constraintExpr));
110 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
112 "Illegal constraint uses inequality operator.");
113 solver->add(expressionAdapter->translateExpression(constraint));
117template<
typename ValueType,
bool RawMode>
118void Z3LpSolver<ValueType, RawMode>::addIndicatorConstraint(std::string
const& name, Variable indicatorVariable,
bool indicatorValue,
119 Constraint
const& constraint) {
120 if constexpr (RawMode) {
121 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Indicator constraints not implemented in RawMode");
124 STORM_LOG_THROW(indicatorVariable.hasIntegerType(), storm::exceptions::InvalidArgumentException,
125 "Variable " << indicatorVariable.getName() <<
" is not binary.");
126 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
128 "Illegal constraint uses inequality operator.");
131 this->getConstant(indicatorValue ? storm::utility::zero<ValueType>() :
storm::utility::
one<
ValueType>());
132 auto indicatorConstraint = (indicatorVariable.getExpression() == invertedIndicatorVal) || constraint;
133 solver->add(expressionAdapter->translateExpression(indicatorConstraint));
137template<
typename ValueType,
bool RawMode>
138void Z3LpSolver<ValueType, RawMode>::optimize()
const {
147 if (!optimizationSummands.empty()) {
150 z3::optimize::handle optFuncHandle = this->getOptimizationDirection() == OptimizationDirection::Minimize
151 ? solver->minimize(expressionAdapter->translateExpression(optimizationFunction))
152 : solver->maximize(expressionAdapter->translateExpression(optimizationFunction));
154 z3::check_result chkRes = solver->check();
155 STORM_LOG_THROW(chkRes != z3::unknown, storm::exceptions::InvalidStateException,
"Unable to solve LP problem with Z3: Check result is unknown.");
160 lastCheckInfeasible = (chkRes == z3::unsat);
161 if (lastCheckInfeasible) {
162 lastCheckUnbounded =
false;
165 lastCheckObjectiveValue = std::make_unique<z3::expr>(solver->upper(optFuncHandle));
167 STORM_LOG_ASSERT(lastCheckObjectiveValue->is_app(),
"Failed to convert Z3 expression. Encountered unknown expression type.");
168 lastCheckUnbounded = (lastCheckObjectiveValue->decl().decl_kind() != Z3_OP_ANUM);
169 if (lastCheckUnbounded) {
170 lastCheckObjectiveValue.reset(
nullptr);
173 STORM_LOG_ASSERT(std::string(Z3_get_numeral_string(*context, *lastCheckObjectiveValue)) ==
174 std::string(Z3_get_numeral_string(*context, solver->lower(optFuncHandle))),
175 "Lower and Upper Approximation of z3LPSolver result do not match.");
176 lastCheckModel = std::make_unique<z3::model>(solver->get_model());
181 this->currentModelHasBeenOptimized =
true;
184template<
typename ValueType,
bool RawMode>
185bool Z3LpSolver<ValueType, RawMode>::isInfeasible()
const {
186 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
187 "Illegal call to Z3LpSolver<ValueType, RawMode>::isInfeasible: model has not been optimized.");
188 return lastCheckInfeasible;
191template<
typename ValueType,
bool RawMode>
192bool Z3LpSolver<ValueType, RawMode>::isUnbounded()
const {
193 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
194 "Illegal call to Z3LpSolver<ValueType, RawMode>::isUnbounded: model has not been optimized.");
195 return lastCheckUnbounded;
198template<
typename ValueType,
bool RawMode>
199bool Z3LpSolver<ValueType, RawMode>::isOptimal()
const {
200 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
201 "Illegal call to Z3LpSolver<ValueType, RawMode>::isOptimal: model has not been optimized.");
202 return !lastCheckInfeasible && !lastCheckUnbounded;
205template<
typename ValueType,
bool RawMode>
207 if (!this->isOptimal()) {
208 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from infeasible model.");
209 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unbounded model.");
210 STORM_LOG_THROW(
false, storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unoptimized model.");
214 if constexpr (RawMode) {
215 STORM_LOG_ASSERT(variable < rawIndexToVariableMap.size(),
"Requested variable out of range.");
216 z3::expr z3Var = this->expressionAdapter->translateExpression(rawIndexToVariableMap[variable]);
217 return this->expressionAdapter->translateExpression(lastCheckModel->eval(z3Var,
true));
219 STORM_LOG_ASSERT(variable.getManager() == this->getManager(),
"Requested variable is managed by a different manager.");
220 z3::expr z3Var = this->expressionAdapter->translateExpression(variable);
221 return this->expressionAdapter->translateExpression(lastCheckModel->eval(z3Var,
true));
225template<
typename ValueType,
bool RawMode>
226ValueType Z3LpSolver<ValueType, RawMode>::getContinuousValue(Variable
const& variable)
const {
232 "Expected a rational literal while obtaining the value of a continuous variable. Got " << value <<
"instead.");
236template<
typename ValueType,
bool RawMode>
237int_fast64_t Z3LpSolver<ValueType, RawMode>::getIntegerValue(Variable
const& variable)
const {
240 "Expected an integer literal while obtaining the value of an integer variable. Got " << value <<
"instead.");
244template<
typename ValueType,
bool RawMode>
245bool Z3LpSolver<ValueType, RawMode>::getBinaryValue(Variable
const& variable)
const {
249 "Expected an integer literal while obtaining the value of a binary variable. Got " << value <<
"instead.");
251 STORM_LOG_THROW((val == 0 || val == 1), storm::exceptions::ExpressionEvaluationException,
252 "Tried to get a binary value for a variable that is neither 0 nor 1.");
256template<
typename ValueType,
bool RawMode>
257ValueType Z3LpSolver<ValueType, RawMode>::getObjectiveValue()
const {
258 if (!this->isOptimal()) {
259 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from infeasible model.");
260 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unbounded model.");
261 STORM_LOG_THROW(
false, storm::exceptions::InvalidAccessException,
"Unable to get Z3 solution from unoptimized model.");
263 STORM_LOG_ASSERT(lastCheckObjectiveValue,
"Objective value has not been stored.");
270 "Expected a rational literal while obtaining the objective result. Got " << result <<
"instead.");
274template<
typename ValueType,
bool RawMode>
275void Z3LpSolver<ValueType, RawMode>::writeModelToFile(std::string
const& filename)
const {
276 std::ofstream stream;
278 stream << Z3_optimize_to_string(*context, *solver);
282template<
typename ValueType,
bool RawMode>
283void Z3LpSolver<ValueType, RawMode>::push() {
284 STORM_LOG_THROW(!RawMode, storm::exceptions::NotImplementedException,
"Incremental solving is not supported in Raw mode.");
285 incrementaOptimizationSummandIndicators.push_back(optimizationSummands.size());
289template<
typename ValueType,
bool RawMode>
290void Z3LpSolver<ValueType, RawMode>::pop() {
291 STORM_LOG_THROW(!RawMode, storm::exceptions::NotImplementedException,
"Incremental solving is not supported in Raw mode.");
292 STORM_LOG_ASSERT(!incrementaOptimizationSummandIndicators.empty(),
"Tried to pop() without push()ing first.");
295 optimizationSummands.resize(incrementaOptimizationSummandIndicators.back());
296 incrementaOptimizationSummandIndicators.pop_back();
297 isIncremental =
true;
300template<
typename ValueType,
bool RawMode>
301void Z3LpSolver<ValueType, RawMode>::setMaximalMILPGap(ValueType
const&,
bool) {
306template<
typename ValueType,
bool RawMode>
307ValueType Z3LpSolver<ValueType, RawMode>::getMILPGap(
bool relative)
const {
309 return storm::utility::zero<ValueType>();
312template<
typename ValueType,
bool RawMode>
314 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
315 "Yet, a method was called that requires this support.";
318template<
typename ValueType,
bool RawMode>
320 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
321 "Yet, a method was called that requires this support.";
324template<
typename ValueType,
bool RawMode>
326 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
327 "Yet, a method was called that requires this support.";
330template<
typename ValueType,
bool RawMode>
332 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
333 "Yet, a method was called that requires this support.";
336template<
typename ValueType,
bool RawMode>
339template<
typename ValueType,
bool RawMode>
341 std::optional<ValueType>
const&, std::optional<ValueType>
const&,
343 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
344 "Yet, a method was called that requires this support.";
347template<
typename ValueType,
bool RawMode>
349 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
350 "Yet, a method was called that requires this support.";
353template<
typename ValueType,
bool RawMode>
355 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
356 "Yet, a method was called that requires this support.";
359template<
typename ValueType,
bool RawMode>
361 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
362 "Yet, a method was called that requires this support.";
365template<
typename ValueType,
bool RawMode>
367 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
368 "Yet, a method was called that requires this support.";
371template<
typename ValueType,
bool RawMode>
373 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
374 "Yet, a method was called that requires this support.";
377template<
typename ValueType,
bool RawMode>
379 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
380 "Yet, a method was called that requires this support.";
383template<
typename ValueType,
bool RawMode>
385 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
386 "Yet, a method was called that requires this support.";
389template<
typename ValueType,
bool RawMode>
391 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
392 "Yet, a method was called that requires this support.";
395template<
typename ValueType,
bool RawMode>
397 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
398 "Yet, a method was called that requires this support.";
401template<
typename ValueType,
bool RawMode>
403 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
404 "Yet, a method was called that requires this support.";
407template<
typename ValueType,
bool RawMode>
409 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
410 "Yet, a method was called that requires this support.";
413template<
typename ValueType,
bool RawMode>
415 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
416 "Yet, a method was called that requires this support.";
419template<
typename ValueType,
bool RawMode>
421 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
422 "Yet, a method was called that requires this support.";
425template<
typename ValueType,
bool RawMode>
427 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
428 "Yet, a method was called that requires this support.";
431template<
typename ValueType,
bool RawMode>
433 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
434 "Yet, a method was called that requires this support.";
437template<
typename ValueType,
bool RawMode>
439 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
440 "Yet, a method was called that requires this support.";
443template<
typename ValueType,
bool RawMode>
445 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without Z3 or the version of Z3 does not support optimization. "
446 "Yet, a method was called that 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.
A class that implements the LpSolver interface using Z3.
typename LpSolver< ValueType, RawMode >::Variable Variable
typename LpSolver< ValueType, RawMode >::Constraint Constraint
Z3LpSolver()
Constructs a solver without a name.
typename LpSolver< ValueType, RawMode >::VariableType VariableType
#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)