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.

350 lines
10 KiB

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #include <unistd.h>
  7. #include <time.h>
  8. #include <sys/types.h>
  9. #include <sys/time.h>
  10. #include <inttypes.h>
  11. #include <assert.h>
  12. #include "test_assert.h"
  13. #include "llmsset.h"
  14. #include "sylvan.h"
  15. #define BLACK "\33[22;30m"
  16. #define GRAY "\33[01;30m"
  17. #define RED "\33[22;31m"
  18. #define LRED "\33[01;31m"
  19. #define GREEN "\33[22;32m"
  20. #define LGREEN "\33[01;32m"
  21. #define BLUE "\33[22;34m"
  22. #define LBLUE "\33[01;34m"
  23. #define BROWN "\33[22;33m"
  24. #define YELLOW "\33[01;33m"
  25. #define CYAN "\33[22;36m"
  26. #define LCYAN "\33[22;36m"
  27. #define MAGENTA "\33[22;35m"
  28. #define LMAGENTA "\33[01;35m"
  29. #define NC "\33[0m"
  30. #define BOLD "\33[1m"
  31. #define ULINE "\33[4m" //underline
  32. #define BLINK "\33[5m"
  33. #define INVERT "\33[7m"
  34. __thread uint64_t seed = 1;
  35. uint64_t
  36. xorshift_rand(void)
  37. {
  38. uint64_t x = seed;
  39. if (seed == 0) seed = rand();
  40. x ^= x >> 12;
  41. x ^= x << 25;
  42. x ^= x >> 27;
  43. seed = x;
  44. return x * 2685821657736338717LL;
  45. }
  46. double
  47. uniform_deviate(uint64_t seed)
  48. {
  49. return seed * (1.0 / (0xffffffffffffffffL + 1.0));
  50. }
  51. int
  52. rng(int low, int high)
  53. {
  54. return low + uniform_deviate(xorshift_rand()) * (high-low);
  55. }
  56. static inline BDD
  57. make_random(int i, int j)
  58. {
  59. if (i == j) return rng(0, 2) ? sylvan_true : sylvan_false;
  60. BDD yes = make_random(i+1, j);
  61. BDD no = make_random(i+1, j);
  62. BDD result = sylvan_invalid;
  63. switch(rng(0, 4)) {
  64. case 0:
  65. result = no;
  66. sylvan_deref(yes);
  67. break;
  68. case 1:
  69. result = yes;
  70. sylvan_deref(no);
  71. break;
  72. case 2:
  73. result = sylvan_ref(sylvan_makenode(i, yes, no));
  74. sylvan_deref(no);
  75. sylvan_deref(yes);
  76. break;
  77. case 3:
  78. default:
  79. result = sylvan_ref(sylvan_makenode(i, no, yes));
  80. sylvan_deref(no);
  81. sylvan_deref(yes);
  82. break;
  83. }
  84. return result;
  85. }
  86. /** GC testing */
  87. VOID_TASK_2(gctest_fill, int, levels, int, width)
  88. {
  89. if (levels > 1) {
  90. int i;
  91. for (i=0; i<width; i++) { SPAWN(gctest_fill, levels-1, width); }
  92. for (i=0; i<width; i++) { SYNC(gctest_fill); }
  93. } else {
  94. sylvan_deref(make_random(0, 10));
  95. }
  96. }
  97. void report_table()
  98. {
  99. llmsset_t __sylvan_get_internal_data();
  100. llmsset_t tbl = __sylvan_get_internal_data();
  101. LACE_ME;
  102. size_t filled = llmsset_count_marked(tbl);
  103. size_t total = llmsset_get_size(tbl);
  104. printf("done, table: %0.1f%% full (%zu nodes).\n", 100.0*(double)filled/total, filled);
  105. }
  106. int test_gc(int threads)
  107. {
  108. LACE_ME;
  109. int N_canaries = 16;
  110. BDD canaries[N_canaries];
  111. char* hashes[N_canaries];
  112. char* hashes2[N_canaries];
  113. int i,j;
  114. for (i=0;i<N_canaries;i++) {
  115. canaries[i] = make_random(0, 10);
  116. hashes[i] = (char*)malloc(80);
  117. hashes2[i] = (char*)malloc(80);
  118. sylvan_getsha(canaries[i], hashes[i]);
  119. sylvan_test_isbdd(canaries[i]);
  120. }
  121. test_assert(sylvan_count_refs() == (size_t)N_canaries);
  122. for (j=0;j<10*threads;j++) {
  123. CALL(gctest_fill, 6, 5);
  124. for (i=0;i<N_canaries;i++) {
  125. sylvan_test_isbdd(canaries[i]);
  126. sylvan_getsha(canaries[i], hashes2[i]);
  127. test_assert(strcmp(hashes[i], hashes2[i]) == 0);
  128. }
  129. }
  130. test_assert(sylvan_count_refs() == (size_t)N_canaries);
  131. return 0;
  132. }
  133. TASK_2(MDD, random_ldd, int, depth, int, count)
  134. {
  135. uint32_t n[depth];
  136. MDD result = lddmc_false;
  137. int i, j;
  138. for (i=0; i<count; i++) {
  139. for (j=0; j<depth; j++) {
  140. n[j] = rng(0, 10);
  141. }
  142. //MDD old = result;
  143. result = lddmc_union_cube(result, n, depth);
  144. //assert(lddmc_cube(n, depth) != lddmc_true);
  145. //assert(result == lddmc_union(old, lddmc_cube(n, depth)));
  146. //assert(result != lddmc_true);
  147. }
  148. return result;
  149. }
  150. VOID_TASK_3(enumer, uint32_t*, values, size_t, count, void*, context)
  151. {
  152. return;
  153. (void)values;
  154. (void)count;
  155. (void)context;
  156. }
  157. int
  158. test_lddmc()
  159. {
  160. LACE_ME;
  161. sylvan_init_package(1LL<<24, 1LL<<24, 1LL<<24, 1LL<<24);
  162. sylvan_init_ldd();
  163. sylvan_gc_disable();
  164. MDD a, b, c;
  165. // Test union, union_cube, member_cube, satcount
  166. a = lddmc_cube((uint32_t[]){1,2,3,5,4,3}, 6);
  167. a = lddmc_union(a,lddmc_cube((uint32_t[]){2,2,3,5,4,3}, 6));
  168. c = b = a = lddmc_union_cube(a, (uint32_t[]){2,2,3,5,4,2}, 6);
  169. a = lddmc_union_cube(a, (uint32_t[]){2,3,3,5,4,3}, 6);
  170. a = lddmc_union(a, lddmc_cube((uint32_t[]){2,3,4,4,4,3}, 6));
  171. test_assert(lddmc_member_cube(a, (uint32_t[]){2,3,3,5,4,3}, 6));
  172. test_assert(lddmc_member_cube(a, (uint32_t[]){1,2,3,5,4,3}, 6));
  173. test_assert(lddmc_member_cube(a, (uint32_t[]){2,2,3,5,4,3}, 6));
  174. test_assert(lddmc_member_cube(a, (uint32_t[]){2,2,3,5,4,2}, 6));
  175. test_assert(lddmc_satcount(a) == 5);
  176. lddmc_sat_all_par(a, TASK(enumer), NULL);
  177. // Test minus, member_cube, satcount
  178. a = lddmc_minus(a, b);
  179. test_assert(lddmc_member_cube(a, (uint32_t[]){2,3,3,5,4,3}, 6));
  180. test_assert(!lddmc_member_cube(a, (uint32_t[]){1,2,3,5,4,3}, 6));
  181. test_assert(!lddmc_member_cube(a, (uint32_t[]){2,2,3,5,4,3}, 6));
  182. test_assert(!lddmc_member_cube(a, (uint32_t[]){2,2,3,5,4,2}, 6));
  183. test_assert(lddmc_member_cube(a, (uint32_t[]){2,3,4,4,4,3}, 6));
  184. test_assert(lddmc_satcount(a) == 2);
  185. // Test intersect
  186. test_assert(lddmc_satcount(lddmc_intersect(a,b)) == 0);
  187. test_assert(lddmc_intersect(b,c)==lddmc_intersect(c,b));
  188. test_assert(lddmc_intersect(b,c)==c);
  189. // Test project, project_minus
  190. a = lddmc_cube((uint32_t[]){1,2,3,5,4,3}, 6);
  191. a = lddmc_union_cube(a, (uint32_t[]){2,2,3,5,4,3}, 6);
  192. a = lddmc_union_cube(a, (uint32_t[]){2,2,3,5,4,2}, 6);
  193. a = lddmc_union_cube(a, (uint32_t[]){2,3,3,5,4,3}, 6);
  194. a = lddmc_union_cube(a, (uint32_t[]){2,3,4,4,4,3}, 6);
  195. // a = {<1,2,3,5,4,3>,<2,2,3,5,4,3>,<2,2,3,5,4,2>,<2,3,3,5,4,3>,<2,3,4,4,4,3>}
  196. MDD proj = lddmc_cube((uint32_t[]){1,1,-2},3);
  197. b = lddmc_cube((uint32_t[]){1,2}, 2);
  198. b = lddmc_union_cube(b, (uint32_t[]){2,2}, 2);
  199. b = lddmc_union_cube(b, (uint32_t[]){2,3}, 2);
  200. test_assert(lddmc_project(a, proj)==b);
  201. test_assert(lddmc_project_minus(a, proj, lddmc_false)==b);
  202. test_assert(lddmc_project_minus(a, proj, b)==lddmc_false);
  203. // Test relprod
  204. a = lddmc_cube((uint32_t[]){1},1);
  205. b = lddmc_cube((uint32_t[]){1,2},2);
  206. proj = lddmc_cube((uint32_t[]){1,2,-1}, 3);
  207. test_assert(lddmc_cube((uint32_t[]){2},1) == lddmc_relprod(a, b, proj));
  208. test_assert(lddmc_cube((uint32_t[]){3},1) == lddmc_relprod(a, lddmc_cube((uint32_t[]){1,3},2), proj));
  209. a = lddmc_union_cube(a, (uint32_t[]){2},1);
  210. test_assert(lddmc_satcount(a) == 2);
  211. test_assert(lddmc_cube((uint32_t[]){2},1) == lddmc_relprod(a, b, proj));
  212. b = lddmc_union_cube(b, (uint32_t[]){2,2},2);
  213. test_assert(lddmc_cube((uint32_t[]){2},1) == lddmc_relprod(a, b, proj));
  214. b = lddmc_union_cube(b, (uint32_t[]){2,3},2);
  215. test_assert(lddmc_satcount(lddmc_relprod(a, b, proj)) == 2);
  216. test_assert(lddmc_union(lddmc_cube((uint32_t[]){2},1),lddmc_cube((uint32_t[]){3},1)) == lddmc_relprod(a, b, proj));
  217. // Test relprev
  218. MDD universe = lddmc_union(lddmc_cube((uint32_t[]){1},1), lddmc_cube((uint32_t[]){2},1));
  219. a = lddmc_cube((uint32_t[]){2},1);
  220. b = lddmc_cube((uint32_t[]){1,2},2);
  221. test_assert(lddmc_cube((uint32_t[]){1},1) == lddmc_relprev(a, b, proj, universe));
  222. test_assert(lddmc_cube((uint32_t[]){1},1) == lddmc_relprev(a, b, proj, lddmc_cube((uint32_t[]){1},1)));
  223. a = lddmc_cube((uint32_t[]){1},1);
  224. MDD next = lddmc_relprod(a, b, proj);
  225. test_assert(lddmc_relprev(next, b, proj, a) == a);
  226. // Random tests
  227. MDD rnd1, rnd2;
  228. int i;
  229. for (i=0; i<200; i++) {
  230. int depth = rng(1, 20);
  231. rnd1 = CALL(random_ldd, depth, rng(0, 30));
  232. rnd2 = CALL(random_ldd, depth, rng(0, 30));
  233. test_assert(rnd1 != lddmc_true);
  234. test_assert(rnd2 != lddmc_true);
  235. test_assert(lddmc_intersect(rnd1,rnd2) == lddmc_intersect(rnd2,rnd1));
  236. test_assert(lddmc_union(rnd1,rnd2) == lddmc_union(rnd2,rnd1));
  237. MDD tmp = lddmc_union(lddmc_minus(rnd1, rnd2), lddmc_minus(rnd2, rnd1));
  238. test_assert(lddmc_intersect(tmp, lddmc_intersect(rnd1, rnd2)) == lddmc_false);
  239. test_assert(lddmc_union(tmp, lddmc_intersect(rnd1, rnd2)) == lddmc_union(rnd1, rnd2));
  240. test_assert(lddmc_minus(rnd1,rnd2) == lddmc_minus(rnd1, lddmc_intersect(rnd1,rnd2)));
  241. }
  242. // Test file stuff
  243. for (i=0; i<10; i++) {
  244. FILE *f = fopen("__lddmc_test_bdd", "w+");
  245. int N = 20;
  246. MDD rnd[N];
  247. size_t a[N];
  248. char sha[N][65];
  249. int j;
  250. for (j=0;j<N;j++) rnd[j] = CALL(random_ldd, 5, 500);
  251. for (j=0;j<N;j++) lddmc_getsha(rnd[j], sha[j]);
  252. for (j=0;j<N;j++) { a[j] = lddmc_serialize_add(rnd[j]); lddmc_serialize_tofile(f); }
  253. for (j=0;j<N;j++) test_assert(a[j] == lddmc_serialize_get(rnd[j]));
  254. for (j=0;j<N;j++) test_assert(rnd[j] == lddmc_serialize_get_reversed(a[j]));
  255. fseek(f, 0, SEEK_SET);
  256. lddmc_serialize_reset();
  257. sylvan_quit();
  258. sylvan_init_package(1LL<<24, 1LL<<24, 1LL<<24, 1LL<<24);
  259. sylvan_init_ldd();
  260. sylvan_gc_disable();
  261. for (j=0;j<N;j++) lddmc_serialize_fromfile(f);
  262. fclose(f);
  263. unlink("__lddmc_test_bdd");
  264. for (j=0;j<N;j++) rnd[j] = lddmc_serialize_get_reversed(a[j]);
  265. char sha2[N][65];
  266. for (j=0;j<N;j++) lddmc_getsha(rnd[j], sha2[j]);
  267. for (j=0;j<N;j++) test_assert(memcmp(sha[j], sha2[j], 64)==0);
  268. lddmc_serialize_reset();
  269. }
  270. sylvan_quit();
  271. return 0;
  272. }
  273. int runtests(int threads)
  274. {
  275. lace_init(threads, 100000);
  276. lace_startup(0, NULL, NULL);
  277. printf(BOLD "Testing LDDMC... ");
  278. fflush(stdout);
  279. if (test_lddmc()) return 1;
  280. printf(LGREEN "success" NC "!\n");
  281. printf(NC "Testing garbage collection... ");
  282. fflush(stdout);
  283. sylvan_init_package(1LL<<14, 1LL<<14, 1LL<<20, 1LL<<20);
  284. sylvan_init_bdd(1);
  285. sylvan_gc_enable();
  286. if (test_gc(threads)) return 1;
  287. sylvan_quit();
  288. printf(LGREEN "success" NC "!\n");
  289. lace_exit();
  290. return 0;
  291. }
  292. int main(int argc, char **argv)
  293. {
  294. int threads = 2;
  295. if (argc > 1) sscanf(argv[1], "%d", &threads);
  296. if (runtests(threads)) exit(1);
  297. printf(NC);
  298. exit(0);
  299. }