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.

422 lines
17 KiB

  1. #include "gtest/gtest.h"
  2. #include "storm-config.h"
  3. #include "src/exceptions/InvalidArgumentException.h"
  4. #include "src/storage/dd/CuddDdManager.h"
  5. #include "src/storage/dd/CuddDd.h"
  6. #include "src/storage/dd/CuddOdd.h"
  7. #include "src/storage/dd/DdMetaVariable.h"
  8. TEST(CuddDdManager, Constants) {
  9. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  10. storm::dd::Dd<storm::dd::DdType::CUDD> zero;
  11. ASSERT_NO_THROW(zero = manager->getZero());
  12. EXPECT_EQ(0, zero.getNonZeroCount());
  13. EXPECT_EQ(1, zero.getLeafCount());
  14. EXPECT_EQ(1, zero.getNodeCount());
  15. EXPECT_EQ(0, zero.getMin());
  16. EXPECT_EQ(0, zero.getMax());
  17. storm::dd::Dd<storm::dd::DdType::CUDD> one;
  18. ASSERT_NO_THROW(one = manager->getOne());
  19. EXPECT_EQ(1, one.getNonZeroCount());
  20. EXPECT_EQ(1, one.getLeafCount());
  21. EXPECT_EQ(1, one.getNodeCount());
  22. EXPECT_EQ(1, one.getMin());
  23. EXPECT_EQ(1, one.getMax());
  24. storm::dd::Dd<storm::dd::DdType::CUDD> two;
  25. ASSERT_NO_THROW(two = manager->getConstant(2));
  26. EXPECT_EQ(1, two.getNonZeroCount());
  27. EXPECT_EQ(1, two.getLeafCount());
  28. EXPECT_EQ(1, two.getNodeCount());
  29. EXPECT_EQ(2, two.getMin());
  30. EXPECT_EQ(2, two.getMax());
  31. }
  32. TEST(CuddDdManager, AddGetMetaVariableTest) {
  33. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  34. ASSERT_NO_THROW(manager->addMetaVariable("x", 1, 9));
  35. EXPECT_EQ(2, manager->getNumberOfMetaVariables());
  36. ASSERT_THROW(manager->addMetaVariable("x", 0, 3), storm::exceptions::InvalidArgumentException);
  37. ASSERT_NO_THROW(manager->addMetaVariable("y", 0, 3));
  38. EXPECT_EQ(4, manager->getNumberOfMetaVariables());
  39. EXPECT_TRUE(manager->hasMetaVariable("x'"));
  40. EXPECT_TRUE(manager->hasMetaVariable("y'"));
  41. std::set<std::string> metaVariableSet = {"x", "x'", "y", "y'"};
  42. EXPECT_EQ(metaVariableSet, manager->getAllMetaVariableNames());
  43. }
  44. TEST(CuddDdManager, EncodingTest) {
  45. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  46. manager->addMetaVariable("x", 1, 9);
  47. storm::dd::Dd<storm::dd::DdType::CUDD> encoding;
  48. ASSERT_THROW(encoding = manager->getEncoding("x", 0), storm::exceptions::InvalidArgumentException);
  49. ASSERT_THROW(encoding = manager->getEncoding("x", 10), storm::exceptions::InvalidArgumentException);
  50. ASSERT_NO_THROW(encoding = manager->getEncoding("x", 4));
  51. EXPECT_EQ(1, encoding.getNonZeroCount());
  52. EXPECT_EQ(6, encoding.getNodeCount());
  53. EXPECT_EQ(2, encoding.getLeafCount());
  54. }
  55. TEST(CuddDdManager, RangeTest) {
  56. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  57. ASSERT_NO_THROW(manager->addMetaVariable("x", 1, 9));
  58. storm::dd::Dd<storm::dd::DdType::CUDD> range;
  59. ASSERT_THROW(range = manager->getRange("y"), storm::exceptions::InvalidArgumentException);
  60. ASSERT_NO_THROW(range = manager->getRange("x"));
  61. EXPECT_EQ(9, range.getNonZeroCount());
  62. EXPECT_EQ(2, range.getLeafCount());
  63. EXPECT_EQ(6, range.getNodeCount());
  64. }
  65. TEST(CuddDdManager, IdentityTest) {
  66. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  67. manager->addMetaVariable("x", 1, 9);
  68. storm::dd::Dd<storm::dd::DdType::CUDD> range;
  69. ASSERT_THROW(range = manager->getIdentity("y"), storm::exceptions::InvalidArgumentException);
  70. ASSERT_NO_THROW(range = manager->getIdentity("x"));
  71. EXPECT_EQ(9, range.getNonZeroCount());
  72. EXPECT_EQ(10, range.getLeafCount());
  73. EXPECT_EQ(21, range.getNodeCount());
  74. }
  75. TEST(CuddDd, OperatorTest) {
  76. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  77. manager->addMetaVariable("x", 1, 9);
  78. EXPECT_TRUE(manager->getZero() == manager->getZero());
  79. EXPECT_FALSE(manager->getZero() == manager->getOne());
  80. EXPECT_FALSE(manager->getZero() != manager->getZero());
  81. EXPECT_TRUE(manager->getZero() != manager->getOne());
  82. storm::dd::Dd<storm::dd::DdType::CUDD> dd1 = manager->getOne();
  83. storm::dd::Dd<storm::dd::DdType::CUDD> dd2 = manager->getOne();
  84. storm::dd::Dd<storm::dd::DdType::CUDD> dd3 = dd1 + dd2;
  85. EXPECT_TRUE(dd3 == manager->getConstant(2));
  86. dd3 += manager->getZero();
  87. EXPECT_TRUE(dd3 == manager->getConstant(2));
  88. dd3 = dd1 && manager->getConstant(3);
  89. EXPECT_TRUE(dd1 == manager->getOne());
  90. dd3 = dd1 * manager->getConstant(3);
  91. EXPECT_TRUE(dd3 == manager->getConstant(3));
  92. dd3 *= manager->getConstant(2);
  93. EXPECT_TRUE(dd3 == manager->getConstant(6));
  94. dd3 = dd1 - dd2;
  95. EXPECT_TRUE(dd3 == manager->getZero());
  96. dd3 -= manager->getConstant(-2);
  97. EXPECT_TRUE(dd3 == manager->getConstant(2));
  98. dd3 /= manager->getConstant(2);
  99. EXPECT_TRUE(dd3 == manager->getOne());
  100. dd3.complement();
  101. EXPECT_TRUE(dd3 == manager->getZero());
  102. dd1 = !dd3;
  103. EXPECT_TRUE(dd1 == manager->getOne());
  104. dd3 = dd1 || dd2;
  105. EXPECT_TRUE(dd3 == manager->getOne());
  106. dd1 = manager->getIdentity("x");
  107. dd2 = manager->getConstant(5);
  108. dd3 = dd1.equals(dd2);
  109. EXPECT_EQ(1, dd3.getNonZeroCount());
  110. storm::dd::Dd<storm::dd::DdType::CUDD> dd4 = dd1.notEquals(dd2);
  111. EXPECT_TRUE(dd4 == !dd3);
  112. dd3 = dd1.less(dd2);
  113. EXPECT_EQ(11, dd3.getNonZeroCount());
  114. dd3 = dd1.lessOrEqual(dd2);
  115. EXPECT_EQ(12, dd3.getNonZeroCount());
  116. dd3 = dd1.greater(dd2);
  117. EXPECT_EQ(4, dd3.getNonZeroCount());
  118. dd3 = dd1.greaterOrEqual(dd2);
  119. EXPECT_EQ(5, dd3.getNonZeroCount());
  120. dd3 = (manager->getEncoding("x", 2)).ite(dd2, dd1);
  121. dd4 = dd3.less(dd2);
  122. EXPECT_EQ(10, dd4.getNonZeroCount());
  123. dd4 = dd3.minimum(dd1);
  124. dd4 *= manager->getEncoding("x", 2);
  125. dd4 = dd4.sumAbstract({"x"});
  126. EXPECT_EQ(2, dd4.getValue());
  127. dd4 = dd3.maximum(dd1);
  128. dd4 *= manager->getEncoding("x", 2);
  129. dd4 = dd4.sumAbstract({"x"});
  130. EXPECT_EQ(5, dd4.getValue());
  131. dd1 = manager->getConstant(0.01);
  132. dd2 = manager->getConstant(0.01 + 1e-6);
  133. EXPECT_TRUE(dd1.equalModuloPrecision(dd2, 1e-6, false));
  134. EXPECT_FALSE(dd1.equalModuloPrecision(dd2, 1e-6));
  135. }
  136. TEST(CuddDd, AbstractionTest) {
  137. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  138. manager->addMetaVariable("x", 1, 9);
  139. storm::dd::Dd<storm::dd::DdType::CUDD> dd1;
  140. storm::dd::Dd<storm::dd::DdType::CUDD> dd2;
  141. storm::dd::Dd<storm::dd::DdType::CUDD> dd3;
  142. dd1 = manager->getIdentity("x");
  143. dd2 = manager->getConstant(5);
  144. dd3 = dd1.equals(dd2);
  145. EXPECT_EQ(1, dd3.getNonZeroCount());
  146. ASSERT_THROW(dd3 = dd3.existsAbstract({"x'"}), storm::exceptions::InvalidArgumentException);
  147. ASSERT_NO_THROW(dd3 = dd3.existsAbstract({"x"}));
  148. EXPECT_EQ(1, dd3.getNonZeroCount());
  149. EXPECT_EQ(1, dd3.getMax());
  150. dd3 = dd1.equals(dd2);
  151. dd3 *= manager->getConstant(3);
  152. EXPECT_EQ(1, dd3.getNonZeroCount());
  153. ASSERT_THROW(dd3 = dd3.existsAbstract({"x'"}), storm::exceptions::InvalidArgumentException);
  154. ASSERT_NO_THROW(dd3 = dd3.existsAbstract({"x"}));
  155. EXPECT_TRUE(dd3 == manager->getZero());
  156. dd3 = dd1.equals(dd2);
  157. dd3 *= manager->getConstant(3);
  158. ASSERT_THROW(dd3 = dd3.sumAbstract({"x'"}), storm::exceptions::InvalidArgumentException);
  159. ASSERT_NO_THROW(dd3 = dd3.sumAbstract({"x"}));
  160. EXPECT_EQ(1, dd3.getNonZeroCount());
  161. EXPECT_EQ(3, dd3.getMax());
  162. dd3 = dd1.equals(dd2);
  163. dd3 *= manager->getConstant(3);
  164. ASSERT_THROW(dd3 = dd3.minAbstract({"x'"}), storm::exceptions::InvalidArgumentException);
  165. ASSERT_NO_THROW(dd3 = dd3.minAbstract({"x"}));
  166. EXPECT_EQ(0, dd3.getNonZeroCount());
  167. EXPECT_EQ(0, dd3.getMax());
  168. dd3 = dd1.equals(dd2);
  169. dd3 *= manager->getConstant(3);
  170. ASSERT_THROW(dd3 = dd3.maxAbstract({"x'"}), storm::exceptions::InvalidArgumentException);
  171. ASSERT_NO_THROW(dd3 = dd3.maxAbstract({"x"}));
  172. EXPECT_EQ(1, dd3.getNonZeroCount());
  173. EXPECT_EQ(3, dd3.getMax());
  174. }
  175. TEST(CuddDd, SwapTest) {
  176. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  177. manager->addMetaVariable("x", 1, 9);
  178. manager->addMetaVariable("z", 2, 8);
  179. storm::dd::Dd<storm::dd::DdType::CUDD> dd1;
  180. storm::dd::Dd<storm::dd::DdType::CUDD> dd2;
  181. dd1 = manager->getIdentity("x");
  182. ASSERT_THROW(dd1.swapVariables({std::make_pair("x", "z")}), storm::exceptions::InvalidArgumentException);
  183. ASSERT_NO_THROW(dd1.swapVariables({std::make_pair("x", "x'")}));
  184. EXPECT_TRUE(dd1 == manager->getIdentity("x'"));
  185. }
  186. TEST(CuddDd, MultiplyMatrixTest) {
  187. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  188. manager->addMetaVariable("x", 1, 9);
  189. storm::dd::Dd<storm::dd::DdType::CUDD> dd1 = manager->getIdentity("x").equals(manager->getIdentity("x'"));
  190. storm::dd::Dd<storm::dd::DdType::CUDD> dd2 = manager->getRange("x'");
  191. storm::dd::Dd<storm::dd::DdType::CUDD> dd3;
  192. dd1 *= manager->getConstant(2);
  193. ASSERT_NO_THROW(dd3 = dd1.multiplyMatrix(dd2, {"x'"}));
  194. ASSERT_NO_THROW(dd3.swapVariables({std::make_pair("x", "x'")}));
  195. EXPECT_TRUE(dd3 == dd2 * manager->getConstant(2));
  196. }
  197. TEST(CuddDd, GetSetValueTest) {
  198. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  199. manager->addMetaVariable("x", 1, 9);
  200. storm::dd::Dd<storm::dd::DdType::CUDD> dd1 = manager->getOne();
  201. ASSERT_NO_THROW(dd1.setValue("x", 4, 2));
  202. EXPECT_EQ(2, dd1.getLeafCount());
  203. std::map<std::string, int_fast64_t> metaVariableToValueMap;
  204. metaVariableToValueMap.emplace("x", 1);
  205. EXPECT_EQ(1, dd1.getValue(metaVariableToValueMap));
  206. metaVariableToValueMap.clear();
  207. metaVariableToValueMap.emplace("x", 4);
  208. EXPECT_EQ(2, dd1.getValue(metaVariableToValueMap));
  209. }
  210. TEST(CuddDd, ForwardIteratorTest) {
  211. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  212. manager->addMetaVariable("x", 1, 9);
  213. manager->addMetaVariable("y", 0, 3);
  214. storm::dd::Dd<storm::dd::DdType::CUDD> dd;
  215. ASSERT_NO_THROW(dd = manager->getRange("x"));
  216. storm::dd::DdForwardIterator<storm::dd::DdType::CUDD> it, ite;
  217. ASSERT_NO_THROW(it = dd.begin());
  218. ASSERT_NO_THROW(ite = dd.end());
  219. std::pair<storm::expressions::SimpleValuation, double> valuationValuePair;
  220. uint_fast64_t numberOfValuations = 0;
  221. while (it != ite) {
  222. ASSERT_NO_THROW(valuationValuePair = *it);
  223. ASSERT_NO_THROW(++it);
  224. ++numberOfValuations;
  225. }
  226. EXPECT_EQ(9, numberOfValuations);
  227. dd = manager->getRange("x");
  228. dd = dd.ite(manager->getOne(), manager->getOne());
  229. ASSERT_NO_THROW(it = dd.begin());
  230. ASSERT_NO_THROW(ite = dd.end());
  231. numberOfValuations = 0;
  232. while (it != ite) {
  233. ASSERT_NO_THROW(valuationValuePair = *it);
  234. ASSERT_NO_THROW(++it);
  235. ++numberOfValuations;
  236. }
  237. EXPECT_EQ(16, numberOfValuations);
  238. ASSERT_NO_THROW(it = dd.begin(false));
  239. ASSERT_NO_THROW(ite = dd.end());
  240. numberOfValuations = 0;
  241. while (it != ite) {
  242. ASSERT_NO_THROW(valuationValuePair = *it);
  243. ASSERT_NO_THROW(++it);
  244. ++numberOfValuations;
  245. }
  246. EXPECT_EQ(1, numberOfValuations);
  247. }
  248. TEST(CuddDd, ToExpressionTest) {
  249. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  250. manager->addMetaVariable("x", 1, 9);
  251. storm::dd::Dd<storm::dd::DdType::CUDD> dd;
  252. ASSERT_NO_THROW(dd = manager->getIdentity("x"));
  253. storm::expressions::Expression ddAsExpression;
  254. ASSERT_NO_THROW(ddAsExpression = dd.toExpression());
  255. storm::expressions::SimpleValuation valuation;
  256. for (std::size_t bit = 0; bit < manager->getMetaVariable("x").getNumberOfDdVariables(); ++bit) {
  257. valuation.addBooleanIdentifier("x." + std::to_string(bit));
  258. }
  259. storm::dd::DdMetaVariable<storm::dd::DdType::CUDD> const& metaVariable = manager->getMetaVariable("x");
  260. for (auto valuationValuePair : dd) {
  261. for (std::size_t i = 0; i < metaVariable.getNumberOfDdVariables(); ++i) {
  262. // Check if the i-th bit is set or not and modify the valuation accordingly.
  263. if (((valuationValuePair.first.getIntegerValue("x") - metaVariable.getLow()) & (1ull << (metaVariable.getNumberOfDdVariables() - i - 1))) != 0) {
  264. valuation.setBooleanValue("x." + std::to_string(i), true);
  265. } else {
  266. valuation.setBooleanValue("x." + std::to_string(i), false);
  267. }
  268. }
  269. // At this point, the constructed valuation should make the expression obtained from the DD evaluate to the very
  270. // same value as the current value obtained from the DD.
  271. EXPECT_EQ(valuationValuePair.second, ddAsExpression.evaluateAsDouble(&valuation));
  272. }
  273. storm::expressions::Expression mintermExpression = dd.getMintermExpression();
  274. // Check whether all minterms are covered.
  275. for (auto valuationValuePair : dd) {
  276. for (std::size_t i = 0; i < metaVariable.getNumberOfDdVariables(); ++i) {
  277. // Check if the i-th bit is set or not and modify the valuation accordingly.
  278. if (((valuationValuePair.first.getIntegerValue("x") - metaVariable.getLow()) & (1ull << (metaVariable.getNumberOfDdVariables() - i - 1))) != 0) {
  279. valuation.setBooleanValue("x." + std::to_string(i), true);
  280. } else {
  281. valuation.setBooleanValue("x." + std::to_string(i), false);
  282. }
  283. }
  284. // At this point, the constructed valuation should make the expression obtained from the DD evaluate to the very
  285. // same value as the current value obtained from the DD.
  286. EXPECT_TRUE(mintermExpression.evaluateAsBool(&valuation));
  287. }
  288. // Now check no additional minterms are covered.
  289. dd = !dd;
  290. for (auto valuationValuePair : dd) {
  291. for (std::size_t i = 0; i < metaVariable.getNumberOfDdVariables(); ++i) {
  292. // Check if the i-th bit is set or not and modify the valuation accordingly.
  293. if (((valuationValuePair.first.getIntegerValue("x") - metaVariable.getLow()) & (1ull << (metaVariable.getNumberOfDdVariables() - i - 1))) != 0) {
  294. valuation.setBooleanValue("x." + std::to_string(i), true);
  295. } else {
  296. valuation.setBooleanValue("x." + std::to_string(i), false);
  297. }
  298. }
  299. // At this point, the constructed valuation should make the expression obtained from the DD evaluate to the very
  300. // same value as the current value obtained from the DD.
  301. EXPECT_FALSE(mintermExpression.evaluateAsBool(&valuation));
  302. }
  303. }
  304. TEST(CuddDd, OddTest) {
  305. std::shared_ptr<storm::dd::DdManager<storm::dd::DdType::CUDD>> manager(new storm::dd::DdManager<storm::dd::DdType::CUDD>());
  306. manager->addMetaVariable("a");
  307. manager->addMetaVariable("x", 1, 9);
  308. storm::dd::Dd<storm::dd::DdType::CUDD> dd = manager->getIdentity("x");
  309. storm::dd::Odd<storm::dd::DdType::CUDD> odd;
  310. ASSERT_NO_THROW(odd = storm::dd::Odd<storm::dd::DdType::CUDD>(dd));
  311. EXPECT_EQ(9, odd.getTotalOffset());
  312. EXPECT_EQ(12, odd.getNodeCount());
  313. std::vector<double> ddAsVector;
  314. ASSERT_NO_THROW(ddAsVector = dd.toVector<double>());
  315. EXPECT_EQ(9, ddAsVector.size());
  316. for (uint_fast64_t i = 0; i < ddAsVector.size(); ++i) {
  317. EXPECT_TRUE(i+1 == ddAsVector[i]);
  318. }
  319. // Create a non-trivial matrix.
  320. dd = manager->getIdentity("x").equals(manager->getIdentity("x'")) * manager->getRange("x");
  321. dd += manager->getEncoding("x", 1) * manager->getRange("x'") + manager->getEncoding("x'", 1) * manager->getRange("x");
  322. // Create the ODDs.
  323. storm::dd::Odd<storm::dd::DdType::CUDD> rowOdd;
  324. ASSERT_NO_THROW(rowOdd = storm::dd::Odd<storm::dd::DdType::CUDD>(manager->getRange("x")));
  325. storm::dd::Odd<storm::dd::DdType::CUDD> columnOdd;
  326. ASSERT_NO_THROW(columnOdd = storm::dd::Odd<storm::dd::DdType::CUDD>(manager->getRange("x'")));
  327. // Try to translate the matrix.
  328. storm::storage::SparseMatrix<double> matrix;
  329. ASSERT_NO_THROW(matrix = dd.toMatrix({"x"}, {"x'"}, rowOdd, columnOdd));
  330. EXPECT_EQ(9, matrix.getRowCount());
  331. EXPECT_EQ(9, matrix.getColumnCount());
  332. EXPECT_EQ(25, matrix.getNonzeroEntryCount());
  333. dd = manager->getRange("x") * manager->getRange("x'") * manager->getEncoding("a", 0).ite(dd, dd + manager->getConstant(1));
  334. ASSERT_NO_THROW(matrix = dd.toMatrix({"x"}, {"x'"}, {"a"}, rowOdd, columnOdd));
  335. EXPECT_EQ(18, matrix.getRowCount());
  336. EXPECT_EQ(9, matrix.getRowGroupCount());
  337. EXPECT_EQ(9, matrix.getColumnCount());
  338. EXPECT_EQ(106, matrix.getNonzeroEntryCount());
  339. }