#include #include #include #include #include #include #include #include #include #include #include "sylvan.h" #include "test_assert.h" #include "sylvan_int.h" __thread uint64_t seed = 1; uint64_t xorshift_rand(void) { uint64_t x = seed; if (seed == 0) seed = rand(); x ^= x >> 12; x ^= x << 25; x ^= x >> 27; seed = x; return x * 2685821657736338717LL; } double uniform_deviate(uint64_t seed) { return seed * (1.0 / (0xffffffffffffffffL + 1.0)); } int rng(int low, int high) { return low + uniform_deviate(xorshift_rand()) * (high-low); } static int test_cache() { test_assert(cache_getused() == 0); /** * Test cache for large number of random entries */ size_t number_add = 4000000; uint64_t *arr = (uint64_t*)malloc(sizeof(uint64_t)*4*number_add); for (size_t i=0; i 111 and !000 --> 000 t = sylvan_false; t = sylvan_union_cube(t, all_vars_set, ((uint8_t[]){0,1,0,1,0,1})); t = sylvan_union_cube(t, all_vars_set, ((uint8_t[]){1,0,2,0,2,0})); t = sylvan_union_cube(t, all_vars_set, ((uint8_t[]){2,0,1,0,2,0})); t = sylvan_union_cube(t, all_vars_set, ((uint8_t[]){2,0,2,0,1,0})); s = sylvan_cube(vars_set, (uint8_t[]){0,0,1}); zeroes = sylvan_cube(vars_set, (uint8_t[]){0,0,0}); ones = sylvan_cube(vars_set, (uint8_t[]){1,1,1}); next = sylvan_relnext(s, t, all_vars_set); prev = sylvan_relprev(t, next, all_vars_set); test_assert(next == zeroes); test_assert(prev == sylvan_not(zeroes)); next = sylvan_relnext(next, t, all_vars_set); prev = sylvan_relprev(t, next, all_vars_set); test_assert(next == ones); test_assert(prev == zeroes); t = sylvan_cube(all_vars_set, (uint8_t[]){0,0,0,0,0,1}); test_assert(sylvan_relprev(t, s, all_vars_set) == zeroes); test_assert(sylvan_relprev(t, sylvan_not(s), all_vars_set) == sylvan_false); test_assert(sylvan_relnext(s, t, all_vars_set) == sylvan_false); test_assert(sylvan_relnext(zeroes, t, all_vars_set) == s); t = sylvan_cube(all_vars_set, (uint8_t[]){0,0,0,0,0,2}); test_assert(sylvan_relprev(t, s, all_vars_set) == zeroes); test_assert(sylvan_relprev(t, zeroes, all_vars_set) == zeroes); test_assert(sylvan_relnext(sylvan_not(zeroes), t, all_vars_set) == sylvan_false); return 0; } int test_compose() { LACE_ME; BDD a = sylvan_ithvar(1); BDD b = sylvan_ithvar(2); BDD a_or_b = sylvan_or(a, b); BDD one = make_random(3, 16); BDD two = make_random(8, 24); BDDMAP map = sylvan_map_empty(); map = sylvan_map_add(map, 1, one); map = sylvan_map_add(map, 2, two); test_assert(sylvan_map_key(map) == 1); test_assert(sylvan_map_value(map) == one); test_assert(sylvan_map_key(sylvan_map_next(map)) == 2); test_assert(sylvan_map_value(sylvan_map_next(map)) == two); test_assert(testEqual(one, sylvan_compose(a, map))); test_assert(testEqual(two, sylvan_compose(b, map))); test_assert(testEqual(sylvan_or(one, two), sylvan_compose(a_or_b, map))); map = sylvan_map_add(map, 2, one); test_assert(testEqual(sylvan_compose(a_or_b, map), one)); map = sylvan_map_add(map, 1, two); test_assert(testEqual(sylvan_or(one, two), sylvan_compose(a_or_b, map))); test_assert(testEqual(sylvan_and(one, two), sylvan_compose(sylvan_and(a, b), map))); // test that composing [0:=true] on "0" yields true map = sylvan_map_add(sylvan_map_empty(), 1, sylvan_true); test_assert(testEqual(sylvan_compose(a, map), sylvan_true)); // test that composing [0:=false] on "0" yields false map = sylvan_map_add(sylvan_map_empty(), 1, sylvan_false); test_assert(testEqual(sylvan_compose(a, map), sylvan_false)); return 0; } int test_ldd() { // very basic testing of makenode for (int i=0; i<10; i++) { uint32_t value = rng(0, 100); MDD m = lddmc_makenode(value, lddmc_true, lddmc_false); test_assert(lddmc_getvalue(m) == value); test_assert(lddmc_getdown(m) == lddmc_true); test_assert(lddmc_getright(m) == lddmc_false); test_assert(lddmc_iscopy(m) == 0); test_assert(lddmc_follow(m, value) == lddmc_true); for (int j=0; j<100; j++) { uint32_t other_value = rng(0, 100); if (value != other_value) test_assert(lddmc_follow(m, other_value) == lddmc_false); } } // test handling of the copy node by primitives MDD m = lddmc_make_copynode(lddmc_true, lddmc_false); test_assert(lddmc_iscopy(m) == 1); test_assert(lddmc_getvalue(m) == 0); test_assert(lddmc_getdown(m) == lddmc_true); test_assert(lddmc_getright(m) == lddmc_false); m = lddmc_extendnode(m, 0, lddmc_true); test_assert(lddmc_iscopy(m) == 1); test_assert(lddmc_getvalue(m) == 0); test_assert(lddmc_getdown(m) == lddmc_true); test_assert(lddmc_getright(m) != lddmc_false); test_assert(lddmc_follow(m, 0) == lddmc_true); test_assert(lddmc_getvalue(lddmc_getright(m)) == 0); test_assert(lddmc_iscopy(lddmc_getright(m)) == 0); test_assert(lddmc_makenode(0, lddmc_true, lddmc_false) == lddmc_getright(m)); LACE_ME; // test union_cube for (int i=0; i<100; i++) { int depth = rng(1, 6); int elements = rng(1, 30); m = make_random_ldd_set(depth, 10, elements); assert(m != lddmc_true); assert(m != lddmc_false); assert(lddmc_satcount(m) <= elements); assert(lddmc_satcount(m) >= 1); } // test simply transition relation { MDD states, rel, meta, expected; // relation: (0,0) to (1,1) rel = lddmc_cube((uint32_t[]){0,1,0,1}, 4); test_assert(lddmc_satcount(rel) == 1); // relation: (0,0) to (2,2) rel = lddmc_union_cube(rel, (uint32_t[]){0,2,0,2}, 4); test_assert(lddmc_satcount(rel) == 2); // meta: read write read write meta = lddmc_cube((uint32_t[]){1,2,1,2}, 4); test_assert(lddmc_satcount(meta) == 1); // initial state: (0,0) states = lddmc_cube((uint32_t[]){0,0}, 2); test_assert(lddmc_satcount(states) == 1); // relprod should give two states states = lddmc_relprod(states, rel, meta); test_assert(lddmc_satcount(states) == 2); // relprod should give states (1,1) and (2,2) expected = lddmc_cube((uint32_t[]){1,1}, 2); expected = lddmc_union_cube(expected, (uint32_t[]){2,2}, 2); test_assert(states == expected); // now test relprod union on the simple example states = lddmc_cube((uint32_t[]){0,0}, 2); states = lddmc_relprod_union(states, rel, meta, states); test_assert(lddmc_satcount(states) == 3); test_assert(states == lddmc_union(states, expected)); // now create transition (1,1) --> (1,1) (using copy nodes) rel = lddmc_cube_copy((uint32_t[]){1,0,1,0}, (int[]){0,1,0,1}, 4); states = lddmc_relprod(states, rel, meta); // the result should be just state (1,1) test_assert(states == lddmc_cube((uint32_t[]){1,1}, 2)); MDD statezero = lddmc_cube((uint32_t[]){0,0}, 2); states = lddmc_union_cube(statezero, (uint32_t[]){1,1}, 2); test_assert(lddmc_relprod_union(states, rel, meta, statezero) == states); // now create transition (*,*) --> (*,*) (copy nodes) rel = lddmc_cube_copy((uint32_t[]){0,0}, (int[]){1,1}, 2); meta = lddmc_cube((uint32_t[]){4,4}, 2); states = make_random_ldd_set(2, 10, 10); MDD states2 = make_random_ldd_set(2, 10, 10); test_assert(lddmc_union(states, states2) == lddmc_relprod_union(states, rel, meta, states2)); } return 0; } int runtests() { // we are not testing garbage collection sylvan_gc_disable(); if (test_cache()) return 1; if (test_bdd()) return 1; for (int j=0;j<10;j++) if (test_cube()) return 1; for (int j=0;j<10;j++) if (test_relprod()) return 1; for (int j=0;j<10;j++) if (test_compose()) return 1; for (int j=0;j<10;j++) if (test_operators()) return 1; if (test_ldd()) return 1; return 0; } int main() { // Standard Lace initialization with 1 worker lace_init(1, 0); lace_startup(0, NULL, NULL); // Simple Sylvan initialization, also initialize BDD, MTBDD and LDD support sylvan_set_sizes(1LL<<20, 1LL<<20, 1LL<<16, 1LL<<16); sylvan_init_package(); sylvan_init_bdd(); sylvan_init_mtbdd(); sylvan_init_ldd(); int res = runtests(); sylvan_quit(); lace_exit(); return res; }