Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
MathsatExpressionAdapter.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <sstream>
5#include <string>
6
15
16#ifdef STORM_HAVE_MATHSAT
17
18bool operator==(msat_decl decl1, msat_decl decl2) {
19 return decl1.repr == decl2.repr;
20}
21
22namespace storm {
23namespace adapters {
24
25MathsatExpressionAdapter::MathsatExpressionAdapter(storm::expressions::ExpressionManager& manager, msat_env& env)
26 : manager(manager), env(env), variableToDeclarationMapping() {
27 // Intentionally left empty.
28}
29
30msat_term MathsatExpressionAdapter::translateExpression(storm::expressions::Expression const& expression) {
31 additionalConstraints.clear();
32 msat_term result = boost::any_cast<msat_term>(expression.getBaseExpression().accept(*this, boost::none));
33 if (MSAT_ERROR_TERM(result)) {
34 std::string errorMessage(msat_last_error_message(env));
35 STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException,
36 "Could not translate expression to MathSAT's format. (Message: " << errorMessage << ").");
37 }
38
39 return result;
40}
41
42msat_term MathsatExpressionAdapter::translateExpression(storm::expressions::Variable const& variable) {
43 STORM_LOG_ASSERT(variable.getManager() == this->manager, "Invalid expression for solver.");
44
45 auto const& variableExpressionPair = variableToDeclarationMapping.find(variable);
46 if (variableExpressionPair == variableToDeclarationMapping.end()) {
47 return msat_make_constant(env, createVariable(variable));
48 }
49 return msat_make_constant(env, variableExpressionPair->second);
50}
51
52bool MathsatExpressionAdapter::hasAdditionalConstraints() const {
53 return !additionalConstraints.empty();
54}
55
56std::vector<msat_term> const& MathsatExpressionAdapter::getAdditionalConstraints() const {
57 return additionalConstraints;
58}
59
60storm::expressions::Variable const& MathsatExpressionAdapter::getVariable(msat_decl msatVariableDeclaration) const {
61 auto const& declarationVariablePair = declarationToVariableMapping.find(msatVariableDeclaration);
62 STORM_LOG_ASSERT(declarationVariablePair != declarationToVariableMapping.end(), "Unknown variable declaration.");
63 return declarationVariablePair->second;
64}
65
66std::unordered_map<storm::expressions::Variable, msat_decl> const& MathsatExpressionAdapter::getAllDeclaredVariables() const {
67 return variableToDeclarationMapping;
68}
69
70boost::any MathsatExpressionAdapter::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
71 msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
72 msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
73
74 switch (expression.getOperatorType()) {
76 return msat_make_and(env, leftResult, rightResult);
78 return msat_make_or(env, leftResult, rightResult);
80 return msat_make_iff(env, leftResult, rightResult);
82 return msat_make_or(env, msat_make_not(env, leftResult), rightResult);
83 default:
84 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
85 "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<uint_fast64_t>(expression.getOperatorType())
86 << "' in expression " << expression << ".");
87 }
88}
89
90boost::any MathsatExpressionAdapter::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
91 msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
92 msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
93
94 msat_term result = leftResult;
95 int_fast64_t exponent;
96 int_fast64_t modulus;
97 storm::expressions::Variable freshAuxiliaryVariable;
98 msat_term modVariable;
99 msat_term lower;
100 msat_term upper;
102 switch (expression.getOperatorType()) {
104 return msat_make_plus(env, leftResult, rightResult);
106 return msat_make_plus(env, leftResult, msat_make_times(env, msat_make_number(env, "-1"), rightResult));
108 return msat_make_times(env, leftResult, rightResult);
110 return msat_make_divide(env, leftResult, rightResult);
112 return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), leftResult, rightResult);
114 return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), rightResult, leftResult);
116 exponent = expression.getSecondOperand()->evaluateAsInt();
117 STORM_LOG_THROW(exponent >= 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative exponent.");
118 --exponent;
119 if (exponent > 0) {
120 for (; exponent > 0; --exponent) {
121 result = msat_make_times(env, result, leftResult);
122 }
123 }
124 return result;
126 modulus = expression.getSecondOperand()->evaluateAsInt();
127 STORM_LOG_THROW(modulus > 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative modulus.");
128
129 freshAuxiliaryVariable = manager.declareFreshVariable(manager.getIntegerType(), true);
130 modVariable = msat_make_constant(env, createVariable(freshAuxiliaryVariable));
131
132 gmpModulus = typename storm::NumberTraits<storm::GmpRationalNumber>::IntegerType(static_cast<unsigned>(modulus));
133
134 // Create the constraint that fixes the value of the fresh variable.
135 additionalConstraints.push_back(msat_make_int_modular_congruence(env, gmpModulus.get_mpz_t(), modVariable, leftResult));
136
137 // Create the constraint that limits the value of the modulo operation to 0 <= val <= modulus-1.
138 lower = msat_make_number(env, "-1");
139 upper = msat_make_number(env, std::to_string(modulus - 1).c_str());
140 additionalConstraints.push_back(
141 msat_make_and(env, msat_make_not(env, msat_make_leq(env, modVariable, lower)), msat_make_leq(env, modVariable, upper)));
142 return modVariable;
143 default:
144 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
145 "Cannot evaluate expression: unknown numerical binary operator '" << static_cast<uint_fast64_t>(expression.getOperatorType())
146 << "' in expression " << expression << ".");
147 }
148}
149
150boost::any MathsatExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) {
151 msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
152 msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
153
154 switch (expression.getRelationType()) {
156 if (expression.getFirstOperand()->getType().isBooleanType() && expression.getSecondOperand()->getType().isBooleanType()) {
157 return msat_make_iff(env, leftResult, rightResult);
158 } else {
159 return msat_make_equal(env, leftResult, rightResult);
160 }
162 if (expression.getFirstOperand()->getType().isBooleanType() && expression.getSecondOperand()->getType().isBooleanType()) {
163 return msat_make_not(env, msat_make_iff(env, leftResult, rightResult));
164 } else {
165 return msat_make_not(env, msat_make_equal(env, leftResult, rightResult));
166 }
168 return msat_make_and(env, msat_make_not(env, msat_make_equal(env, leftResult, rightResult)), msat_make_leq(env, leftResult, rightResult));
170 return msat_make_leq(env, leftResult, rightResult);
172 return msat_make_not(env, msat_make_leq(env, leftResult, rightResult));
174 return msat_make_or(env, msat_make_equal(env, leftResult, rightResult), msat_make_not(env, msat_make_leq(env, leftResult, rightResult)));
175 default:
176 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
177 "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<uint_fast64_t>(expression.getRelationType())
178 << "' in expression " << expression << ".");
179 }
180}
181
182boost::any MathsatExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
183 msat_term conditionResult = boost::any_cast<msat_term>(expression.getCondition()->accept(*this, data));
184 msat_term thenResult = boost::any_cast<msat_term>(expression.getThenExpression()->accept(*this, data));
185 msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this, data));
186
187 // MathSAT does not allow ite with boolean arguments, so we have to encode it ourselves.
188 if (expression.getThenExpression()->hasBooleanType() && expression.getElseExpression()->hasBooleanType()) {
189 return msat_make_and(env, msat_make_or(env, msat_make_not(env, conditionResult), thenResult), msat_make_or(env, conditionResult, elseResult));
190 } else {
191 return msat_make_term_ite(env, conditionResult, thenResult, elseResult);
192 }
193}
194
195boost::any MathsatExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) {
196 return expression.getValue() ? msat_make_true(env) : msat_make_false(env);
197}
198
199boost::any MathsatExpressionAdapter::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) {
200 std::stringstream fractionStream;
201 fractionStream << expression.getValue();
202 return msat_make_number(env, fractionStream.str().c_str());
203}
204
205boost::any MathsatExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) {
206 return msat_make_number(env, std::to_string(static_cast<int>(expression.getValue())).c_str());
207}
208
209boost::any MathsatExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
210 msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
211
212 switch (expression.getOperatorType()) {
214 return msat_make_not(env, childResult);
215 break;
216 default:
217 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
218 "Cannot evaluate expression: unknown boolean unary operator: '" << static_cast<uint_fast64_t>(expression.getOperatorType())
219 << "' in expression " << expression << ".");
220 }
221}
222
223boost::any MathsatExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
224 msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
225
226 switch (expression.getOperatorType()) {
228 return msat_make_times(env, msat_make_number(env, "-1"), childResult);
230 return msat_make_floor(env, childResult);
232 // Mathsat does not support ceil... but ceil(x) = -floor(-x) wheeii \o/
233 return msat_make_times(env, msat_make_number(env, "-1"), msat_make_floor(env, msat_make_times(env, msat_make_number(env, "-1"), childResult)));
234 default:
235 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
236 "Cannot evaluate expression: unknown numerical unary operator: '" << static_cast<uint_fast64_t>(expression.getOperatorType())
237 << "' in expression " << expression << ".");
238 }
239}
240
241boost::any MathsatExpressionAdapter::visit(storm::expressions::VariableExpression const& expression, boost::any const&) {
242 return translateExpression(expression.getVariable());
243}
244
245storm::expressions::Expression MathsatExpressionAdapter::translateExpression(msat_term const& term) {
246 if (msat_term_is_and(env, term)) {
247 return translateExpression(msat_term_get_arg(term, 0)) && translateExpression(msat_term_get_arg(term, 1));
248 } else if (msat_term_is_or(env, term)) {
249 return translateExpression(msat_term_get_arg(term, 0)) || translateExpression(msat_term_get_arg(term, 1));
250 } else if (msat_term_is_iff(env, term)) {
251 return storm::expressions::iff(translateExpression(msat_term_get_arg(term, 0)), translateExpression(msat_term_get_arg(term, 1)));
252 } else if (msat_term_is_not(env, term)) {
253 return !translateExpression(msat_term_get_arg(term, 0));
254 } else if (msat_term_is_plus(env, term)) {
255 return translateExpression(msat_term_get_arg(term, 0)) + translateExpression(msat_term_get_arg(term, 1));
256 } else if (msat_term_is_times(env, term)) {
257 return translateExpression(msat_term_get_arg(term, 0)) * translateExpression(msat_term_get_arg(term, 1));
258 } else if (msat_term_is_equal(env, term)) {
259 return translateExpression(msat_term_get_arg(term, 0)) == translateExpression(msat_term_get_arg(term, 1));
260 } else if (msat_term_is_leq(env, term)) {
261 return translateExpression(msat_term_get_arg(term, 0)) <= translateExpression(msat_term_get_arg(term, 1));
262 } else if (msat_term_is_true(env, term)) {
263 return manager.boolean(true);
264 } else if (msat_term_is_false(env, term)) {
265 return manager.boolean(false);
266 } else if (msat_term_is_constant(env, term)) {
267 char* name = msat_decl_get_name(msat_term_get_decl(term));
268 std::string nameString(name);
269 storm::expressions::Expression result = manager.getVariableExpression(nameString.substr(0, nameString.find('/')));
270 msat_free(name);
271 return result;
272 } else if (msat_term_is_number(env, term)) {
273 char* termAsCString = msat_term_repr(term);
274 std::string termString(termAsCString);
275 msat_free(termAsCString);
276 if (msat_is_integer_type(env, msat_term_get_type(term))) {
277 return manager.integer(std::stoll(msat_term_repr(term)));
278 } else if (msat_is_rational_type(env, msat_term_get_type(term))) {
280 }
281 } else if (msat_term_is_term_ite(env, term)) {
282 return storm::expressions::ite(translateExpression(msat_term_get_arg(term, 0)), translateExpression(msat_term_get_arg(term, 1)),
283 translateExpression(msat_term_get_arg(term, 2)));
284 }
285
286 // If all other cases did not apply, we cannot represent the term in our expression framework.
287 char* termAsCString = msat_term_repr(term);
288 std::string termString(termAsCString);
289 msat_free(termAsCString);
290 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot translate expression: unknown term: '" << termString << "'.");
291}
292
293msat_decl MathsatExpressionAdapter::createVariable(storm::expressions::Variable const& variable) {
294 msat_decl msatDeclaration;
295 if (variable.getType().isBooleanType()) {
296 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_bool_type(env));
297 } else if (variable.getType().isIntegerType()) {
298 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_integer_type(env));
299 } else if (variable.getType().isBitVectorType()) {
300 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_bv_type(env, variable.getType().getWidth()));
301 } else if (variable.getType().isRationalType()) {
302 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_rational_type(env));
303 } else {
304 STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException,
305 "Encountered variable '" << variable.getName() << "' with unknown type while trying to create solver variables.");
306 }
307 variableToDeclarationMapping.insert(std::make_pair(variable, msatDeclaration));
308 declarationToVariableMapping.insert(std::make_pair(msatDeclaration, variable));
309 return msatDeclaration;
310}
311
312} // namespace adapters
313} // namespace storm
314
315#endif // STORM_HAVE_MATHSAT
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.
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.
Definition Type.cpp:194
std::size_t getWidth() const
Retrieves the bit width of the type, provided that it is a bitvector type.
Definition Type.cpp:226
bool isIntegerType() const
Checks whether this type is an integral type.
Definition Type.cpp:198
bool isRationalType() const
Checks whether this type is a rational type.
Definition Type.cpp:234
bool isBitVectorType() const
Checks whether this type is a bitvector type.
Definition Type.cpp:202
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.
Definition Variable.cpp:54
Type const & getType() const
Retrieves the type of the variable.
Definition Variable.cpp:50
std::string const & getName() const
Retrieves the name of the variable.
Definition Variable.cpp:46
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
bool operator==(BEColourClass< ValueType > const &lhs, BEColourClass< ValueType > const &rhs)
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
Expression iff(Expression const &first, Expression const &second)
SettingsManager const & manager()
Retrieves the settings manager.
TargetType convertNumber(SourceType const &number)