You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
7.9 KiB

  1. #include "gtest/gtest.h"
  2. #include "storm-config.h"
  3. #include <memory>
  4. #include "src/storage/expressions/ExpressionManager.h"
  5. #ifdef STORM_HAVE_Z3
  6. #include "z3++.h"
  7. #include "src/adapters/Z3ExpressionAdapter.h"
  8. #include "src/settings/SettingsManager.h"
  9. TEST(Z3ExpressionAdapter, StormToZ3Basic) {
  10. z3::context ctx;
  11. z3::solver s(ctx);
  12. z3::expr conjecture = ctx.bool_val(false);
  13. std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
  14. storm::adapters::Z3ExpressionAdapter adapter(*manager, ctx);
  15. storm::expressions::Expression exprTrue = manager->boolean(true);
  16. z3::expr z3True = ctx.bool_val(true);
  17. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprTrue), z3True)));
  18. s.add(conjecture);
  19. ASSERT_TRUE(s.check() == z3::unsat);
  20. s.reset();
  21. storm::expressions::Expression exprFalse = manager->boolean(false);
  22. z3::expr z3False = ctx.bool_val(false);
  23. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprFalse), z3False)));
  24. s.add(conjecture);
  25. ASSERT_TRUE(s.check() == z3::unsat);
  26. s.reset();
  27. storm::expressions::Variable x = manager->declareBooleanVariable("x");
  28. storm::expressions::Variable y = manager->declareBooleanVariable("y");
  29. storm::expressions::Expression exprConjunction = x && y;
  30. z3::expr z3Conjunction = (ctx.bool_const("x") && ctx.bool_const("y"));
  31. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprConjunction), z3Conjunction)));
  32. s.add(conjecture);
  33. ASSERT_TRUE(s.check() == z3::unsat);
  34. s.reset();
  35. storm::expressions::Expression exprNor = !(x || y);
  36. z3::expr z3Nor = !(ctx.bool_const("x") || ctx.bool_const("y"));
  37. ASSERT_NO_THROW(adapter.translateExpression(exprNor)); // Variables already created in adapter.
  38. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprNor), z3Nor)));
  39. s.add(conjecture);
  40. ASSERT_TRUE(s.check() == z3::unsat);
  41. s.reset();
  42. }
  43. TEST(Z3ExpressionAdapter, StormToZ3Integer) {
  44. z3::context ctx;
  45. z3::solver s(ctx);
  46. z3::expr conjecture = ctx.bool_val(false);
  47. std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
  48. storm::adapters::Z3ExpressionAdapter adapter(*manager, ctx);
  49. storm::expressions::Variable x = manager->declareIntegerVariable("x");
  50. storm::expressions::Variable y = manager->declareIntegerVariable("y");
  51. storm::expressions::Expression exprAdd = x + y < -y;
  52. z3::expr z3Add = (ctx.int_const("x") + ctx.int_const("y") < -ctx.int_const("y"));
  53. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprAdd), z3Add)));
  54. s.add(conjecture);
  55. ASSERT_TRUE(s.check() == z3::unsat);
  56. s.reset();
  57. storm::expressions::Expression exprMult = !(x * y == y);
  58. z3::expr z3Mult = !(ctx.int_const("x") * ctx.int_const("y") == ctx.int_const("y"));
  59. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprMult), z3Mult)));
  60. s.add(conjecture);
  61. ASSERT_TRUE(s.check() == z3::unsat);
  62. s.reset();
  63. }
  64. TEST(Z3ExpressionAdapter, StormToZ3Real) {
  65. z3::context ctx;
  66. z3::solver s(ctx);
  67. z3::expr conjecture = ctx.bool_val(false);
  68. std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
  69. storm::adapters::Z3ExpressionAdapter adapter(*manager, ctx);
  70. storm::expressions::Variable x = manager->declareRationalVariable("x");
  71. storm::expressions::Variable y = manager->declareRationalVariable("y");
  72. storm::expressions::Expression exprAdd = x + y < -y;
  73. z3::expr z3Add = (ctx.real_const("x") + ctx.real_const("y") < -ctx.real_const("y"));
  74. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprAdd), z3Add)));
  75. s.add(conjecture);
  76. ASSERT_TRUE(s.check() == z3::unsat);
  77. s.reset();
  78. storm::expressions::Expression exprMult = !(x * y == y);
  79. z3::expr z3Mult = !(ctx.real_const("x") * ctx.real_const("y") == ctx.real_const("y"));
  80. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprMult), z3Mult)));
  81. s.add(conjecture);
  82. ASSERT_TRUE(s.check() == z3::unsat);
  83. s.reset();
  84. }
  85. TEST(Z3ExpressionAdapter, StormToZ3FloorCeil) {
  86. z3::context ctx;
  87. z3::solver s(ctx);
  88. z3::expr conjecture = ctx.bool_val(false);
  89. std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
  90. storm::adapters::Z3ExpressionAdapter adapter(*manager, ctx);
  91. storm::expressions::Variable d = manager->declareRationalVariable("d");
  92. storm::expressions::Variable i = manager->declareIntegerVariable("i");
  93. storm::expressions::Expression exprFloor = storm::expressions::floor(d) == i && d > manager->rational(4.1) && d < manager->rational(4.991);
  94. z3::expr z3Floor = ctx.int_val(4) == ctx.int_const("i");
  95. conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprFloor), z3Floor));
  96. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprFloor), z3Floor)));
  97. s.add(conjecture);
  98. // It is not logically equivalent, so this should be satisfiable.
  99. ASSERT_TRUE(s.check() == z3::sat);
  100. s.reset();
  101. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_implies(ctx, adapter.translateExpression(exprFloor), z3Floor)));
  102. s.add(conjecture);
  103. // However, the left part implies the right one, which is why this should be unsatisfiable.
  104. ASSERT_TRUE(s.check() == z3::unsat);
  105. s.reset();
  106. storm::expressions::Expression exprCeil = storm::expressions::ceil(d) == i && d > manager->rational(4.1) && d < manager->rational(4.991);
  107. z3::expr z3Ceil = ctx.int_val(5) == ctx.int_const("i");
  108. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_iff(ctx, adapter.translateExpression(exprCeil), z3Ceil)));
  109. s.add(conjecture);
  110. // It is not logically equivalent, so this should be satisfiable.
  111. ASSERT_TRUE(s.check() == z3::sat);
  112. s.reset();
  113. ASSERT_NO_THROW(conjecture = !z3::expr(ctx, Z3_mk_implies(ctx, adapter.translateExpression(exprCeil), z3Ceil)));
  114. s.add(conjecture);
  115. // However, the left part implies the right one, which is why this should be unsatisfiable.
  116. ASSERT_TRUE(s.check() == z3::unsat);
  117. s.reset();
  118. }
  119. TEST(Z3ExpressionAdapter, Z3ToStormBasic) {
  120. z3::context ctx;
  121. unsigned args = 2;
  122. std::shared_ptr<storm::expressions::ExpressionManager> manager(new storm::expressions::ExpressionManager());
  123. manager->declareBooleanVariable("x");
  124. manager->declareBooleanVariable("y");
  125. storm::adapters::Z3ExpressionAdapter adapter(*manager, ctx);
  126. z3::expr z3True = ctx.bool_val(true);
  127. storm::expressions::Expression exprTrue;
  128. exprTrue = adapter.translateExpression(z3True);
  129. ASSERT_TRUE(exprTrue.isTrue());
  130. z3::expr z3False = ctx.bool_val(false);
  131. storm::expressions::Expression exprFalse;
  132. exprFalse = adapter.translateExpression(z3False);
  133. ASSERT_TRUE(exprFalse.isFalse());
  134. z3::expr z3Conjunction = (ctx.bool_const("x") && ctx.bool_const("y"));
  135. storm::expressions::Expression exprConjunction;
  136. (exprConjunction = adapter.translateExpression(z3Conjunction));
  137. ASSERT_EQ(storm::expressions::OperatorType::And, exprConjunction.getOperator());
  138. ASSERT_TRUE(exprConjunction.getOperand(0).isVariable());
  139. ASSERT_EQ("x", exprConjunction.getOperand(0).getIdentifier());
  140. ASSERT_TRUE(exprConjunction.getOperand(1).isVariable());
  141. ASSERT_EQ("y", exprConjunction.getOperand(1).getIdentifier());
  142. z3::expr z3Nor = !(ctx.bool_const("x") || ctx.bool_const("y"));
  143. storm::expressions::Expression exprNor;
  144. (exprNor = adapter.translateExpression(z3Nor));
  145. ASSERT_EQ(storm::expressions::OperatorType::Not, exprNor.getOperator());
  146. ASSERT_EQ(storm::expressions::OperatorType::Or, exprNor.getOperand(0).getOperator());
  147. ASSERT_TRUE(exprNor.getOperand(0).getOperand(0).isVariable());
  148. ASSERT_EQ("x", exprNor.getOperand(0).getOperand(0).getIdentifier());
  149. ASSERT_TRUE(exprNor.getOperand(0).getOperand(1).isVariable());
  150. ASSERT_EQ("y", exprNor.getOperand(0).getOperand(1).getIdentifier());
  151. }
  152. #endif