34storm::expressions::Expression translateNumericalConstant(storm::expressions::ExpressionManager& manager, std::string
const& stringRepresentation,
38 std::vector<std::string_view> tokens;
39 std::string_view
const input(stringRepresentation);
40 size_t tokenStart = 0;
42 auto const flushToken = [&](
size_t end) {
44 tokens.push_back(input.substr(tokenStart, end - tokenStart));
48 for (
size_t i = 0;
i < input.size(); ++
i) {
49 char const c = input[
i];
50 if (std::isspace(
static_cast<unsigned char>(c))) {
52 }
else if (c ==
'(') {
55 if (i + 1 < input.size() && (input[i + 1] ==
'-' || input[i + 1] ==
'/')) {
56 tokens.push_back(input.substr(i, 2));
59 tokens.push_back(input.substr(i, 1));
61 }
else if (c ==
')') {
63 tokens.push_back(input.substr(i, 1));
64 }
else if (!inToken) {
69 flushToken(input.size());
70 STORM_LOG_THROW(!tokens.empty(), storm::exceptions::ExpressionEvaluationException,
71 "Failed to convert cvc5 expression. Encountered empty numerical constant.");
76 bool isNegative = tokens[position] ==
"(-";
80 STORM_LOG_THROW(position < tokens.size(), storm::exceptions::ExpressionEvaluationException,
81 "Failed to convert cvc5 expression. Encountered malformed integer constant " << stringRepresentation <<
".");
82 std::string
const number(tokens[position]);
85 STORM_LOG_THROW(position < tokens.size() && tokens[position] ==
")", storm::exceptions::ExpressionEvaluationException,
86 "Failed to convert cvc5 expression. Encountered malformed integer constant " << stringRepresentation <<
".");
89 STORM_LOG_THROW(position == tokens.size(), storm::exceptions::ExpressionEvaluationException,
90 "Failed to convert cvc5 expression. Encountered malformed integer constant " << stringRepresentation <<
".");
96 value = std::stoll(isNegative ?
"-" + number : number);
97 }
catch (std::logic_error
const&) {
98 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
99 "Failed to convert cvc5 expression. Integer constant " << stringRepresentation <<
" does not fit into a 64-bit integer.");
106 std::function<storm::RationalNumber(
bool)> parse;
107 parse = [&tokens, &position, &parse, &stringRepresentation](
bool isNegative) -> storm::RationalNumber {
108 STORM_LOG_THROW(position < tokens.size(), storm::exceptions::ExpressionEvaluationException,
109 "Failed to convert cvc5 expression. Encountered malformed rational constant " << stringRepresentation <<
".");
112 if (tokens[position] ==
"(-") {
113 STORM_LOG_THROW(!isNegative, storm::exceptions::ExpressionEvaluationException,
114 "Failed to convert cvc5 expression. Encountered doubly negated rational constant " << stringRepresentation <<
".");
116 storm::RationalNumber result = parse(
true);
117 STORM_LOG_THROW(position < tokens.size() && tokens[position] ==
")", storm::exceptions::ExpressionEvaluationException,
118 "Failed to convert cvc5 expression. Encountered malformed rational constant " << stringRepresentation <<
".");
124 if (tokens[position] ==
"(/") {
126 storm::RationalNumber
numerator = parse(isNegative);
128 STORM_LOG_THROW(position < tokens.size() && tokens[position] ==
")", storm::exceptions::ExpressionEvaluationException,
129 "Failed to convert cvc5 expression. Encountered malformed fraction " << stringRepresentation <<
".");
135 std::string
const number(tokens[position]);
138 return isNegative ? -result : result;
141 storm::RationalNumber
const value = parse(
false);
142 STORM_LOG_THROW(position == tokens.size(), storm::exceptions::ExpressionEvaluationException,
143 "Failed to convert cvc5 expression. Encountered malformed rational constant " << stringRepresentation <<
".");
144 return manager.rational(value);
149Cvc5ExpressionAdapter::Cvc5ExpressionAdapter(storm::expressions::ExpressionManager& manager, cvc5::Solver& solver)
150 :
manager(
manager), termManager(solver.getTermManager()), variableToExpressionMapping() {
158 expressionCache.clear();
165 auto const& variableExpressionPair = variableToExpressionMapping.find(variable);
166 if (variableExpressionPair == variableToExpressionMapping.end()) {
167 return createVariable(variable);
170 return variableExpressionPair->second;
175 if (term.getSort().isBoolean()) {
176 if (term == this->termManager.mkBoolean(
true)) {
177 return this->manager.
boolean(
true);
178 }
else if (term == this->termManager.mkBoolean(
false)) {
179 return this->manager.
boolean(
false);
184 if (term.getKind() == cvc5::Kind::CONSTANT) {
185 STORM_LOG_THROW(term.hasSymbol(), storm::exceptions::ExpressionEvaluationException,
186 "Failed to convert cvc5 expression. Encountered a constant without a symbol.");
187 return this->getVariable(term).getExpression();
188 }
else if (term.getKind() == cvc5::Kind::CONST_INTEGER || term.getKind() == cvc5::Kind::CONST_RATIONAL) {
189 return translateNumericalConstant(this->manager, term.toString(), term.getKind() == cvc5::Kind::CONST_INTEGER);
192 switch (term.getKind()) {
193 case cvc5::Kind::CONST_BOOLEAN:
194 return term == this->termManager.mkBoolean(
true) ? this->manager.
boolean(
true) : this->manager.
boolean(
false);
195 case cvc5::Kind::EQUAL: {
204 return first == second;
206 case cvc5::Kind::DISTINCT: {
207 STORM_LOG_THROW(term.getNumChildren() != 0, storm::exceptions::ExpressionEvaluationException,
208 "Failed to convert cvc5 expression. DISTINCT (mutual !=) operator with 0-arity is assumed to be an error.");
209 if (term.getNumChildren() == 1) {
210 return this->manager.
boolean(
true);
213 for (
size_t arg2 = 2; arg2 < term.getNumChildren(); ++arg2) {
214 retVal = retVal && (this->translateExpression(term[0]) != this->translateExpression(term[arg2]));
216 for (
size_t arg1 = 1; arg1 < term.getNumChildren(); ++arg1) {
217 for (
size_t arg2 = arg1 + 1; arg2 < term.getNumChildren(); ++arg2) {
218 retVal = retVal && (this->translateExpression(term[arg1]) != this->translateExpression(term[arg2]));
224 case cvc5::Kind::ITE:
225 return storm::expressions::ite(this->translateExpression(term[0]), this->translateExpression(term[1]), this->translateExpression(term[2]));
226 case cvc5::Kind::AND: {
227 STORM_LOG_THROW(term.getNumChildren() != 0, storm::exceptions::ExpressionEvaluationException,
228 "Failed to convert cvc5 expression. 0-ary AND is assumed to be an error.");
229 if (term.getNumChildren() == 1) {
230 return this->translateExpression(term[0]);
233 for (
size_t i = 1;
i < term.getNumChildren(); ++
i) {
234 retVal = retVal && this->translateExpression(term[i]);
239 case cvc5::Kind::OR: {
240 STORM_LOG_THROW(term.getNumChildren() != 0, storm::exceptions::ExpressionEvaluationException,
241 "Failed to convert cvc5 expression. 0-ary OR is assumed to be an error.");
242 if (term.getNumChildren() == 1) {
243 return this->translateExpression(term[0]);
246 for (
size_t i = 1;
i < term.getNumChildren(); ++
i) {
247 retVal = retVal || this->translateExpression(term[i]);
252 case cvc5::Kind::XOR:
254 case cvc5::Kind::NOT:
255 return !this->translateExpression(term[0]);
256 case cvc5::Kind::IMPLIES:
258 case cvc5::Kind::LEQ:
259 return this->translateExpression(term[0]) <= this->translateExpression(term[1]);
260 case cvc5::Kind::GEQ:
261 return this->translateExpression(term[0]) >= this->translateExpression(term[1]);
263 return this->translateExpression(term[0]) < this->translateExpression(term[1]);
265 return this->translateExpression(term[0]) > this->translateExpression(term[1]);
266 case cvc5::Kind::ADD: {
268 std::vector<storm::expressions::Expression> operands;
269 operands.reserve(term.getNumChildren());
270 for (
size_t i = 0;
i < term.getNumChildren(); ++
i) {
271 operands.push_back(this->translateExpression(term[i]));
276 case cvc5::Kind::SUB:
277 return this->translateExpression(term[0]) - this->translateExpression(term[1]);
278 case cvc5::Kind::NEG:
279 return -this->translateExpression(term[0]);
280 case cvc5::Kind::MULT: {
282 std::vector<storm::expressions::Expression> operands;
283 operands.reserve(term.getNumChildren());
284 for (
size_t i = 0;
i < term.getNumChildren(); ++
i) {
285 operands.push_back(this->translateExpression(term[i]));
290 case cvc5::Kind::INTS_DIVISION:
292 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Failed to convert cvc5 expression. Integer division is not supported.");
293 case cvc5::Kind::DIVISION:
294 return this->translateExpression(term[0]) / this->translateExpression(term[1]);
295 case cvc5::Kind::POW:
297 case cvc5::Kind::TO_REAL:
298 return this->translateExpression(term[0]);
299 case cvc5::Kind::TO_INTEGER:
302 case cvc5::Kind::ABS:
305 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
306 "Failed to convert cvc5 expression. Encountered unhandled kind " << term.getKind() <<
".");
309 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
"Failed to convert cvc5 expression.");
313 auto const& constantVariablePair = expressionToVariableMapping.find(constant);
314 STORM_LOG_THROW(constantVariablePair != expressionToVariableMapping.end(), storm::exceptions::ExpressionEvaluationException,
315 "Unable to find the variable corresponding to the given constant.");
316 return constantVariablePair->second;
320 auto cacheIt = expressionCache.find(&expression);
321 if (cacheIt != expressionCache.end()) {
322 return cacheIt->second;
325 cvc5::Term leftResult = boost::any_cast<cvc5::Term>(expression.
getFirstOperand()->accept(*
this, data));
326 cvc5::Term rightResult = boost::any_cast<cvc5::Term>(expression.
getSecondOperand()->accept(*
this, data));
331 kind = cvc5::Kind::AND;
334 kind = cvc5::Kind::OR;
337 kind = cvc5::Kind::XOR;
340 kind = cvc5::Kind::IMPLIES;
343 kind = cvc5::Kind::EQUAL;
346 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
347 "Cannot evaluate expression: unknown boolean binary operator '" <<
static_cast<int>(expression.
getOperatorType())
348 <<
"' in expression " << expression <<
".");
351 cvc5::Term result = this->termManager.mkTerm(kind, {leftResult, rightResult});
353 expressionCache.emplace(&expression, result);
357cvc5::Term Cvc5ExpressionAdapter::convertToRealIfExpected(cvc5::Term
const& term,
bool const& isRealExpected)
const {
358 if (isRealExpected && term.getSort().isInteger()) {
359 return this->termManager.mkTerm(cvc5::Kind::TO_REAL, {term});
364void Cvc5ExpressionAdapter::unifyNumericalTypes(cvc5::Term& leftTerm, cvc5::Term& rightTerm)
const {
365 if (leftTerm.getSort().isInteger() && rightTerm.getSort().isReal()) {
366 leftTerm = this->termManager.mkTerm(cvc5::Kind::TO_REAL, {leftTerm});
367 }
else if (rightTerm.getSort().isInteger() && leftTerm.getSort().isReal()) {
368 rightTerm = this->termManager.mkTerm(cvc5::Kind::TO_REAL, {rightTerm});
373 auto cacheIt = expressionCache.find(&expression);
374 if (cacheIt != expressionCache.end()) {
375 return cacheIt->second;
378 cvc5::Term leftResult = boost::any_cast<cvc5::Term>(expression.
getFirstOperand()->accept(*
this, data));
379 cvc5::Term rightResult = boost::any_cast<cvc5::Term>(expression.
getSecondOperand()->accept(*
this, data));
384 leftResult = this->convertToRealIfExpected(leftResult, isRealExpected);
385 rightResult = this->convertToRealIfExpected(rightResult, isRealExpected);
392 leftResult = this->convertToRealIfExpected(leftResult,
true);
393 rightResult = this->convertToRealIfExpected(rightResult,
true);
398 this->unifyNumericalTypes(leftResult, rightResult);
403 result = this->termManager.mkTerm(cvc5::Kind::ADD, {leftResult, rightResult});
406 result = this->termManager.mkTerm(cvc5::Kind::SUB, {leftResult, rightResult});
409 result = this->termManager.mkTerm(cvc5::Kind::MULT, {leftResult, rightResult});
412 result = this->termManager.mkTerm(cvc5::Kind::DIVISION, {leftResult, rightResult});
415 result = this->termManager.mkTerm(cvc5::Kind::ITE, {this->termManager.mkTerm(cvc5::Kind::LEQ, {leftResult, rightResult}), leftResult, rightResult});
418 result = this->termManager.mkTerm(cvc5::Kind::ITE, {this->termManager.mkTerm(cvc5::Kind::GEQ, {leftResult, rightResult}), leftResult, rightResult});
421 result = this->termManager.mkTerm(cvc5::Kind::POW, {leftResult, rightResult});
424 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
425 "Cannot evaluate expression: unknown numerical binary operator '" <<
static_cast<int>(expression.
getOperatorType())
426 <<
"' in expression " << expression <<
".");
429 expressionCache.emplace(&expression, result);
434 auto cacheIt = expressionCache.find(&expression);
435 if (cacheIt != expressionCache.end()) {
436 return cacheIt->second;
439 cvc5::Term leftResult = boost::any_cast<cvc5::Term>(expression.
getFirstOperand()->accept(*
this, data));
440 cvc5::Term rightResult = boost::any_cast<cvc5::Term>(expression.
getSecondOperand()->accept(*
this, data));
444 this->unifyNumericalTypes(leftResult, rightResult);
449 kind = cvc5::Kind::EQUAL;
452 kind = cvc5::Kind::DISTINCT;
455 kind = cvc5::Kind::LT;
458 kind = cvc5::Kind::LEQ;
461 kind = cvc5::Kind::GT;
464 kind = cvc5::Kind::GEQ;
467 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
468 "Cannot evaluate expression: unknown boolean binary operator '" <<
static_cast<int>(expression.
getRelationType())
469 <<
"' in expression " << expression <<
".");
472 cvc5::Term result = this->termManager.mkTerm(kind, {leftResult, rightResult});
474 expressionCache.emplace(&expression, result);
479 auto cacheIt = expressionCache.find(&expression);
480 if (cacheIt != expressionCache.end()) {
481 return cacheIt->second;
484 cvc5::Term result = this->termManager.mkBoolean(expression.
getValue());
486 expressionCache.emplace(&expression, result);
491 auto cacheIt = expressionCache.find(&expression);
492 if (cacheIt != expressionCache.end()) {
493 return cacheIt->second;
496 cvc5::Term result = this->createRational(expression.
getValue());
498 expressionCache.emplace(&expression, result);
503 auto cacheIt = expressionCache.find(&expression);
504 if (cacheIt != expressionCache.end()) {
505 return cacheIt->second;
508 cvc5::Term result = this->termManager.mkInteger(
static_cast<int64_t
>(expression.
getValue()));
510 expressionCache.emplace(&expression, result);
515 auto cacheIt = expressionCache.find(&expression);
516 if (cacheIt != expressionCache.end()) {
517 return cacheIt->second;
520 cvc5::Term result = boost::any_cast<cvc5::Term>(expression.
getOperand()->accept(*
this, data));
524 result = this->termManager.mkTerm(cvc5::Kind::NOT, {result});
527 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
528 "Cannot evaluate expression: unknown boolean unary operator '" <<
static_cast<int>(expression.
getOperatorType())
529 <<
"' in expression " << expression <<
".");
532 expressionCache.emplace(&expression, result);
537 auto cacheIt = expressionCache.find(&expression);
538 if (cacheIt != expressionCache.end()) {
539 return cacheIt->second;
542 cvc5::Term result = boost::any_cast<cvc5::Term>(expression.
getOperand()->accept(*
this, data));
546 result = this->termManager.mkTerm(cvc5::Kind::NEG, {result});
550 result = this->termManager.mkTerm(cvc5::Kind::TO_INTEGER, {result});
555 result = this->termManager.mkTerm(cvc5::Kind::NEG,
556 {this->termManager.mkTerm(cvc5::Kind::TO_INTEGER, {this->termManager.mkTerm(cvc5::Kind::NEG, {result})})});
560 STORM_LOG_THROW(
false, storm::exceptions::ExpressionEvaluationException,
561 "Cannot evaluate expression: unknown numerical unary operator '" <<
static_cast<int>(expression.
getOperatorType())
562 <<
"' in expression " << expression <<
".");
565 expressionCache.emplace(&expression, result);
570 auto cacheIt = expressionCache.find(&expression);
571 if (cacheIt != expressionCache.end()) {
572 return cacheIt->second;
575 cvc5::Term conditionResult = boost::any_cast<cvc5::Term>(expression.
getCondition()->accept(*
this, data));
576 cvc5::Term thenResult = boost::any_cast<cvc5::Term>(expression.
getThenExpression()->accept(*
this, data));
577 cvc5::Term elseResult = boost::any_cast<cvc5::Term>(expression.
getElseExpression()->accept(*
this, data));
581 this->unifyNumericalTypes(thenResult, elseResult);
583 cvc5::Term result = this->termManager.mkTerm(cvc5::Kind::ITE, {conditionResult, thenResult, elseResult});
585 expressionCache.emplace(&expression, result);
590 return this->translateExpression(expression.
getVariable());
593cvc5::Term Cvc5ExpressionAdapter::createRational(storm::RationalNumber
const& value) {
595 std::stringstream fractionStream;
596 fractionStream << value;
597 return this->termManager.mkReal(fractionStream.str());
603 sort = this->termManager.getBooleanSort();
605 sort = this->termManager.getRealSort();
610 "Encountered variable '" << variable.
getName() <<
"' with unknown type while trying to create solver variables.");
611 sort = this->termManager.getIntegerSort();
613 cvc5::Term cvc5Variable = this->termManager.mkConst(sort, variable.
getName());
614 variableToExpressionMapping.insert(std::make_pair(variable, cvc5Variable));
615 expressionToVariableMapping.insert(std::make_pair(cvc5Variable, variable));
virtual boost::any accept(ExpressionVisitor &visitor, boost::any const &data) const =0
Accepts the given visitor by calling its visit method.
Type const & getType() const
Retrieves the type of the expression.
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.
bool hasBooleanType() const
Retrieves whether the expression has a boolean return type.
BaseExpression const & getBaseExpression() const
Retrieves the base expression underlying this expression object.
ExpressionManager const & getManager() const
Retrieves the manager responsible for this expression.
Expression integer(int_fast64_t value) const
Creates an expression that characterizes the given integer literal.
Expression boolean(bool value) const
Creates an expression that characterizes the given boolean literal.
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.
bool isIntegerType() const
Checks whether this type is an integral type.
bool isRationalType() const
Checks whether this type is a rational 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_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 abs(Expression const &first)
Expression sum(std::vector< storm::expressions::Expression > const &expressions)
Expression product(std::vector< storm::expressions::Expression > const &expressions)
Expression pow(Expression const &base, Expression const &exponent, bool allowIntegerType)
The type of the resulting expression is.
Expression floor(Expression const &first)
Expression xclusiveor(Expression const &first, Expression const &second)
Expression implies(Expression const &first, Expression const &second)
SettingsManager const & manager()
Retrieves the settings manager.
NumberTraits< RationalType >::IntegerType denominator(RationalType const &number)
NumberTraits< RationalType >::IntegerType numerator(RationalType const &number)
TargetType convertNumber(SourceType const &number)