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