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.

796 lines
28 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. #include <sylvan_config.h>
  2. #include <assert.h>
  3. #include <inttypes.h>
  4. #include <math.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sylvan.h>
  10. #include <sylvan_common.h>
  11. #include <sylvan_cache.h>
  12. #include <sylvan_int.h>
  13. #include <sylvan_mtbdd_int.h>
  14. #include <sylvan_storm_rational_function.h>
  15. uint32_t srf_type;
  16. static uint64_t sylvan_storm_rational_function_hash(const uint64_t v, const uint64_t seed) {
  17. storm_rational_function_ptr x = (storm_rational_function_ptr)v;
  18. return storm_rational_function_hash(x, seed);
  19. }
  20. static int sylvan_storm_rational_function_equals(const uint64_t left, const uint64_t right) {
  21. return storm_rational_function_equals((storm_rational_function_ptr)(size_t)left, (storm_rational_function_ptr)(size_t)right);
  22. }
  23. static void sylvan_storm_rational_function_create(uint64_t *val) {
  24. // This function is called by the unique table when a leaf does not yet exist. We make a copy, which will be stored in the hash table.
  25. storm_rational_function_ptr* x = (storm_rational_function_ptr*)(size_t)val;
  26. storm_rational_function_init(x);
  27. }
  28. static void sylvan_storm_rational_function_destroy(uint64_t val) {
  29. // This function is called by the unique table when a leaf is removed during garbage collection.
  30. storm_rational_function_ptr x = (storm_rational_function_ptr)(size_t)val;
  31. storm_rational_function_destroy(x);
  32. }
  33. static char* sylvan_storm_rational_function_to_str(int comp, uint64_t val, char* buf, size_t buflen) {
  34. return storm_rational_function_to_str((storm_rational_function_ptr)(size_t)val, buf, buflen);
  35. (void)comp;
  36. }
  37. void sylvan_storm_rational_function_init() {
  38. // Register custom leaf type storing rational functions.
  39. srf_type = sylvan_mt_create_type();
  40. sylvan_mt_set_hash(srf_type, sylvan_storm_rational_function_hash);
  41. sylvan_mt_set_equals(srf_type, sylvan_storm_rational_function_equals);
  42. sylvan_mt_set_create(srf_type, sylvan_storm_rational_function_create);
  43. sylvan_mt_set_destroy(srf_type, sylvan_storm_rational_function_destroy);
  44. sylvan_mt_set_to_str(srf_type, sylvan_storm_rational_function_to_str);
  45. // sylvan_mt_set_write_binary(srf_type, sylvan_storm_rational_function_write_binary);
  46. // sylvan_mt_set_read_binary(srf_type, sylvan_storm_rational_function_read_binary);
  47. }
  48. uint32_t sylvan_storm_rational_function_get_type() {
  49. return srf_type;
  50. }
  51. MTBDD mtbdd_storm_rational_function(storm_rational_function_ptr val) {
  52. uint64_t terminalValue = (uint64_t)val;
  53. return mtbdd_makeleaf(srf_type, terminalValue);
  54. }
  55. storm_rational_function_ptr mtbdd_getstorm_rational_function_ptr(MTBDD terminal) {
  56. uint64_t value = mtbdd_getvalue(terminal);
  57. return (storm_rational_function_ptr)value;
  58. }
  59. TASK_IMPL_2(MTBDD, mtbdd_op_bool_to_storm_rational_function, MTBDD, a, size_t, v) {
  60. if (a == mtbdd_false) {
  61. return mtbdd_storm_rational_function(storm_rational_function_get_zero());
  62. }
  63. if (a == mtbdd_true) {
  64. return mtbdd_storm_rational_function(storm_rational_function_get_one());
  65. }
  66. // Ugly hack to get rid of the error "unused variable v" (because there is no version of uapply without a parameter).
  67. (void)v;
  68. return mtbdd_invalid;
  69. }
  70. TASK_IMPL_1(MTBDD, mtbdd_bool_to_storm_rational_function, MTBDD, dd) {
  71. return mtbdd_uapply(dd, TASK(mtbdd_op_bool_to_storm_rational_function), 0);
  72. }
  73. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_equals, MTBDD*, pa, MTBDD*, pb) {
  74. MTBDD a = *pa, b = *pb;
  75. /* Check for partial functions */
  76. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  77. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  78. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  79. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  80. return storm_rational_function_equals(ma, mb) ? mtbdd_true : mtbdd_false;
  81. }
  82. /* Commutative, so swap a,b for better cache performance */
  83. if (a < b) {
  84. *pa = b;
  85. *pb = a;
  86. }
  87. return mtbdd_invalid;
  88. }
  89. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_plus, MTBDD*, pa, MTBDD*, pb) {
  90. MTBDD a = *pa, b = *pb;
  91. /* Check for partial functions */
  92. if (a == mtbdd_false) return b;
  93. if (b == mtbdd_false) return a;
  94. if (a == mtbdd_true || b == mtbdd_true) return mtbdd_true;
  95. /* If both leaves, compute plus */
  96. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  97. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  98. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  99. storm_rational_function_ptr mres = storm_rational_function_plus(ma, mb);
  100. MTBDD res = mtbdd_storm_rational_function(mres);
  101. storm_rational_function_destroy(mres);
  102. return res;
  103. }
  104. /* Commutative, so swap a,b for better cache performance */
  105. if (a < b) {
  106. *pa = b;
  107. *pb = a;
  108. }
  109. return mtbdd_invalid;
  110. }
  111. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_minus, MTBDD*, pa, MTBDD*, pb) {
  112. MTBDD a = *pa, b = *pb;
  113. /* Check for partial functions */
  114. if (a == mtbdd_false) return sylvan_storm_rational_function_neg(b);
  115. if (b == mtbdd_false) return a;
  116. /* If both leaves, compute minus */
  117. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  118. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  119. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  120. storm_rational_function_ptr mres = storm_rational_function_minus(ma, mb);
  121. MTBDD res = mtbdd_storm_rational_function(mres);
  122. storm_rational_function_destroy(mres);
  123. return res;
  124. }
  125. return mtbdd_invalid;
  126. }
  127. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_times, MTBDD*, pa, MTBDD*, pb) {
  128. MTBDD a = *pa, b = *pb;
  129. /* Check for partial functions */
  130. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  131. if (a == mtbdd_true) return b;
  132. if (b == mtbdd_true) return a;
  133. /* If both leaves, compute multiplication */
  134. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  135. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  136. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  137. storm_rational_function_ptr mres = storm_rational_function_times(ma, mb);
  138. MTBDD res = mtbdd_storm_rational_function(mres);
  139. storm_rational_function_destroy(mres);
  140. return res;
  141. }
  142. /* Commutative, so make "a" the lowest for better cache performance */
  143. if (a < b) {
  144. *pa = b;
  145. *pb = a;
  146. }
  147. return mtbdd_invalid;
  148. }
  149. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_divide, MTBDD*, pa, MTBDD*, pb) {
  150. MTBDD a = *pa, b = *pb;
  151. /* Check for partial functions */
  152. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  153. /* If both leaves, compute division */
  154. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  155. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  156. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  157. storm_rational_function_ptr mres;
  158. if (storm_rational_function_is_zero(ma)) {
  159. mres = storm_rational_function_get_zero();
  160. } else if (storm_rational_function_is_zero(mb)) {
  161. mres = storm_rational_function_get_infinity();
  162. } else {
  163. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  164. mres = storm_rational_function_divide(ma, mb);
  165. }
  166. MTBDD res = mtbdd_storm_rational_function(mres);
  167. storm_rational_function_destroy(mres);
  168. return res;
  169. }
  170. return mtbdd_invalid;
  171. }
  172. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_less, MTBDD*, pa, MTBDD*, pb) {
  173. MTBDD a = *pa, b = *pb;
  174. /* Check for partial functions and for Boolean (filter) */
  175. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  176. /* If both leaves, compute less */
  177. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  178. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  179. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  180. return storm_rational_function_less(ma, mb) ? mtbdd_true : mtbdd_false;
  181. }
  182. return mtbdd_invalid;
  183. }
  184. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_less_or_equal, MTBDD*, pa, MTBDD*, pb) {
  185. MTBDD a = *pa, b = *pb;
  186. /* Check for partial functions and for Boolean (filter) */
  187. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  188. /* If both leaves, compute less or equal */
  189. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  190. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  191. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  192. return storm_rational_function_less_or_equal(ma, mb) ? mtbdd_true : mtbdd_false;
  193. }
  194. return mtbdd_invalid;
  195. }
  196. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_mod, MTBDD*, pa, MTBDD*, pb) {
  197. MTBDD a = *pa, b = *pb;
  198. /* Check for partial functions and for Boolean (filter) */
  199. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  200. /* If both leaves, compute modulo */
  201. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  202. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  203. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  204. storm_rational_function_ptr mres = storm_rational_function_mod(ma, mb);
  205. MTBDD res = mtbdd_storm_rational_function(mres);
  206. storm_rational_function_destroy(mres);
  207. return res;
  208. }
  209. return mtbdd_invalid;
  210. }
  211. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_min, MTBDD*, pa, MTBDD*, pb) {
  212. MTBDD a = *pa, b = *pb;
  213. /* Check for partial functions and for Boolean (filter) */
  214. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  215. /* If both leaves, compute min */
  216. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  217. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  218. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  219. storm_rational_function_ptr mres = storm_rational_function_min(ma, mb);
  220. MTBDD res = mtbdd_storm_rational_function(mres);
  221. storm_rational_function_destroy(mres);
  222. return res;
  223. }
  224. /* Commutative, so make "a" the lowest for better cache performance */
  225. if (a < b) {
  226. *pa = b;
  227. *pb = a;
  228. }
  229. return mtbdd_invalid;
  230. }
  231. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_abstract_op_min, MTBDD, a, MTBDD, b, int, k) {
  232. if (k==0) {
  233. return mtbdd_apply(a, b, TASK(sylvan_storm_rational_function_op_min));
  234. } else {
  235. MTBDD res = a;
  236. for (int i=0; i<k; i++) {
  237. mtbdd_refs_push(res);
  238. res = mtbdd_apply(res, res, TASK(sylvan_storm_rational_function_op_min));
  239. mtbdd_refs_pop(1);
  240. }
  241. return res;
  242. }
  243. }
  244. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_max, MTBDD*, pa, MTBDD*, pb) {
  245. MTBDD a = *pa, b = *pb;
  246. /* Check for partial functions and for Boolean (filter) */
  247. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  248. /* If both leaves, compute max */
  249. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  250. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  251. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  252. storm_rational_function_ptr mres = storm_rational_function_max(ma, mb);
  253. MTBDD res = mtbdd_storm_rational_function(mres);
  254. storm_rational_function_destroy(mres);
  255. return res;
  256. }
  257. /* Commutative, so make "a" the lowest for better cache performance */
  258. if (a < b) {
  259. *pa = b;
  260. *pb = a;
  261. }
  262. return mtbdd_invalid;
  263. }
  264. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_abstract_op_max, MTBDD, a, MTBDD, b, int, k) {
  265. if (k==0) {
  266. return mtbdd_apply(a, b, TASK(sylvan_storm_rational_function_op_max));
  267. } else {
  268. MTBDD res = a;
  269. for (int i=0; i<k; i++) {
  270. mtbdd_refs_push(res);
  271. res = mtbdd_apply(res, res, TASK(sylvan_storm_rational_function_op_max));
  272. mtbdd_refs_pop(1);
  273. }
  274. return res;
  275. }
  276. }
  277. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_pow, MTBDD*, pa, MTBDD*, pb) {
  278. MTBDD a = *pa, b = *pb;
  279. /* Check for partial functions and for Boolean (filter) */
  280. if (a == mtbdd_false || b == mtbdd_false) return mtbdd_false;
  281. /* Handle multiplication of leaves */
  282. if (mtbdd_isleaf(a) && mtbdd_isleaf(b)) {
  283. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  284. storm_rational_function_ptr mb = mtbdd_getstorm_rational_function_ptr(b);
  285. storm_rational_function_ptr mres = storm_rational_function_pow(ma, mb);
  286. MTBDD res = mtbdd_storm_rational_function(mres);
  287. storm_rational_function_destroy(mres);
  288. return res;
  289. }
  290. return mtbdd_invalid;
  291. }
  292. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_abstract_op_plus, MTBDD, a, MTBDD, b, int, k) {
  293. if (k==0) {
  294. return mtbdd_apply(a, b, TASK(sylvan_storm_rational_function_op_plus));
  295. } else {
  296. MTBDD res = a;
  297. for (int i=0; i<k; i++) {
  298. mtbdd_refs_push(res);
  299. res = mtbdd_apply(res, res, TASK(sylvan_storm_rational_function_op_plus));
  300. mtbdd_refs_pop(1);
  301. }
  302. return res;
  303. }
  304. }
  305. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_abstract_op_times, MTBDD, a, MTBDD, b, int, k) {
  306. if (k==0) {
  307. return mtbdd_apply(a, b, TASK(sylvan_storm_rational_function_op_times));
  308. } else {
  309. MTBDD res = a;
  310. for (int i=0; i<k; i++) {
  311. mtbdd_refs_push(res);
  312. res = mtbdd_apply(res, res, TASK(sylvan_storm_rational_function_op_times));
  313. mtbdd_refs_pop(1);
  314. }
  315. return res;
  316. }
  317. }
  318. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_neg, MTBDD, dd, size_t, p) {
  319. /* Handle partial functions */
  320. if (dd == mtbdd_false) return mtbdd_false;
  321. /* Compute result for leaf */
  322. if (mtbdd_isleaf(dd)) {
  323. storm_rational_function_ptr mdd = mtbdd_getstorm_rational_function_ptr(dd);
  324. storm_rational_function_ptr mres = storm_rational_function_negate(mdd);
  325. MTBDD res = mtbdd_storm_rational_function(mres);
  326. storm_rational_function_destroy(mres);
  327. return res;
  328. }
  329. return mtbdd_invalid;
  330. (void)p;
  331. }
  332. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_floor, MTBDD, dd, size_t, p) {
  333. /* Handle partial functions */
  334. if (dd == mtbdd_false) return mtbdd_false;
  335. /* Compute result for leaf */
  336. if (mtbdd_isleaf(dd)) {
  337. storm_rational_function_ptr mdd = mtbdd_getstorm_rational_function_ptr(dd);
  338. storm_rational_function_ptr mres = storm_rational_function_floor(mdd);
  339. MTBDD res = mtbdd_storm_rational_function(mres);
  340. storm_rational_function_destroy(mres);
  341. return res;
  342. }
  343. return mtbdd_invalid;
  344. (void)p;
  345. }
  346. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_ceil, MTBDD, dd, size_t, p) {
  347. /* Handle partial functions */
  348. if (dd == mtbdd_false) return mtbdd_false;
  349. /* Compute result for leaf */
  350. if (mtbdd_isleaf(dd)) {
  351. storm_rational_function_ptr mdd = mtbdd_getstorm_rational_function_ptr(dd);
  352. storm_rational_function_ptr mres = storm_rational_function_ceil(mdd);
  353. MTBDD res = mtbdd_storm_rational_function(mres);
  354. storm_rational_function_destroy(mres);
  355. return res;
  356. }
  357. return mtbdd_invalid;
  358. (void)p;
  359. }
  360. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_to_double, MTBDD, dd, size_t, p) {
  361. /* Handle partial functions */
  362. if (dd == mtbdd_false) return mtbdd_false;
  363. /* Compute result for leaf */
  364. if (mtbdd_isleaf(dd)) {
  365. storm_rational_function_ptr mdd = mtbdd_getstorm_rational_function_ptr(dd);
  366. MTBDD result = mtbdd_double(storm_rational_function_get_value_double(mdd));
  367. return result;
  368. }
  369. return mtbdd_invalid;
  370. (void)p;
  371. }
  372. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_and_exists, MTBDD, a, MTBDD, b, MTBDD, v) {
  373. /* Check terminal cases */
  374. /* If v == true, then <vars> is an empty set */
  375. if (v == mtbdd_true) return mtbdd_apply(a, b, TASK(sylvan_storm_rational_function_op_times));
  376. /* Try the times operator on a and b */
  377. MTBDD result = CALL(sylvan_storm_rational_function_op_times, &a, &b);
  378. if (result != mtbdd_invalid) {
  379. /* Times operator successful, store reference (for garbage collection) */
  380. mtbdd_refs_push(result);
  381. /* ... and perform abstraction */
  382. result = mtbdd_abstract(result, v, TASK(sylvan_storm_rational_function_abstract_op_plus));
  383. mtbdd_refs_pop(1);
  384. /* Note that the operation cache is used in mtbdd_abstract */
  385. return result;
  386. }
  387. /* Maybe perform garbage collection */
  388. sylvan_gc_test();
  389. /* Check cache. Note that we do this now, since the times operator might swap a and b (commutative) */
  390. if (cache_get3(CACHE_MTBDD_AND_EXISTS_RF, a, b, v, &result)) return result;
  391. /* Now, v is not a constant, and either a or b is not a constant */
  392. /* Get top variable */
  393. int la = mtbdd_isleaf(a);
  394. int lb = mtbdd_isleaf(b);
  395. mtbddnode_t na = la ? 0 : MTBDD_GETNODE(a);
  396. mtbddnode_t nb = lb ? 0 : MTBDD_GETNODE(b);
  397. uint32_t va = la ? 0xffffffff : mtbddnode_getvariable(na);
  398. uint32_t vb = lb ? 0xffffffff : mtbddnode_getvariable(nb);
  399. uint32_t var = va < vb ? va : vb;
  400. mtbddnode_t nv = MTBDD_GETNODE(v);
  401. uint32_t vv = mtbddnode_getvariable(nv);
  402. if (vv < var) {
  403. /* Recursive, then abstract result */
  404. result = CALL(sylvan_storm_rational_function_and_exists, a, b, node_gethigh(v, nv));
  405. mtbdd_refs_push(result);
  406. result = mtbdd_apply(result, result, TASK(sylvan_storm_rational_function_op_plus));
  407. mtbdd_refs_pop(1);
  408. } else {
  409. /* Get cofactors */
  410. MTBDD alow, ahigh, blow, bhigh;
  411. alow = (!la && va == var) ? node_getlow(a, na) : a;
  412. ahigh = (!la && va == var) ? node_gethigh(a, na) : a;
  413. blow = (!lb && vb == var) ? node_getlow(b, nb) : b;
  414. bhigh = (!lb && vb == var) ? node_gethigh(b, nb) : b;
  415. if (vv == var) {
  416. /* Recursive, then abstract result */
  417. mtbdd_refs_spawn(SPAWN(sylvan_storm_rational_function_and_exists, ahigh, bhigh, node_gethigh(v, nv)));
  418. MTBDD low = mtbdd_refs_push(CALL(sylvan_storm_rational_function_and_exists, alow, blow, node_gethigh(v, nv)));
  419. MTBDD high = mtbdd_refs_push(mtbdd_refs_sync(SYNC(sylvan_storm_rational_function_and_exists)));
  420. result = CALL(mtbdd_apply, low, high, TASK(sylvan_storm_rational_function_op_plus));
  421. mtbdd_refs_pop(2);
  422. } else /* vv > v */ {
  423. /* Recursive, then create node */
  424. mtbdd_refs_spawn(SPAWN(sylvan_storm_rational_function_and_exists, ahigh, bhigh, v));
  425. MTBDD low = mtbdd_refs_push(CALL(sylvan_storm_rational_function_and_exists, alow, blow, v));
  426. MTBDD high = mtbdd_refs_sync(SYNC(sylvan_storm_rational_function_and_exists));
  427. mtbdd_refs_pop(1);
  428. result = mtbdd_makenode(var, low, high);
  429. }
  430. }
  431. /* Store in cache */
  432. cache_put3(CACHE_MTBDD_AND_EXISTS_RF, a, b, v, result);
  433. return result;
  434. }
  435. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_threshold, MTBDD, a, size_t*, svalue) {
  436. storm_rational_function_ptr value = (storm_rational_function_ptr)svalue;
  437. if (mtbdd_isleaf(a)) {
  438. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  439. return storm_rational_function_less(ma, value) ? mtbdd_false : mtbdd_true;
  440. }
  441. return mtbdd_invalid;
  442. }
  443. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_op_strict_threshold, MTBDD, a, size_t*, svalue) {
  444. storm_rational_function_ptr value = (storm_rational_function_ptr)svalue;
  445. if (mtbdd_isleaf(a)) {
  446. storm_rational_function_ptr ma = mtbdd_getstorm_rational_function_ptr(a);
  447. return storm_rational_function_less_or_equal(ma, value) ? mtbdd_false : mtbdd_true;
  448. }
  449. return mtbdd_invalid;
  450. }
  451. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_threshold, MTBDD, dd, storm_rational_function_ptr, value)
  452. {
  453. return mtbdd_uapply(dd, TASK(sylvan_storm_rational_function_op_threshold), (size_t*)value);
  454. }
  455. TASK_IMPL_2(MTBDD, sylvan_storm_rational_function_strict_threshold, MTBDD, dd, storm_rational_function_ptr, value)
  456. {
  457. return mtbdd_uapply(dd, TASK(sylvan_storm_rational_function_op_strict_threshold), (size_t*)value);
  458. }
  459. TASK_IMPL_1(MTBDD, sylvan_storm_rational_function_minimum, MTBDD, a) {
  460. /* Check terminal case */
  461. if (a == mtbdd_false) return mtbdd_false;
  462. mtbddnode_t na = MTBDD_GETNODE(a);
  463. if (mtbddnode_isleaf(na)) return a;
  464. /* Maybe perform garbage collection */
  465. sylvan_gc_test();
  466. /* Check cache */
  467. MTBDD result;
  468. if (cache_get3(CACHE_MTBDD_MINIMUM_RF, a, 0, 0, &result)) return result;
  469. /* Call recursive */
  470. SPAWN(mtbdd_minimum, node_getlow(a, na));
  471. MTBDD high = CALL(sylvan_storm_rational_function_minimum, node_gethigh(a, na));
  472. MTBDD low = SYNC(sylvan_storm_rational_function_minimum);
  473. storm_rational_function_ptr fl = mtbdd_getstorm_rational_function_ptr(low);
  474. storm_rational_function_ptr fh = mtbdd_getstorm_rational_function_ptr(high);
  475. if (storm_rational_function_less_or_equal(fl, fh)) {
  476. return low;
  477. } else {
  478. return high;
  479. }
  480. /* Store in cache */
  481. cache_put3(CACHE_MTBDD_MINIMUM_RF, a, 0, 0, result);
  482. return result;
  483. }
  484. TASK_IMPL_1(MTBDD, sylvan_storm_rational_function_maximum, MTBDD, a)
  485. {
  486. /* Check terminal case */
  487. if (a == mtbdd_false) return mtbdd_false;
  488. mtbddnode_t na = MTBDD_GETNODE(a);
  489. if (mtbddnode_isleaf(na)) return a;
  490. /* Maybe perform garbage collection */
  491. sylvan_gc_test();
  492. /* Check cache */
  493. MTBDD result;
  494. if (cache_get3(CACHE_MTBDD_MAXIMUM_RF, a, 0, 0, &result)) return result;
  495. /* Call recursive */
  496. SPAWN(mtbdd_minimum, node_getlow(a, na));
  497. MTBDD high = CALL(sylvan_storm_rational_function_maximum, node_gethigh(a, na));
  498. MTBDD low = SYNC(sylvan_storm_rational_function_maximum);
  499. storm_rational_function_ptr fl = mtbdd_getstorm_rational_function_ptr(low);
  500. storm_rational_function_ptr fh = mtbdd_getstorm_rational_function_ptr(high);
  501. if (storm_rational_function_less(fl, fh)) {
  502. return high;
  503. } else {
  504. return low;
  505. }
  506. /* Store in cache */
  507. cache_put3(CACHE_MTBDD_MAXIMUM_RF, a, 0, 0, result);
  508. return result;
  509. }
  510. TASK_4(MTBDD, sylvan_storm_rational_function_equal_norm_d2, MTBDD, a, MTBDD, b, storm_rational_function_ptr, svalue, int*, shortcircuit)
  511. {
  512. /* Check short circuit */
  513. if (*shortcircuit) return mtbdd_false;
  514. /* Check terminal case */
  515. if (a == b) return mtbdd_true;
  516. if (a == mtbdd_false) return mtbdd_false;
  517. if (b == mtbdd_false) return mtbdd_false;
  518. mtbddnode_t na = MTBDD_GETNODE(a);
  519. mtbddnode_t nb = MTBDD_GETNODE(b);
  520. int la = mtbddnode_isleaf(na);
  521. int lb = mtbddnode_isleaf(nb);
  522. if (la && lb) {
  523. storm_rational_function_ptr fa = mtbdd_getstorm_rational_function_ptr(a);
  524. storm_rational_function_ptr fb = mtbdd_getstorm_rational_function_ptr(b);
  525. return storm_rational_function_equal_modulo_precision(0, fa, fb, svalue) ? mtbdd_true : mtbdd_false;
  526. }
  527. if (b < a) {
  528. MTBDD t = a;
  529. a = b;
  530. b = t;
  531. }
  532. /* Maybe perform garbage collection */
  533. sylvan_gc_test();
  534. /* Count operation */
  535. sylvan_stats_count(MTBDD_EQUAL_NORM);
  536. /* Check cache */
  537. MTBDD result;
  538. if (cache_get3(CACHE_MTBDD_EQUAL_NORM_RF, a, b, (uint64_t)svalue, &result)) {
  539. sylvan_stats_count(MTBDD_EQUAL_NORM_CACHED);
  540. return result;
  541. }
  542. /* Get top variable */
  543. uint32_t va = la ? 0xffffffff : mtbddnode_getvariable(na);
  544. uint32_t vb = lb ? 0xffffffff : mtbddnode_getvariable(nb);
  545. uint32_t var = va < vb ? va : vb;
  546. /* Get cofactors */
  547. MTBDD alow, ahigh, blow, bhigh;
  548. alow = va == var ? node_getlow(a, na) : a;
  549. ahigh = va == var ? node_gethigh(a, na) : a;
  550. blow = vb == var ? node_getlow(b, nb) : b;
  551. bhigh = vb == var ? node_gethigh(b, nb) : b;
  552. SPAWN(sylvan_storm_rational_function_equal_norm_d2, ahigh, bhigh, svalue, shortcircuit);
  553. result = CALL(sylvan_storm_rational_function_equal_norm_d2, alow, blow, svalue, shortcircuit);
  554. if (result == mtbdd_false) *shortcircuit = 1;
  555. if (result != SYNC(sylvan_storm_rational_function_equal_norm_d2)) result = mtbdd_false;
  556. if (result == mtbdd_false) *shortcircuit = 1;
  557. /* Store in cache */
  558. if (cache_put3(CACHE_MTBDD_EQUAL_NORM_RF, a, b, (uint64_t)svalue, result)) {
  559. sylvan_stats_count(MTBDD_EQUAL_NORM_CACHEDPUT);
  560. }
  561. return result;
  562. }
  563. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_equal_norm_d, MTBDD, a, MTBDD, b, storm_rational_function_ptr, d)
  564. {
  565. /* the implementation checks shortcircuit in every task and if the two
  566. MTBDDs are not equal module epsilon, then the computation tree quickly aborts */
  567. int shortcircuit = 0;
  568. return CALL(sylvan_storm_rational_function_equal_norm_d2, a, b, d, &shortcircuit);
  569. }
  570. /**
  571. * Compare two Double MTBDDs, returns Boolean True if they are equal within some value epsilon
  572. * This version computes the relative difference vs the value in a.
  573. */
  574. TASK_4(MTBDD, sylvan_storm_rational_function_equal_norm_rel_d2, MTBDD, a, MTBDD, b, storm_rational_function_ptr, svalue, int*, shortcircuit)
  575. {
  576. /* Check short circuit */
  577. if (*shortcircuit) return mtbdd_false;
  578. /* Check terminal case */
  579. if (a == b) return mtbdd_true;
  580. if (a == mtbdd_false) return mtbdd_false;
  581. if (b == mtbdd_false) return mtbdd_false;
  582. mtbddnode_t na = MTBDD_GETNODE(a);
  583. mtbddnode_t nb = MTBDD_GETNODE(b);
  584. int la = mtbddnode_isleaf(na);
  585. int lb = mtbddnode_isleaf(nb);
  586. if (la && lb) {
  587. storm_rational_function_ptr fa = mtbdd_getstorm_rational_function_ptr(a);
  588. storm_rational_function_ptr fb = mtbdd_getstorm_rational_function_ptr(b);
  589. return storm_rational_function_equal_modulo_precision(1, fa, fb, svalue) ? mtbdd_true : mtbdd_false;
  590. }
  591. /* Maybe perform garbage collection */
  592. sylvan_gc_test();
  593. /* Count operation */
  594. sylvan_stats_count(MTBDD_EQUAL_NORM_REL);
  595. /* Check cache */
  596. MTBDD result;
  597. if (cache_get3(CACHE_MTBDD_EQUAL_NORM_REL_RF, a, b, (uint64_t)svalue, &result)) {
  598. sylvan_stats_count(MTBDD_EQUAL_NORM_REL_CACHED);
  599. return result;
  600. }
  601. /* Get top variable */
  602. uint32_t va = la ? 0xffffffff : mtbddnode_getvariable(na);
  603. uint32_t vb = lb ? 0xffffffff : mtbddnode_getvariable(nb);
  604. uint32_t var = va < vb ? va : vb;
  605. /* Get cofactors */
  606. MTBDD alow, ahigh, blow, bhigh;
  607. alow = va == var ? node_getlow(a, na) : a;
  608. ahigh = va == var ? node_gethigh(a, na) : a;
  609. blow = vb == var ? node_getlow(b, nb) : b;
  610. bhigh = vb == var ? node_gethigh(b, nb) : b;
  611. SPAWN(sylvan_storm_rational_function_equal_norm_rel_d2, ahigh, bhigh, svalue, shortcircuit);
  612. result = CALL(sylvan_storm_rational_function_equal_norm_rel_d2, alow, blow, svalue, shortcircuit);
  613. if (result == mtbdd_false) *shortcircuit = 1;
  614. if (result != SYNC(sylvan_storm_rational_function_equal_norm_rel_d2)) result = mtbdd_false;
  615. if (result == mtbdd_false) *shortcircuit = 1;
  616. /* Store in cache */
  617. if (cache_put3(CACHE_MTBDD_EQUAL_NORM_REL_RF, a, b, (uint64_t)svalue, result)) {
  618. sylvan_stats_count(MTBDD_EQUAL_NORM_REL_CACHEDPUT);
  619. }
  620. return result;
  621. }
  622. TASK_IMPL_3(MTBDD, sylvan_storm_rational_function_equal_norm_rel_d, MTBDD, a, MTBDD, b, storm_rational_function_ptr, d)
  623. {
  624. /* the implementation checks shortcircuit in every task and if the two
  625. MTBDDs are not equal module epsilon, then the computation tree quickly aborts */
  626. int shortcircuit = 0;
  627. return CALL(sylvan_storm_rational_function_equal_norm_rel_d2, a, b, d, &shortcircuit);
  628. }