Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
MathsatExpressionAdapter.h
Go to the documentation of this file.
1#ifndef STORM_ADAPTERS_MATHSATEXPRESSIONADAPTER_H_
2#define STORM_ADAPTERS_MATHSATEXPRESSIONADAPTER_H_
3
4#include "storm-config.h"
5
6#include <stack>
7
8#ifdef STORM_HAVE_MSAT
9#include "mathsat.h"
10#endif
11
21
22#ifdef STORM_HAVE_MSAT
23namespace std {
24// Define hashing operator for MathSAT's declarations.
25template<>
26struct hash<msat_decl> {
27 size_t operator()(msat_decl const& declaration) const {
28 return hash<void*>()(declaration.repr);
29 }
30};
31} // namespace std
32
33// Define equality operator to make hashing work.
34bool operator==(msat_decl decl1, msat_decl decl2);
35#endif
36
37namespace storm {
38namespace adapters {
39
40#ifdef STORM_HAVE_MSAT
41
42class MathsatExpressionAdapter : public storm::expressions::ExpressionVisitor {
43 public:
50 MathsatExpressionAdapter(storm::expressions::ExpressionManager& manager, msat_env& env) : manager(manager), env(env), variableToDeclarationMapping() {
51 // Intentionally left empty.
52 }
53
60 msat_term translateExpression(storm::expressions::Expression const& expression) {
61 additionalConstraints.clear();
62 msat_term result = boost::any_cast<msat_term>(expression.getBaseExpression().accept(*this, boost::none));
63 if (MSAT_ERROR_TERM(result)) {
64 std::string errorMessage(msat_last_error_message(env));
65 STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException,
66 "Could not translate expression to MathSAT's format. (Message: " << errorMessage << ")");
67 }
68
69 return result;
70 }
71
78 msat_term translateExpression(storm::expressions::Variable const& variable) {
79 STORM_LOG_ASSERT(variable.getManager() == this->manager, "Invalid expression for solver.");
80
81 auto const& variableExpressionPair = variableToDeclarationMapping.find(variable);
82 if (variableExpressionPair == variableToDeclarationMapping.end()) {
83 return msat_make_constant(env, createVariable(variable));
84 }
85 return msat_make_constant(env, variableExpressionPair->second);
86 }
87
88 bool hasAdditionalConstraints() const {
89 return !additionalConstraints.empty();
90 }
91
95 std::vector<msat_term> const& getAdditionalConstraints() const {
96 return additionalConstraints;
97 }
98
105 storm::expressions::Variable const& getVariable(msat_decl msatVariableDeclaration) const {
106 auto const& declarationVariablePair = declarationToVariableMapping.find(msatVariableDeclaration);
107 STORM_LOG_ASSERT(declarationVariablePair != declarationToVariableMapping.end(), "Unknown variable declaration.");
108 return declarationVariablePair->second;
109 }
110
111 std::unordered_map<storm::expressions::Variable, msat_decl> const& getAllDeclaredVariables() const {
112 return variableToDeclarationMapping;
113 }
114
115 virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override {
116 msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
117 msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
118
119 switch (expression.getOperatorType()) {
121 return msat_make_and(env, leftResult, rightResult);
123 return msat_make_or(env, leftResult, rightResult);
125 return msat_make_iff(env, leftResult, rightResult);
127 return msat_make_or(env, msat_make_not(env, leftResult), rightResult);
128 default:
129 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
130 "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<uint_fast64_t>(expression.getOperatorType())
131 << "' in expression " << expression << ".");
132 }
133 }
134
135 virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override {
136 msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
137 msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
138
139 msat_term result = leftResult;
140 int_fast64_t exponent;
141 int_fast64_t modulus;
142 storm::expressions::Variable freshAuxiliaryVariable;
143 msat_term modVariable;
144 msat_term lower;
145 msat_term upper;
147 switch (expression.getOperatorType()) {
149 return msat_make_plus(env, leftResult, rightResult);
151 return msat_make_plus(env, leftResult, msat_make_times(env, msat_make_number(env, "-1"), rightResult));
153 return msat_make_times(env, leftResult, rightResult);
155 return msat_make_divide(env, leftResult, rightResult);
157 return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), leftResult, rightResult);
159 return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), rightResult, leftResult);
161 exponent = expression.getSecondOperand()->evaluateAsInt();
162 STORM_LOG_THROW(exponent >= 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative exponent.");
163 --exponent;
164 if (exponent > 0) {
165 for (; exponent > 0; --exponent) {
166 result = msat_make_times(env, result, leftResult);
167 }
168 }
169 return result;
171 modulus = expression.getSecondOperand()->evaluateAsInt();
172 STORM_LOG_THROW(modulus > 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative modulus.");
173
174 freshAuxiliaryVariable = manager.declareFreshVariable(manager.getIntegerType(), true);
175 modVariable = msat_make_constant(env, createVariable(freshAuxiliaryVariable));
176
177 gmpModulus = typename storm::NumberTraits<storm::GmpRationalNumber>::IntegerType(static_cast<unsigned>(modulus));
178
179 // Create the constraint that fixes the value of the fresh variable.
180 additionalConstraints.push_back(msat_make_int_modular_congruence(env, gmpModulus.get_mpz_t(), modVariable, leftResult));
181
182 // Create the constraint that limits the value of the modulo operation to 0 <= val <= modulus-1.
183 lower = msat_make_number(env, "-1");
184 upper = msat_make_number(env, std::to_string(modulus - 1).c_str());
185 additionalConstraints.push_back(
186 msat_make_and(env, msat_make_not(env, msat_make_leq(env, modVariable, lower)), msat_make_leq(env, modVariable, upper)));
187 return modVariable;
188 default:
189 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
190 "Cannot evaluate expression: unknown numerical binary operator '" << static_cast<uint_fast64_t>(expression.getOperatorType())
191 << "' in expression " << expression << ".");
192 }
193 }
194
195 virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override {
196 msat_term leftResult = boost::any_cast<msat_term>(expression.getFirstOperand()->accept(*this, data));
197 msat_term rightResult = boost::any_cast<msat_term>(expression.getSecondOperand()->accept(*this, data));
198
199 switch (expression.getRelationType()) {
201 if (expression.getFirstOperand()->getType().isBooleanType() && expression.getSecondOperand()->getType().isBooleanType()) {
202 return msat_make_iff(env, leftResult, rightResult);
203 } else {
204 return msat_make_equal(env, leftResult, rightResult);
205 }
207 if (expression.getFirstOperand()->getType().isBooleanType() && expression.getSecondOperand()->getType().isBooleanType()) {
208 return msat_make_not(env, msat_make_iff(env, leftResult, rightResult));
209 } else {
210 return msat_make_not(env, msat_make_equal(env, leftResult, rightResult));
211 }
213 return msat_make_and(env, msat_make_not(env, msat_make_equal(env, leftResult, rightResult)), msat_make_leq(env, leftResult, rightResult));
215 return msat_make_leq(env, leftResult, rightResult);
217 return msat_make_not(env, msat_make_leq(env, leftResult, rightResult));
219 return msat_make_or(env, msat_make_equal(env, leftResult, rightResult), msat_make_not(env, msat_make_leq(env, leftResult, rightResult)));
220 default:
221 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
222 "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<uint_fast64_t>(expression.getRelationType())
223 << "' in expression " << expression << ".");
224 }
225 }
226
227 virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override {
228 msat_term conditionResult = boost::any_cast<msat_term>(expression.getCondition()->accept(*this, data));
229 msat_term thenResult = boost::any_cast<msat_term>(expression.getThenExpression()->accept(*this, data));
230 msat_term elseResult = boost::any_cast<msat_term>(expression.getElseExpression()->accept(*this, data));
231
232 // MathSAT does not allow ite with boolean arguments, so we have to encode it ourselves.
233 if (expression.getThenExpression()->hasBooleanType() && expression.getElseExpression()->hasBooleanType()) {
234 return msat_make_and(env, msat_make_or(env, msat_make_not(env, conditionResult), thenResult), msat_make_or(env, conditionResult, elseResult));
235 } else {
236 return msat_make_term_ite(env, conditionResult, thenResult, elseResult);
237 }
238 }
239
240 virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) override {
241 return expression.getValue() ? msat_make_true(env) : msat_make_false(env);
242 }
243
244 virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override {
245 std::stringstream fractionStream;
246 fractionStream << expression.getValue();
247 return msat_make_number(env, fractionStream.str().c_str());
248 }
249
250 virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override {
251 return msat_make_number(env, std::to_string(static_cast<int>(expression.getValue())).c_str());
252 }
253
254 virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override {
255 msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
256
257 switch (expression.getOperatorType()) {
259 return msat_make_not(env, childResult);
260 break;
261 default:
262 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
263 "Cannot evaluate expression: unknown boolean unary operator: '" << static_cast<uint_fast64_t>(expression.getOperatorType())
264 << "' in expression " << expression << ".");
265 }
266 }
267
268 virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override {
269 msat_term childResult = boost::any_cast<msat_term>(expression.getOperand()->accept(*this, data));
270
271 switch (expression.getOperatorType()) {
273 return msat_make_times(env, msat_make_number(env, "-1"), childResult);
275 return msat_make_floor(env, childResult);
277 // Mathsat does not support ceil... but ceil(x) = -floor(-x) wheeii \o/
278 return msat_make_times(env, msat_make_number(env, "-1"), msat_make_floor(env, msat_make_times(env, msat_make_number(env, "-1"), childResult)));
279 default:
280 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException,
281 "Cannot evaluate expression: unknown numerical unary operator: '" << static_cast<uint_fast64_t>(expression.getOperatorType())
282 << "' in expression " << expression << ".");
283 }
284 }
285
286 virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const&) override {
287 return translateExpression(expression.getVariable());
288 }
289
290 storm::expressions::Expression translateExpression(msat_term const& term) {
291 if (msat_term_is_and(env, term)) {
292 return translateExpression(msat_term_get_arg(term, 0)) && translateExpression(msat_term_get_arg(term, 1));
293 } else if (msat_term_is_or(env, term)) {
294 return translateExpression(msat_term_get_arg(term, 0)) || translateExpression(msat_term_get_arg(term, 1));
295 } else if (msat_term_is_iff(env, term)) {
296 return storm::expressions::iff(translateExpression(msat_term_get_arg(term, 0)), translateExpression(msat_term_get_arg(term, 1)));
297 } else if (msat_term_is_not(env, term)) {
298 return !translateExpression(msat_term_get_arg(term, 0));
299 } else if (msat_term_is_plus(env, term)) {
300 return translateExpression(msat_term_get_arg(term, 0)) + translateExpression(msat_term_get_arg(term, 1));
301 } else if (msat_term_is_times(env, term)) {
302 return translateExpression(msat_term_get_arg(term, 0)) * translateExpression(msat_term_get_arg(term, 1));
303 } else if (msat_term_is_equal(env, term)) {
304 return translateExpression(msat_term_get_arg(term, 0)) == translateExpression(msat_term_get_arg(term, 1));
305 } else if (msat_term_is_leq(env, term)) {
306 return translateExpression(msat_term_get_arg(term, 0)) <= translateExpression(msat_term_get_arg(term, 1));
307 } else if (msat_term_is_true(env, term)) {
308 return manager.boolean(true);
309 } else if (msat_term_is_false(env, term)) {
310 return manager.boolean(false);
311 } else if (msat_term_is_constant(env, term)) {
312 char* name = msat_decl_get_name(msat_term_get_decl(term));
313 std::string nameString(name);
314 storm::expressions::Expression result = manager.getVariableExpression(nameString.substr(0, nameString.find('/')));
315 msat_free(name);
316 return result;
317 } else if (msat_term_is_number(env, term)) {
318 char* termAsCString = msat_term_repr(term);
319 std::string termString(termAsCString);
320 msat_free(termAsCString);
321 if (msat_is_integer_type(env, msat_term_get_type(term))) {
322 return manager.integer(std::stoll(msat_term_repr(term)));
323 } else if (msat_is_rational_type(env, msat_term_get_type(term))) {
324 return manager.rational(storm::utility::convertNumber<storm::RationalNumber>(termString));
325 }
326 } else if (msat_term_is_term_ite(env, term)) {
327 return storm::expressions::ite(translateExpression(msat_term_get_arg(term, 0)), translateExpression(msat_term_get_arg(term, 1)),
328 translateExpression(msat_term_get_arg(term, 2)));
329 }
330
331 // If all other cases did not apply, we cannot represent the term in our expression framework.
332 char* termAsCString = msat_term_repr(term);
333 std::string termString(termAsCString);
334 msat_free(termAsCString);
335 STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot translate expression: unknown term: '" << termString << "'.");
336 }
337
338 private:
344 msat_decl createVariable(storm::expressions::Variable const& variable) {
345 msat_decl msatDeclaration;
346 if (variable.getType().isBooleanType()) {
347 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_bool_type(env));
348 } else if (variable.getType().isIntegerType()) {
349 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_integer_type(env));
350 } else if (variable.getType().isBitVectorType()) {
351 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_bv_type(env, variable.getType().getWidth()));
352 } else if (variable.getType().isRationalType()) {
353 msatDeclaration = msat_declare_function(env, variable.getName().c_str(), msat_get_rational_type(env));
354 } else {
355 STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException,
356 "Encountered variable '" << variable.getName() << "' with unknown type while trying to create solver variables.");
357 }
358 variableToDeclarationMapping.insert(std::make_pair(variable, msatDeclaration));
359 declarationToVariableMapping.insert(std::make_pair(msatDeclaration, variable));
360 return msatDeclaration;
361 }
362
363 // The expression manager to use.
365
366 // The MathSAT environment used.
367 msat_env& env;
368
369 // A vector of constraints that need to be kept separate, because they were only implicitly part of an
370 // assertion that was added.
371 std::vector<msat_term> additionalConstraints;
372
373 // A mapping of variable names to their declaration in the MathSAT environment.
374 std::unordered_map<storm::expressions::Variable, msat_decl> variableToDeclarationMapping;
375
376 // A mapping from MathSAT variable declarations to our variables.
377 std::unordered_map<msat_decl, storm::expressions::Variable> declarationToVariableMapping;
378};
379#endif
380} // namespace adapters
381} // namespace storm
382
383#endif /* STORM_ADAPTERS_MATHSATEXPRESSIONADAPTER_H_ */
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.
This class is responsible for managing a set of typed variables and all expressions using these varia...
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:178
std::size_t getWidth() const
Retrieves the bit width of the type, provided that it is a bitvector type.
Definition Type.cpp:206
bool isIntegerType() const
Checks whether this type is an integral type.
Definition Type.cpp:182
bool isRationalType() const
Checks whether this type is a rational type.
Definition Type.cpp:214
bool isBitVectorType() const
Checks whether this type is a bitvector type.
Definition Type.cpp:186
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:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
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.
LabParser.cpp.
Definition cli.cpp:18