421 lines
26 KiB

  1. #include "storm/adapters/Z3ExpressionAdapter.h"
  2. #include <cstdint>
  3. #include "storm/storage/expressions/Expressions.h"
  4. #include "storm/storage/expressions/ExpressionManager.h"
  5. #include "storm/utility/macros.h"
  6. #include "storm/utility/constants.h"
  7. #include "storm/exceptions/ExpressionEvaluationException.h"
  8. #include "storm/exceptions/InvalidTypeException.h"
  9. #include "storm/exceptions/NotImplementedException.h"
  10. namespace storm {
  11. namespace adapters {
  12. #ifdef STORM_HAVE_Z3
  13. #ifdef STORM_Z3_API_USES_STANDARD_INTEGERS
  14. typedef int64_t Z3_SIGNED_INTEGER;
  15. typedef uint64_t Z3_UNSIGNED_INTEGER;
  16. #else
  17. typedef long long Z3_SIGNED_INTEGER;
  18. typedef unsigned long long Z3_UNSIGNED_INTEGER;
  19. #endif
  20. Z3ExpressionAdapter::Z3ExpressionAdapter(storm::expressions::ExpressionManager& manager, z3::context& context) : manager(manager), context(context), additionalAssertions(), variableToExpressionMapping() {
  21. // Intentionally left empty.
  22. }
  23. z3::expr Z3ExpressionAdapter::translateExpression(storm::expressions::Expression const& expression) {
  24. STORM_LOG_ASSERT(expression.getManager() == this->manager, "Invalid expression for solver.");
  25. z3::expr result = boost::any_cast<z3::expr>(expression.getBaseExpression().accept(*this, boost::none));
  26. expressionCache.clear();
  27. for (z3::expr const& assertion : additionalAssertions) {
  28. result = result && assertion;
  29. }
  30. additionalAssertions.clear();
  31. return result.simplify();
  32. }
  33. z3::expr Z3ExpressionAdapter::translateExpression(storm::expressions::Variable const& variable) {
  34. STORM_LOG_ASSERT(variable.getManager() == this->manager, "Invalid expression for solver.");
  35. auto const& variableExpressionPair = variableToExpressionMapping.find(variable);
  36. if (variableExpressionPair == variableToExpressionMapping.end()) {
  37. return createVariable(variable);
  38. }
  39. return variableExpressionPair->second;
  40. }
  41. storm::expressions::Variable const& Z3ExpressionAdapter::getVariable(z3::func_decl z3Declaration) {
  42. auto const& declarationVariablePair = declarationToVariableMapping.find(z3Declaration);
  43. STORM_LOG_ASSERT(declarationVariablePair != declarationToVariableMapping.end(), "Unable to find declaration.");
  44. return declarationVariablePair->second;
  45. }
  46. storm::expressions::Expression Z3ExpressionAdapter::translateExpression(z3::expr const& expr) {
  47. if (expr.is_app()) {
  48. switch (expr.decl().decl_kind()) {
  49. case Z3_OP_TRUE:
  50. return manager.boolean(true);
  51. case Z3_OP_FALSE:
  52. return manager.boolean(false);
  53. case Z3_OP_EQ:
  54. return this->translateExpression(expr.arg(0)) == this->translateExpression(expr.arg(1));
  55. case Z3_OP_DISTINCT: {
  56. unsigned args = expr.num_args();
  57. STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. DISTINCT (mutual != ) operator with 0-arity is assumed to be an error.");
  58. if (args == 1) {
  59. return manager.boolean(true);
  60. } else {
  61. storm::expressions::Expression retVal = this->translateExpression(expr.arg(0)) != this->translateExpression(expr.arg(1));
  62. for (unsigned arg2 = 2; arg2 < args; ++arg2) {
  63. retVal = retVal && (this->translateExpression(expr.arg(0)) != this->translateExpression(expr.arg(arg2)));
  64. }
  65. for (unsigned arg1 = 1; arg1 < args; ++arg1) {
  66. for (unsigned arg2 = arg1 + 1; arg2 < args; ++arg2) {
  67. retVal = retVal && (this->translateExpression(expr.arg(arg1)) != this->translateExpression(expr.arg(arg2)));
  68. }
  69. }
  70. return retVal;
  71. }
  72. }
  73. case Z3_OP_ITE:
  74. return storm::expressions::ite(this->translateExpression(expr.arg(0)), this->translateExpression(expr.arg(1)), this->translateExpression(expr.arg(2)));
  75. case Z3_OP_AND: {
  76. unsigned args = expr.num_args();
  77. STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. 0-ary AND is assumed to be an error.");
  78. if (args == 1) {
  79. return this->translateExpression(expr.arg(0));
  80. } else {
  81. storm::expressions::Expression retVal = this->translateExpression(expr.arg(0));
  82. for (unsigned i = 1; i < args; i++) {
  83. retVal = retVal && this->translateExpression(expr.arg(i));
  84. }
  85. return retVal;
  86. }
  87. }
  88. case Z3_OP_OR: {
  89. unsigned args = expr.num_args();
  90. STORM_LOG_THROW(args != 0, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. 0-ary OR is assumed to be an error.");
  91. if (args == 1) {
  92. return this->translateExpression(expr.arg(0));
  93. } else {
  94. storm::expressions::Expression retVal = this->translateExpression(expr.arg(0));
  95. for (unsigned i = 1; i < args; i++) {
  96. retVal = retVal || this->translateExpression(expr.arg(i));
  97. }
  98. return retVal;
  99. }
  100. }
  101. case Z3_OP_IFF:
  102. return storm::expressions::iff(this->translateExpression(expr.arg(0)), this->translateExpression(expr.arg(1)));
  103. case Z3_OP_XOR:
  104. return storm::expressions::xclusiveor(this->translateExpression(expr.arg(0)), this->translateExpression(expr.arg(1)));
  105. case Z3_OP_NOT:
  106. return !this->translateExpression(expr.arg(0));
  107. case Z3_OP_IMPLIES:
  108. return storm::expressions::implies(this->translateExpression(expr.arg(0)), this->translateExpression(expr.arg(1)));
  109. case Z3_OP_LE:
  110. return this->translateExpression(expr.arg(0)) <= this->translateExpression(expr.arg(1));
  111. case Z3_OP_GE:
  112. return this->translateExpression(expr.arg(0)) >= this->translateExpression(expr.arg(1));
  113. case Z3_OP_LT:
  114. return this->translateExpression(expr.arg(0)) < this->translateExpression(expr.arg(1));
  115. case Z3_OP_GT:
  116. return this->translateExpression(expr.arg(0)) > this->translateExpression(expr.arg(1));
  117. case Z3_OP_ADD:
  118. return this->translateExpression(expr.arg(0)) + this->translateExpression(expr.arg(1));
  119. case Z3_OP_SUB:
  120. return this->translateExpression(expr.arg(0)) - this->translateExpression(expr.arg(1));
  121. case Z3_OP_UMINUS:
  122. return -this->translateExpression(expr.arg(0));
  123. case Z3_OP_MUL:
  124. return this->translateExpression(expr.arg(0)) * this->translateExpression(expr.arg(1));
  125. case Z3_OP_DIV:
  126. return this->translateExpression(expr.arg(0)) / this->translateExpression(expr.arg(1));
  127. case Z3_OP_IDIV:
  128. return this->translateExpression(expr.arg(0)) / this->translateExpression(expr.arg(1));
  129. case Z3_OP_ANUM:
  130. // Arithmetic numeral.
  131. if (expr.is_int() && expr.is_const()) {
  132. Z3_SIGNED_INTEGER value;
  133. if (Z3_get_numeral_int64(expr.ctx(), expr, &value)) {
  134. return manager.integer(value);
  135. } else {
  136. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Expression is constant integer and value does not fit into 64-bit integer.");
  137. }
  138. } else {
  139. STORM_LOG_ASSERT(expr.is_real() && expr.is_const(), "Cannot handle numerical expression");
  140. Z3_SIGNED_INTEGER num;
  141. Z3_SIGNED_INTEGER den;
  142. if (Z3_get_numeral_rational_int64(expr.ctx(), expr, &num, &den)) {
  143. return manager.rational(storm::utility::convertNumber<storm::RationalNumber>(static_cast<int_fast64_t>(num)) / storm::utility::convertNumber<storm::RationalNumber>(static_cast<int_fast64_t>(den)));
  144. } else {
  145. return manager.rational(storm::utility::convertNumber<storm::RationalNumber>(std::string(Z3_get_numeral_string(expr.ctx(), expr))));
  146. }
  147. }
  148. case Z3_OP_UNINTERPRETED:
  149. // Currently, we only support uninterpreted constant functions.
  150. STORM_LOG_THROW(expr.is_const(), storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Encountered non-constant uninterpreted function.");
  151. return manager.getVariable(expr.decl().name().str()).getExpression();
  152. default:
  153. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Encountered unhandled Z3_decl_kind " << expr.decl().decl_kind() <<".");
  154. break;
  155. }
  156. } else {
  157. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Encountered unknown expression type.");
  158. }
  159. }
  160. boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
  161. auto cacheIt = expressionCache.find(&expression);
  162. if (cacheIt != expressionCache.end()) {
  163. return cacheIt->second;
  164. }
  165. z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
  166. z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
  167. z3::expr result(context);
  168. switch(expression.getOperatorType()) {
  169. case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::And:
  170. result = leftResult && rightResult;
  171. break;
  172. case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Or:
  173. result = leftResult || rightResult;
  174. break;
  175. case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Xor:
  176. result = z3::expr(context, Z3_mk_xor(context, leftResult, rightResult));
  177. break;
  178. case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Implies:
  179. result = z3::expr(context, Z3_mk_implies(context, leftResult, rightResult));
  180. break;
  181. case storm::expressions::BinaryBooleanFunctionExpression::OperatorType::Iff:
  182. result = z3::expr(context, Z3_mk_iff(context, leftResult, rightResult));
  183. break;
  184. default:
  185. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<int>(expression.getOperatorType()) << "' in expression " << expression << ".");
  186. }
  187. expressionCache.emplace(&expression, result);
  188. return result;
  189. }
  190. boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) {
  191. auto cacheIt = expressionCache.find(&expression);
  192. if (cacheIt != expressionCache.end()) {
  193. return cacheIt->second;
  194. }
  195. z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
  196. z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
  197. z3::expr result(context);
  198. switch(expression.getOperatorType()) {
  199. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus:
  200. result = leftResult + rightResult;
  201. break;
  202. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Minus:
  203. result = leftResult - rightResult;
  204. break;
  205. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Times:
  206. result = leftResult * rightResult;
  207. break;
  208. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Divide:
  209. if (leftResult.is_int() && rightResult.is_int()) {
  210. leftResult = z3::expr(context, Z3_mk_int2real(context, leftResult));
  211. }
  212. result = leftResult / rightResult;
  213. break;
  214. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Min:
  215. result = ite(leftResult <= rightResult, leftResult, rightResult);
  216. break;
  217. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max:
  218. result = ite(leftResult >= rightResult, leftResult, rightResult);
  219. break;
  220. case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power:
  221. result = pw(leftResult,rightResult);
  222. break;
  223. default:
  224. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast<int>(expression.getOperatorType()) << "' in expression " << expression << ".");
  225. }
  226. expressionCache.emplace(&expression, result);
  227. return result;
  228. }
  229. boost::any Z3ExpressionAdapter::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) {
  230. auto cacheIt = expressionCache.find(&expression);
  231. if (cacheIt != expressionCache.end()) {
  232. return cacheIt->second;
  233. }
  234. z3::expr leftResult = boost::any_cast<z3::expr>(expression.getFirstOperand()->accept(*this, data));
  235. z3::expr rightResult = boost::any_cast<z3::expr>(expression.getSecondOperand()->accept(*this, data));
  236. z3::expr result(context);
  237. switch(expression.getRelationType()) {
  238. case storm::expressions::BinaryRelationExpression::RelationType::Equal:
  239. result = leftResult == rightResult;
  240. break;
  241. case storm::expressions::BinaryRelationExpression::RelationType::NotEqual:
  242. result = leftResult != rightResult;
  243. break;
  244. case storm::expressions::BinaryRelationExpression::RelationType::Less:
  245. result = leftResult < rightResult;
  246. break;
  247. case storm::expressions::BinaryRelationExpression::RelationType::LessOrEqual:
  248. result = leftResult <= rightResult;
  249. break;
  250. case storm::expressions::BinaryRelationExpression::RelationType::Greater:
  251. result = leftResult > rightResult;
  252. break;
  253. case storm::expressions::BinaryRelationExpression::RelationType::GreaterOrEqual:
  254. result = leftResult >= rightResult;
  255. break;
  256. default:
  257. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<int>(expression.getRelationType()) << "' in expression " << expression << ".");
  258. }
  259. expressionCache.emplace(&expression, result);
  260. return result;
  261. }
  262. boost::any Z3ExpressionAdapter::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) {
  263. auto cacheIt = expressionCache.find(&expression);
  264. if (cacheIt != expressionCache.end()) {
  265. return cacheIt->second;
  266. }
  267. z3::expr result = context.bool_val(expression.getValue());
  268. expressionCache.emplace(&expression, result);
  269. return result;
  270. }
  271. boost::any Z3ExpressionAdapter::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) {
  272. auto cacheIt = expressionCache.find(&expression);
  273. if (cacheIt != expressionCache.end()) {
  274. return cacheIt->second;
  275. }
  276. std::stringstream fractionStream;
  277. fractionStream << expression.getValue();
  278. z3::expr result = context.real_val(fractionStream.str().c_str());
  279. expressionCache.emplace(&expression, result);
  280. return result;
  281. }
  282. boost::any Z3ExpressionAdapter::visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) {
  283. auto cacheIt = expressionCache.find(&expression);
  284. if (cacheIt != expressionCache.end()) {
  285. return cacheIt->second;
  286. }
  287. z3::expr result = context.int_val(static_cast<Z3_SIGNED_INTEGER>(expression.getValue()));
  288. expressionCache.emplace(&expression, result);
  289. return result;
  290. }
  291. boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
  292. auto cacheIt = expressionCache.find(&expression);
  293. if (cacheIt != expressionCache.end()) {
  294. return cacheIt->second;
  295. }
  296. z3::expr result = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data));
  297. switch (expression.getOperatorType()) {
  298. case storm::expressions::UnaryBooleanFunctionExpression::OperatorType::Not:
  299. result = !result;
  300. break;
  301. default:
  302. STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown boolean binary operator '" << static_cast<int>(expression.getOperatorType()) << "' in expression " << expression << ".");
  303. }
  304. expressionCache.emplace(&expression, result);
  305. return result;
  306. }
  307. boost::any Z3ExpressionAdapter::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) {
  308. auto cacheIt = expressionCache.find(&expression);
  309. if (cacheIt != expressionCache.end()) {
  310. return cacheIt->second;
  311. }
  312. z3::expr result = boost::any_cast<z3::expr>(expression.getOperand()->accept(*this, data));
  313. switch(expression.getOperatorType()) {
  314. case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Minus:
  315. result = 0 - result;
  316. break;
  317. case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Floor: {
  318. storm::expressions::Variable freshAuxiliaryVariable = manager.declareFreshVariable(manager.getIntegerType(), true);
  319. z3::expr floorVariable = context.int_const(freshAuxiliaryVariable.getName().c_str());
  320. additionalAssertions.push_back(z3::expr(context, Z3_mk_int2real(context, floorVariable)) <= result && result < (z3::expr(context, Z3_mk_int2real(context, floorVariable)) + 1));
  321. result = floorVariable;
  322. break;
  323. }
  324. case storm::expressions::UnaryNumericalFunctionExpression::OperatorType::Ceil:{
  325. storm::expressions::Variable freshAuxiliaryVariable = manager.declareFreshVariable(manager.getIntegerType(), true);
  326. z3::expr ceilVariable = context.int_const(freshAuxiliaryVariable.getName().c_str());
  327. additionalAssertions.push_back(z3::expr(context, Z3_mk_int2real(context, ceilVariable)) - 1 < result && result <= z3::expr(context, Z3_mk_int2real(context, ceilVariable)));
  328. result = ceilVariable;
  329. break;
  330. }
  331. default: STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical unary operator '" << static_cast<int>(expression.getOperatorType()) << "'.");
  332. }
  333. expressionCache.emplace(&expression, result);
  334. return result;
  335. }
  336. boost::any Z3ExpressionAdapter::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
  337. auto cacheIt = expressionCache.find(&expression);
  338. if (cacheIt != expressionCache.end()) {
  339. return cacheIt->second;
  340. }
  341. z3::expr conditionResult = boost::any_cast<z3::expr>(expression.getCondition()->accept(*this, data));
  342. z3::expr thenResult = boost::any_cast<z3::expr>(expression.getThenExpression()->accept(*this, data));
  343. z3::expr elseResult = boost::any_cast<z3::expr>(expression.getElseExpression()->accept(*this, data));
  344. z3::expr result = z3::expr(context, Z3_mk_ite(context, conditionResult, thenResult, elseResult));
  345. expressionCache.emplace(&expression, result);
  346. return result;
  347. }
  348. boost::any Z3ExpressionAdapter::visit(storm::expressions::VariableExpression const& expression, boost::any const&) {
  349. return this->translateExpression(expression.getVariable());
  350. }
  351. z3::expr Z3ExpressionAdapter::createVariable(storm::expressions::Variable const& variable) {
  352. z3::expr z3Variable(context);
  353. if (variable.getType().isBooleanType()) {
  354. z3Variable = context.bool_const(variable.getName().c_str());
  355. } else if (variable.getType().isIntegerType()) {
  356. z3Variable = context.int_const(variable.getName().c_str());
  357. } else if (variable.getType().isBitVectorType()) {
  358. z3Variable = context.bv_const(variable.getName().c_str(), variable.getType().getWidth());
  359. } else if (variable.getType().isRationalType()) {
  360. z3Variable = context.real_const(variable.getName().c_str());
  361. } else {
  362. STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Encountered variable '" << variable.getName() << "' with unknown type while trying to create solver variables.");
  363. }
  364. variableToExpressionMapping.insert(std::make_pair(variable, z3Variable));
  365. declarationToVariableMapping.insert(std::make_pair(z3Variable.decl(), variable));
  366. return z3Variable;
  367. }
  368. #endif
  369. } // namespace adapters
  370. } // namespace storm