18typedef int64_t Z3_SIGNED_INTEGER;
19typedef uint64_t Z3_UNSIGNED_INTEGER;
21Z3ExpressionAdapter::Z3ExpressionAdapter(storm::expressions::ExpressionManager& manager, z3::context& context)
22 :
manager(
manager), context(context), additionalAssertions(), variableToExpressionMapping() {
30 expressionCache.clear();
32 for (z3::expr
const& assertion : additionalAssertions) {
33 result = result && assertion;
35 additionalAssertions.clear();
36 return result.simplify();
42 auto const& variableExpressionPair = variableToExpressionMapping.find(variable);
43 if (variableExpressionPair == variableToExpressionMapping.end()) {
44 return createVariable(variable);
47 return variableExpressionPair->second;
51 auto const& declarationVariablePair = declarationToVariableMapping.find(z3Declaration);
52 STORM_LOG_ASSERT(declarationVariablePair != declarationToVariableMapping.end(),
"Unable to find declaration.");
53 return declarationVariablePair->second;
58 switch (expr.decl().decl_kind()) {
64 return this->translateExpression(expr.arg(0)) == this->translateExpression(expr.arg(1));
65 case Z3_OP_DISTINCT: {
66 unsigned args = expr.num_args();
67 STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException,
68 "Failed to convert Z3 expression. DISTINCT (mutual != ) operator with 0-arity is assumed to be an error.");
73 for (
unsigned arg2 = 2; arg2 < args; ++arg2) {
74 retVal = retVal && (this->translateExpression(expr.arg(0)) != this->translateExpression(expr.arg(arg2)));
76 for (
unsigned arg1 = 1; arg1 < args; ++arg1) {
77 for (
unsigned arg2 = arg1 + 1; arg2 < args; ++arg2) {
78 retVal = retVal && (this->translateExpression(expr.arg(arg1)) != this->translateExpression(expr.arg(arg2)));
86 this->translateExpression(expr.arg(2)));
88 unsigned args = expr.num_args();
89 STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException,
90 "Failed to convert Z3 expression. 0-ary AND is assumed to be an error.");
92 return this->translateExpression(expr.arg(0));
95 for (
unsigned i = 1;
i < args;
i++) {
96 retVal = retVal && this->translateExpression(expr.arg(i));
102 unsigned args = expr.num_args();
103 STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException,
104 "Failed to convert Z3 expression. 0-ary OR is assumed to be an error.");
106 return this->translateExpression(expr.arg(0));
109 for (
unsigned i = 1;
i < args;
i++) {
110 retVal = retVal || this->translateExpression(expr.arg(i));
116 return storm::expressions::iff(this->translateExpression(expr.arg(0)), this->translateExpression(expr.arg(1)));
120 return !this->translateExpression(expr.arg(0));
124 return this->translateExpression(expr.arg(0)) <= this->translateExpression(expr.arg(1));
126 return this->translateExpression(expr.arg(0)) >= this->translateExpression(expr.arg(1));
128 return this->translateExpression(expr.arg(0)) < this->translateExpression(expr.arg(1));
130 return this->translateExpression(expr.arg(0)) > this->translateExpression(expr.arg(1));
132 return this->translateExpression(expr.arg(0)) + this->translateExpression(expr.arg(1));
134 return this->translateExpression(expr.arg(0)) - this->translateExpression(expr.arg(1));
136 return -this->translateExpression(expr.arg(0));
138 return this->translateExpression(expr.arg(0)) * this->translateExpression(expr.arg(1));
140 return this->translateExpression(expr.arg(0)) / this->translateExpression(expr.arg(1));
142 return this->translateExpression(expr.arg(0)) / this->translateExpression(expr.arg(1));
145 if (expr.is_int() && expr.is_const()) {
146 Z3_SIGNED_INTEGER value;
147 if (Z3_get_numeral_int64(expr.ctx(), expr, &value)) {
150 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
151 "Failed to convert Z3 expression. Expression is constant integer and value does not fit into 64-bit integer.");
154 STORM_LOG_ASSERT(expr.is_real() && expr.is_const(),
"Cannot handle numerical expression.");
155 Z3_SIGNED_INTEGER num;
156 Z3_SIGNED_INTEGER den;
157 if (Z3_get_numeral_rational_int64(expr.ctx(), expr, &num, &den)) {
166 STORM_LOG_WARN(
"Interpreting algebraic numbers as rational numbers. This is not an exact computation.");
169 std::string(Z3_get_numeral_string(expr.ctx(), Z3_get_algebraic_number_lower(expr.ctx(), expr, 16)))));
170 case Z3_OP_UNINTERPRETED:
172 STORM_LOG_THROW(expr.is_const(), storm::exceptions::ExpressionEvaluationException,
173 "Failed to convert Z3 expression. Encountered non-constant uninterpreted function.");
174 return manager.getVariable(expr.decl().name().str()).getExpression();
176 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
177 "Failed to convert Z3 expression. Encountered unhandled Z3_decl_kind " << expr.decl().decl_kind() <<
".");
181 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
"Failed to convert Z3 expression. Encountered unknown expression type.");
186 auto cacheIt = expressionCache.find(&expression);
187 if (cacheIt != expressionCache.end()) {
188 return cacheIt->second;
191 z3::expr leftResult = boost::any_cast<z3::expr>(expression.
getFirstOperand()->accept(*
this, data));
192 z3::expr rightResult = boost::any_cast<z3::expr>(expression.
getSecondOperand()->accept(*
this, data));
194 z3::expr result(context);
197 result = leftResult && rightResult;
200 result = leftResult || rightResult;
203 result = z3::expr(context, Z3_mk_xor(context, leftResult, rightResult));
206 result = z3::expr(context, Z3_mk_implies(context, leftResult, rightResult));
209 result = z3::expr(context, Z3_mk_iff(context, leftResult, rightResult));
212 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
213 "Cannot evaluate expression: unknown boolean binary operator '" <<
static_cast<int>(expression.
getOperatorType())
214 <<
"' in expression " << expression <<
".");
217 expressionCache.emplace(&expression, result);
222 auto cacheIt = expressionCache.find(&expression);
223 if (cacheIt != expressionCache.end()) {
224 return cacheIt->second;
227 z3::expr leftResult = boost::any_cast<z3::expr>(expression.
getFirstOperand()->accept(*
this, data));
228 z3::expr rightResult = boost::any_cast<z3::expr>(expression.
getSecondOperand()->accept(*
this, data));
230 z3::expr result(context);
233 result = leftResult + rightResult;
236 result = leftResult - rightResult;
239 result = leftResult * rightResult;
242 if (leftResult.is_int() && rightResult.is_int()) {
243 leftResult = z3::expr(context, Z3_mk_int2real(context, leftResult));
245 result = leftResult / rightResult;
248 result =
ite(leftResult <= rightResult, leftResult, rightResult);
251 result =
ite(leftResult >= rightResult, leftResult, rightResult);
254 result = pw(leftResult, rightResult);
257 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
258 "Cannot evaluate expression: unknown numerical binary operator '" <<
static_cast<int>(expression.
getOperatorType())
259 <<
"' in expression " << expression <<
".");
262 expressionCache.emplace(&expression, result);
267 auto cacheIt = expressionCache.find(&expression);
268 if (cacheIt != expressionCache.end()) {
269 return cacheIt->second;
272 z3::expr leftResult = boost::any_cast<z3::expr>(expression.
getFirstOperand()->accept(*
this, data));
273 z3::expr rightResult = boost::any_cast<z3::expr>(expression.
getSecondOperand()->accept(*
this, data));
275 z3::expr result(context);
278 result = leftResult == rightResult;
281 result = leftResult != rightResult;
284 result = leftResult < rightResult;
287 result = leftResult <= rightResult;
290 result = leftResult > rightResult;
293 result = leftResult >= rightResult;
296 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
297 "Cannot evaluate expression: unknown boolean binary operator '" <<
static_cast<int>(expression.
getRelationType())
298 <<
"' in expression " << expression <<
".");
301 expressionCache.emplace(&expression, result);
306 auto cacheIt = expressionCache.find(&expression);
307 if (cacheIt != expressionCache.end()) {
308 return cacheIt->second;
311 z3::expr result = context.bool_val(expression.
getValue());
313 expressionCache.emplace(&expression, result);
318 auto cacheIt = expressionCache.find(&expression);
319 if (cacheIt != expressionCache.end()) {
320 return cacheIt->second;
323 std::stringstream fractionStream;
324 fractionStream << expression.
getValue();
325 z3::expr result = context.real_val(fractionStream.str().c_str());
327 expressionCache.emplace(&expression, result);
332 auto cacheIt = expressionCache.find(&expression);
333 if (cacheIt != expressionCache.end()) {
334 return cacheIt->second;
337 z3::expr result = context.int_val(
static_cast<Z3_SIGNED_INTEGER
>(expression.
getValue()));
339 expressionCache.emplace(&expression, result);
344 auto cacheIt = expressionCache.find(&expression);
345 if (cacheIt != expressionCache.end()) {
346 return cacheIt->second;
349 z3::expr result = boost::any_cast<z3::expr>(expression.
getOperand()->accept(*
this, data));
356 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
357 "Cannot evaluate expression: unknown boolean binary operator '" <<
static_cast<int>(expression.
getOperatorType())
358 <<
"' in expression " << expression <<
".");
361 expressionCache.emplace(&expression, result);
366 auto cacheIt = expressionCache.find(&expression);
367 if (cacheIt != expressionCache.end()) {
368 return cacheIt->second;
371 z3::expr result = boost::any_cast<z3::expr>(expression.
getOperand()->accept(*
this, data));
379 z3::expr floorVariable = context.int_const(freshAuxiliaryVariable.
getName().c_str());
380 additionalAssertions.push_back(z3::expr(context, Z3_mk_int2real(context, floorVariable)) <= result &&
381 result < (z3::expr(context, Z3_mk_int2real(context, floorVariable)) + 1));
382 result = floorVariable;
387 z3::expr ceilVariable = context.int_const(freshAuxiliaryVariable.
getName().c_str());
388 additionalAssertions.push_back(z3::expr(context, Z3_mk_int2real(context, ceilVariable)) - 1 < result &&
389 result <= z3::expr(context, Z3_mk_int2real(context, ceilVariable)));
390 result = ceilVariable;
394 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
395 "Cannot evaluate expression: unknown numerical unary operator '" <<
static_cast<int>(expression.
getOperatorType()) <<
"'.");
398 expressionCache.emplace(&expression, result);
403 auto cacheIt = expressionCache.find(&expression);
404 if (cacheIt != expressionCache.end()) {
405 return cacheIt->second;
408 z3::expr conditionResult = boost::any_cast<z3::expr>(expression.
getCondition()->accept(*
this, data));
409 z3::expr thenResult = boost::any_cast<z3::expr>(expression.
getThenExpression()->accept(*
this, data));
410 z3::expr elseResult = boost::any_cast<z3::expr>(expression.
getElseExpression()->accept(*
this, data));
411 z3::expr result = z3::expr(context, Z3_mk_ite(context, conditionResult, thenResult, elseResult));
413 expressionCache.emplace(&expression, result);
418 return this->translateExpression(expression.
getVariable());
422 z3::expr z3Variable(context);
424 z3Variable = context.bool_const(variable.
getName().c_str());
426 z3Variable = context.int_const(variable.
getName().c_str());
430 z3Variable = context.real_const(variable.
getName().c_str());
433 "Encountered variable '" << variable.
getName() <<
"' with unknown type while trying to create solver variables.");
435 variableToExpressionMapping.insert(std::make_pair(variable, z3Variable));
436 declarationToVariableMapping.insert(std::make_pair(z3Variable.decl(), variable));
virtual boost::any accept(ExpressionVisitor &visitor, boost::any const &data) const =0
Accepts the given visitor by calling its visit method.
OperatorType getOperatorType() const
Retrieves the operator associated with the expression.
std::shared_ptr< BaseExpression const > const & getSecondOperand() const
Retrieves the second operand of the expression.
std::shared_ptr< BaseExpression const > const & getFirstOperand() const
Retrieves the first operand of the expression.
OperatorType getOperatorType() const
Retrieves the operator associated with the expression.
RelationType getRelationType() const
Retrieves the relation associated with the expression.
bool getValue() const
Retrieves the value of the boolean literal.
BaseExpression const & getBaseExpression() const
Retrieves the base expression underlying this expression object.
ExpressionManager const & getManager() const
Retrieves the manager responsible for this expression.
std::shared_ptr< BaseExpression const > getElseExpression() const
Retrieves the else expression of the if-then-else expression.
std::shared_ptr< BaseExpression const > getCondition() const
Retrieves the condition expression of the if-then-else expression.
std::shared_ptr< BaseExpression const > getThenExpression() const
Retrieves the then expression of the if-then-else expression.
int_fast64_t getValue() const
Retrieves the value of the integer literal.
storm::RationalNumber getValue() const
Retrieves the value of the double literal.
bool isBooleanType() const
Checks whether this type is a boolean type.
std::size_t getWidth() const
Retrieves the bit width of the type, provided that it is a bitvector type.
bool isIntegerType() const
Checks whether this type is an integral type.
bool isRationalType() const
Checks whether this type is a rational type.
bool isBitVectorType() const
Checks whether this type is a bitvector type.
OperatorType getOperatorType() const
Retrieves the operator associated with this expression.
virtual std::shared_ptr< BaseExpression const > getOperand(uint_fast64_t operandIndex) const override
Retrieves the given operand from the expression.
OperatorType getOperatorType() const
Retrieves the operator associated with this expression.
Variable const & getVariable() const
Retrieves the variable associated with this expression.
ExpressionManager const & getManager() const
Retrieves the manager responsible for this variable.
Type const & getType() const
Retrieves the type of the variable.
std::string const & getName() const
Retrieves the name of the variable.
#define STORM_LOG_WARN(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
Expression iff(Expression const &first, Expression const &second)
Expression xclusiveor(Expression const &first, Expression const &second)
Expression implies(Expression const &first, Expression const &second)
SettingsManager const & manager()
Retrieves the settings manager.
TargetType convertNumber(SourceType const &number)