def test_collect_garbage(): # all nodes are garbage g = BDD({'x': 0, 'y': 1}) u = g.add_expr('x & y') n = len(g) assert n == 4, n uref = g._ref[abs(u)] assert uref == 0, uref _, v, w = g._succ[abs(u)] vref = g._ref[abs(v)] wref = g._ref[w] assert vref == 5, vref assert wref == 1, wref g.collect_garbage() n = len(g) assert n == 1, n assert u not in g, g._succ assert w not in g, g._succ # some nodes not garbage # projection of x is garbage g = BDD({'x': 0, 'y': 1}) u = g.add_expr('x & y') n = len(g) assert n == 4, n g._ref[abs(u)] += 1 uref = g._ref[abs(u)] assert uref == 1, uref g.collect_garbage() n = len(g) assert n == 3, n
def test_image_rename_map_checks(): ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} bdd = BDD(ordering) # non-adjacent rename = {0: 2, 3: 4} qvars = set() with nt.assert_raises(AssertionError): _bdd.image(1, 1, rename, qvars, bdd) with nt.assert_raises(AssertionError): _bdd.preimage(1, 1, rename, qvars, bdd) # overlapping keys and values rename = {0: 1, 1: 2} with nt.assert_raises(AssertionError): _bdd.image(1, 1, rename, qvars, bdd) with nt.assert_raises(AssertionError): _bdd.preimage(1, 1, rename, qvars, bdd) # may be in support after quantification ? trans = bdd.add_expr('x -> xp') source = bdd.add_expr('x & y') qvars = {0} rename = {1: 0, 3: 2} with nt.assert_raises(AssertionError): _bdd.image(trans, source, rename, qvars, bdd) # in support of `target` ? qvars = set() target = bdd.add_expr('y & yp') rename = {2: 3} with nt.assert_raises(AssertionError): _bdd.preimage(trans, target, rename, qvars, bdd)
def test_rename(): ordering = {'x': 0, 'xp': 1} g = BDD(ordering) x = g.add_expr('x') xp = g.add_expr('xp') dvars = {'x': 'xp'} xrenamed = g.let(dvars, x) assert xrenamed == xp, xrenamed ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} g = BDD(ordering) u = g.add_expr('x && y && ! z') dvars = {'x': 'xp', 'y': 'yp', 'z': 'zp'} urenamed = g.let(dvars, u) up = g.add_expr('xp && yp && ! zp') assert urenamed == up, urenamed # assertion violations # non-neighbors dvars = {'x': 'yp'} r = g.let(dvars, u) r_ = g.add_expr('yp && y && ! z') assert r == r_, (r, r_) # u not in bdd dvars = {'x': 'xp'} with nt.assert_raises(AssertionError): g.let(dvars, 1000) # y essential for u dvars = {'xp': 'y'} with nt.assert_raises(AssertionError): g.let(dvars, u) # old and new vars intersect dvars = {'x': 'x'} with nt.assert_raises(AssertionError): g.let(dvars, u)
def test_descendants(): ordering = dict(x=0, y=1) b = BDD(ordering) u = b.add_expr('x && y') v = b.add_expr('x | y') roots = [u, v] nodes = b.descendants(roots) nodes_u = b.descendants([u]) nodes_v = b.descendants([v]) assert u in nodes_u, nodes_u assert v in nodes_v, nodes_v assert u in nodes, nodes assert v in nodes, nodes assert 1 in nodes_u, nodes_u assert 1 in nodes_v, nodes_v assert 1 in nodes, nodes assert len(nodes_u) == 3, nodes_u assert len(nodes_v) == 3, nodes_v assert nodes_u != nodes_v, (nodes_u, nodes_v) assert len(nodes) == 4, nodes assert nodes == nodes_u.union(nodes_v), (nodes, b._succ) # no roots roots = [] nodes = b.descendants(roots) assert len(nodes) == 0, nodes
def test_rename(): ordering = {'x': 0, 'xp': 1} g = BDD(ordering) x = g.add_expr('x') xp = g.add_expr('xp') dvars = {'x': 'xp'} xrenamed = _bdd.rename(x, g, dvars) assert xrenamed == xp, xrenamed ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} g = BDD(ordering) u = g.add_expr('x && y && ! z') dvars = {'x': 'xp', 'y': 'yp', 'z': 'zp'} urenamed = _bdd.rename(u, g, dvars) up = g.add_expr('xp && yp && ! zp') assert urenamed == up, urenamed # assertion violations # non-neighbors dvars = {'x': 'yp'} r = _bdd.rename(u, g, dvars) r_ = g.add_expr('yp && y && ! z') assert r == r_, (r, r_) # u not in bdd dvars = {'x': 'xp'} with nt.assert_raises(AssertionError): _bdd.rename(1000, g, dvars) # y essential for u dvars = {'xp': 'y'} with nt.assert_raises(AssertionError): _bdd.rename(u, g, dvars) # old and new vars intersect dvars = {'x': 'x'} with nt.assert_raises(AssertionError): _bdd.rename(u, g, dvars)
def test_image_rename_map_checks(): ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} bdd = BDD(ordering) # non-adjacent rename = {0: 2, 3: 4} qvars = set() r = _bdd.image(1, 1, rename, qvars, bdd) assert r == 1, r r = _bdd.preimage(1, 1, rename, qvars, bdd) assert r == 1, r # overlapping keys and values rename = {0: 1, 1: 2} with nt.assert_raises(AssertionError): _bdd.image(1, 1, rename, qvars, bdd) with nt.assert_raises(AssertionError): _bdd.preimage(1, 1, rename, qvars, bdd) # may be in support after quantification ? trans = bdd.add_expr('x -> xp') source = bdd.add_expr('x & y') qvars = {0} rename = {1: 0, 3: 2} with nt.assert_raises(AssertionError): _bdd.image(trans, source, rename, qvars, bdd) # in support of `target` ? qvars = set() target = bdd.add_expr('y & yp') rename = {2: 3} with nt.assert_raises(AssertionError): _bdd.preimage(trans, target, rename, qvars, bdd)
def test_descendants(): ordering = dict(x=0, y=1) b = BDD(ordering) u = b.add_expr('x && y') v = b.add_expr('x | y') roots = [u, v] nodes = b.descendants(roots) nodes_u = b.descendants([u]) nodes_v = b.descendants([v]) assert u in nodes_u, nodes_u assert v in nodes_v, nodes_v assert u in nodes, nodes assert v in nodes, nodes assert 1 in nodes_u, nodes_u assert 1 in nodes_v, nodes_v assert 1 in nodes, nodes assert len(nodes_u) == 3, nodes_u assert len(nodes_v) == 3, nodes_v assert nodes_u != nodes_v, (nodes_u, nodes_v) assert len(nodes) == 4, nodes assert nodes == nodes_u.union(nodes_v), ( nodes, b._succ) # no roots roots = [] nodes = b.descendants(roots) assert len(nodes) == 0, nodes
def test_rename(): ordering = {'x': 0, 'xp': 1} g = BDD(ordering) x = g.add_expr('x') xp = g.add_expr('xp') dvars = {'x': 'xp'} xrenamed = _bdd.rename(x, g, dvars) assert xrenamed == xp, xrenamed ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} g = BDD(ordering) u = g.add_expr('x && y && ! z') dvars = {'x': 'xp', 'y': 'yp', 'z': 'zp'} urenamed = _bdd.rename(u, g, dvars) up = g.add_expr('xp && yp && ! zp') assert urenamed == up, urenamed # assertion violations # non-neighbors dvars = {'x': 'yp'} with nt.assert_raises(AssertionError): _bdd.rename(u, g, dvars) # u not in bdd dvars = {'x': 'xp'} with nt.assert_raises(AssertionError): _bdd.rename(15, g, dvars) # y essential for u dvars = {'xp': 'y'} with nt.assert_raises(AssertionError): _bdd.rename(u, g, dvars) # old and new vars intersect dvars = {'x': 'x'} with nt.assert_raises(AssertionError): _bdd.rename(u, g, dvars)
def test_add_expr(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) # x ix = ordering['x'] u = g.add_expr('x') h = ref_var(ix) compare(u, g, h) # x and y u = g.add_expr('x && y') h = ref_x_and_y() compare(u, g, h)
def test_quantify(): ordering = {'x': 0, 'y': 1, 'z': 2} g = BDD(ordering) # x & y e = g.add_expr('x && ! y') x = g.add_expr('x') not_y = g.add_expr('! y') assert g.quantify(e, {'x'}) == not_y assert g.quantify(e, {'x'}, forall=True) == -1 assert g.quantify(e, {'y'}) == x assert g.quantify(e, {'x'}, forall=True) == -1 # x | y | z e = g.add_expr('x || y || z') xy = g.add_expr('x || y') yz = g.add_expr('y || z') zx = g.add_expr('z || x') assert g.quantify(e, {'x'}) assert g.quantify(e, {'y'}) assert g.quantify(e, {'z'}) assert g.quantify(e, {'z'}, forall=True) == xy assert g.quantify(e, {'x'}, forall=True) == yz assert g.quantify(e, {'y'}, forall=True) == zx # complement edges u = -x v = g.quantify(u, {'y'}, forall=True) assert v == -x, g.to_expr(v) # multiple values: test recursion e = g.add_expr('x & y & z') x = g.add_expr('x') r = g.quantify(e, {'y', 'z'}) assert r == x, r
def test_sifting(): # Figs. 6.24, 6.25 Baier 2008 g = BDD({'z1': 0, 'z2': 1, 'z3': 2, 'y1': 3, 'y2': 4, 'y3': 5}) u = g.add_expr('(z1 & y1) | (z2 & y2) | (z3 & y3)') g.incref(u) g.collect_garbage() n = len(g) assert n == 15, n _bdd.reorder(g) u_ = g.add_expr('(z1 & y1) | (z2 & y2) | (z3 & y3)') g.incref(u) g.collect_garbage() g.assert_consistent() assert u == u_, (u, u_)
def test_compose(): ordering = {'x': 0, 'y': 1, 'z': 2} g = BDD(ordering) # x & (x | z) a = g.add_expr('x && y') b = g.add_expr('x || z') c = g.compose(a, 'y', b) d = g.add_expr('x && (x || z)') assert c == d, (c, d) # (y | z) & x ordering = {'x': 0, 'y': 1, 'z': 2, 'w': 3} g = BDD(ordering) a = g.add_expr('(x && y) || z') b = g.add_expr('(y || z) && x') c = g.compose(a, 'z', b) assert c == b, (c, b) # long expr ordering = {'x': 0, 'y': 1, 'z': 2, 'w': 3} g = BDD(ordering) a = g.add_expr('(x && y) || (!z || (w && y && x))') b = g.add_expr('(y || z) && x') c = g.compose(a, 'y', b) d = g.add_expr('(x && ((y || z) && x)) ||' ' (!z || (w && ((y || z) && x) && x))') assert c == d, (c, d) # complemented edges ordering = {'x': 0, 'y': 1} g = BDD(ordering) f = g.add_expr('x <-> y') var = 'y' new_level = 0 var_node = g.find_or_add(new_level, -1, 1) u = g.compose(f, var, var_node) assert u == 1, g.to_expr(u)
def test_compose(): ordering = {'x': 0, 'y': 1, 'z': 2} g = BDD(ordering) # x & (x | z) a = g.add_expr('x && y') b = g.add_expr('x || z') c = g.compose(a, 'y', b) d = g.add_expr('x && (x || z)') assert c == d, (c, d) # (y | z) & x ordering = {'x': 0, 'y': 1, 'z': 2, 'w': 3} g = BDD(ordering) a = g.add_expr('(x && y) || z') b = g.add_expr('(y || z) && x') c = g.compose(a, 'z', b) assert c == b, (c, b) # long expr ordering = {'x': 0, 'y': 1, 'z': 2, 'w': 3} g = BDD(ordering) a = g.add_expr('(x && y) || (!z || (w && y && x))') b = g.add_expr('(y || z) && x') c = g.compose(a, 'y', b) d = g.add_expr( '(x && ((y || z) && x)) ||' ' (!z || (w && ((y || z) && x) && x))') assert c == d, (c, d) # complemented edges ordering = {'x': 0, 'y': 1} g = BDD(ordering) f = g.add_expr('x <-> y') var = 'y' new_level = 0 var_node = g.find_or_add(new_level, -1, 1) u = g.compose(f, var, var_node) assert u == 1, g.to_expr(u)
def test_dump_load(): prefix = 'test_dump_load' fname = prefix + '.p' dvars = dict(x=0, y=1) # dump b = BDD(dvars) e = 'x & !y' u_dumped = b.add_expr(e) b.dump(fname, [u_dumped]) b.dump(fname) # no roots # load b = BDD(dvars) b.add_expr('x | y') u_new = b.add_expr(e) umap = b.load(fname) u_loaded = umap[abs(u_dumped)] if u_dumped < 0: u_loaded = -u_loaded assert u_loaded == u_new, (u_dumped, u_loaded, u_new, umap) assert b.assert_consistent()
def test_dump_load_manager(): prefix = 'test_dump_load_manager' g = BDD({'x': 0, 'y': 1}) e = 'x & !y' u = g.add_expr(e) g.incref(u) fname = prefix + '.p' g._dump_manager(fname) h = g._load_manager(fname) assert g.assert_consistent() u_ = h.add_expr(e) assert u == u_, (u, u_)
def test_dump_load(): prefix = 'test_dump_load' fname = prefix + '.p' dvars = dict(x=0, y=1) # dump b = BDD(dvars) e = 'x & !y' u_dumped = b.add_expr(e) b.dump(fname, [u_dumped]) b.dump(fname) # no roots # load b = BDD(dvars) b.add_expr('x | y') u_new = b.add_expr(e) umap = b.load(fname) u_loaded = umap[abs(u_dumped)] if u_dumped < 0: u_loaded = -u_loaded assert u_loaded == u_new, ( u_dumped, u_loaded, u_new, umap) assert b.assert_consistent()
def test_dump_load(): prefix = 'test_dump_load' g = BDD({'x': 0, 'y': 1}) e = 'x & !y' u = g.add_expr(e) g.incref(u) fname = prefix + '.p' g.dump(fname) h = BDD.load(fname) assert h.assert_consistent() u_ = h.add_expr(e) assert u == u_, (u, u_) h.dump(prefix + '.pdf')
def test_cofactor(): ordering = {'x': 0, 'y': 1, 'z': 2} g = BDD(ordering) # u not in g with nt.assert_raises(AssertionError): g.cofactor(5, {'x': 0, 'y': 1, 'z': 0}) # x & y e = g.add_expr('x && y') x = g.add_expr('x') assert g.cofactor(x, {'x': 0}) == -1 assert g.cofactor(x, {'x': 1}) == 1 assert g.cofactor(-x, {'x': 0}) == 1 assert g.cofactor(-x, {'x': 1}) == -1 y = g.add_expr('y') assert g.cofactor(e, {'x': 1}) == y assert g.cofactor(e, {'x': 0}) == -1 assert g.cofactor(e, {'y': 1}) == x assert g.cofactor(e, {'y': 0}) == -1 assert g.cofactor(-e, {'x': 0}) == 1 assert g.cofactor(-e, {'x': 1}) == -y assert g.cofactor(-e, {'y': 0}) == 1 assert g.cofactor(-e, {'y': 1}) == -x
def test_cofactor(): ordering = {'x': 0, 'y': 1, 'z': 2} g = BDD(ordering) # u not in g with nt.assert_raises(AssertionError): g.let({'x': False, 'y': True, 'z': False}, 5) # x & y e = g.add_expr('x && y') x = g.add_expr('x') assert g.let({'x': False}, x) == -1 assert g.let({'x': True}, x) == 1 assert g.let({'x': False}, -x) == 1 assert g.let({'x': True}, -x) == -1 y = g.add_expr('y') assert g.let({'x': True}, e) == y assert g.let({'x': False}, e) == -1 assert g.let({'y': True}, e) == x assert g.let({'y': False}, e) == -1 assert g.let({'x': False}, -e) == 1 assert g.let({'x': True}, -e) == -y assert g.let({'y': False}, -e) == 1 assert g.let({'y': True}, -e) == -x
def test_bdd_to_mdd(): from dd.bdd import BDD ordering = {'x': 0, 'y': 1} bdd = BDD(ordering) u = bdd.add_expr('x & ! y') bdd.incref(u) # BDD -> MDD dvars = dict(x=dict(level=1, len=2, bitnames=['x']), y=dict(level=0, len=2, bitnames=['y'])) mdd, umap = dd.mdd.bdd_to_mdd(bdd, dvars) pd = dd.mdd.to_pydot(mdd) pd.write_pdf('mdd.pdf') bdd.dump('bdd.pdf') v = umap[abs(u)] if u < 0: v = -v print(v)
def test_bdd_to_mdd(): from dd.bdd import BDD ordering = {'x': 0, 'y': 1} bdd = BDD(ordering) u = bdd.add_expr('x & ! y') bdd.incref(u) # BDD -> MDD dvars = dict( x=dict(level=1, len=2, bitnames=['x']), y=dict(level=0, len=2, bitnames=['y'])) mdd, umap = dd.mdd.bdd_to_mdd(bdd, dvars) # pd = dd.mdd.to_pydot(mdd) # pd.write_pdf('mdd.pdf') # bdd.dump('bdd.pdf') v = umap[abs(u)] if u < 0: v = -v print(v)
def test_pick_iter(): # x & y g = x_and_y() u = 4 bits = {'x', 'y'} s = [{'x': 1, 'y': 1}] compare_iter_to_list_of_sets(u, g, s, bits) # care_bits == support (default) bits = None compare_iter_to_list_of_sets(u, g, s, bits) # # x | y g = x_or_y() u = 4 # support bits = None s = [{'x': 1, 'y': 0}, {'x': 1, 'y': 1}, {'x': 0, 'y': 1}] compare_iter_to_list_of_sets(u, g, s, bits) # only what appears along traversal bits = set() s = [{'x': 1}, {'x': 0, 'y': 1}] compare_iter_to_list_of_sets(u, g, s, bits) # bits < support bits = {'x'} s = [{'x': 1}, {'x': 0, 'y': 1}] compare_iter_to_list_of_sets(u, g, s, bits) bits = {'y'} s = [{'x': 1, 'y': 0}, {'x': 1, 'y': 1}, {'x': 0, 'y': 1}] compare_iter_to_list_of_sets(u, g, s, bits) # # x & !y g = x_and_not_y() u = -2 bits = {'x', 'y'} s = [{'x': 1, 'y': 0}] compare_iter_to_list_of_sets(u, g, s, bits) # gaps in order order = {'x': 0, 'y': 1, 'z': 2} bdd = BDD(order) u = bdd.add_expr('x & z') (m, ) = bdd.pick_iter(u) assert m == {'x': 1, 'z': 1}, m
def test_sat_iter(): # x & y g = x_and_y() u = 2 s = [{'x': 1, 'y': 1}] compare_iter_to_list_of_sets(u, g, s) # x | y g = x_or_y() u = 2 s = [{'x': 1}, {'x': 0, 'y': 1}] compare_iter_to_list_of_sets(u, g, s) # x & !y g = x_and_not_y() u = -2 s = [{'x': 1, 'y': 0}] compare_iter_to_list_of_sets(u, g, s) # gaps in order order = {'x': 0, 'y': 1, 'z': 2} bdd = BDD(order) u = bdd.add_expr('x & z') (m, ) = bdd.sat_iter(u) assert m == {'x': 1, 'z': 1}, m
def test_sat_iter(): # x & y g = x_and_y() u = 2 s = [{'x': 1, 'y': 1}] compare_iter_to_list_of_sets(u, g, s) # x | y g = x_or_y() u = 2 s = [{'x': 1}, {'x': 0, 'y': 1}] compare_iter_to_list_of_sets(u, g, s) # x & !y g = x_and_not_y() u = -2 s = [{'x': 1, 'y': 0}] compare_iter_to_list_of_sets(u, g, s) # gaps in order order = {'x': 0, 'y': 1, 'z': 2} bdd = BDD(order) u = bdd.add_expr('x & z') (m,) = bdd.sat_iter(u) assert m == {'x': 1, 'z': 1}, m
def test_quantifier_syntax(): b = BDD() [b.add_var(var) for var in ['x', 'y']] # constants u = b.add_expr('\E x: True') assert u == b.true, u u = b.add_expr('\E x, y: True') assert u == b.true, u u = b.add_expr('\E x: False') assert u == b.false, u u = b.add_expr('\A x: True') assert u == b.true, u u = b.add_expr('\A x: False') assert u == b.false, u u = b.add_expr('\A x, y: False') assert u == b.false, u # variables u = b.add_expr('\E x: x') assert u == b.true, u u = b.add_expr('\A x: x') assert u == b.false, u u = b.add_expr('\E x, y: x') assert u == b.true, u u = b.add_expr('\E x, y: y') assert u == b.true, u u = b.add_expr('\A x: y') assert u == b.var('y'), u u = b.add_expr('\A x: ! y') u_ = b.apply('not', b.var('y')) assert u == u_, (u, u_)
def test_swap(): # x, y g = BDD({'x': 0, 'y': 1}) x = g.add_expr('x') y = g.add_expr('y') g.incref(x) g.incref(y) n = len(g) assert n == 3, n nold, n = g.swap('x', 'y') assert n == 3, n assert nold == n, nold assert g.ordering == {'y': 0, 'x': 1}, g.ordering assert g.assert_consistent() # functions remain invariant x_ = g.add_expr('x') y_ = g.add_expr('y') assert x == x_, (x, x_, g._succ) assert y == y_, (y, y_, g._succ) # external reference counts remain unchanged assert g._ref[abs(x)] == 1 assert g._ref[abs(y)] == 1 # x & y g = BDD({'x': 0, 'y': 1}) u = g.add_expr('x & y') g.incref(u) nold, n = g.swap('x', 'y') assert nold == n, (nold, n) assert g.ordering == {'y': 0, 'x': 1}, g.ordering u_ = g.add_expr('x & y') assert u == u_, (u, u_) assert g.assert_consistent() # reference counts unchanged assert g._ref[abs(u)] == 1 # x & !y # tests handling of complement edges e = 'x & !y' g = x_and_not_y() u = g.add_expr(e) g.incref(u) g.collect_garbage() n = len(g) assert n == 3, n nold, n = g.swap('x', 'y') assert n == 3, n assert nold == n, nold assert g.ordering == {'x': 1, 'y': 0} assert g.assert_consistent() u_ = g.add_expr(e) # function u must have remained unaffected assert u_ == u, (u, u_, g._succ) # invert swap of: # x & !y nold, n = g.swap('x', 'y') assert n == 3, n assert nold == n, nold assert g.ordering == {'x': 0, 'y': 1} assert g.assert_consistent() u_ = g.add_expr(e) assert u_ == u, (u, u_, g._succ) # Figs. 6.24, 6.25 Baier 2008 g = BDD({'z1': 0, 'y1': 1, 'z2': 2, 'y2': 3, 'z3': 4, 'y3': 5}) u = g.add_expr('(z1 & y1) | (z2 & y2) | (z3 & y3)') g.incref(u) n = len(g) assert n == 16, n g.collect_garbage() n = len(g) assert n == 7, n # sift to inefficient order g.swap('y1', 'z2') # z1, z2, y1, y2, z3, y3 g.swap('y2', 'z3') # z1, z2, y1, z3, y2, y3 g.swap('y1', 'z3') # z1, z2, z3, y1, y2, y3 n = len(g) assert n == 15, n assert g.assert_consistent() new_ordering = {'z1': 0, 'z2': 1, 'z3': 2, 'y1': 3, 'y2': 4, 'y3': 5} assert g.ordering == new_ordering, g.ordering u_ = g.add_expr('(z1 & y1) | (z2 & y2) | (z3 & y3)') assert u_ == u, (u, u_, g._succ)
def test_rename_syntax(): b = BDD() [b.add_var(var) for var in ['x', 'y', 'z', 'w']] # single substitution u = b.add_expr('\S y / x: True') assert u == b.true, u u = b.add_expr('\S y / x: False') assert u == b.false, u u = b.add_expr('\S y / x: x') u_ = b.add_expr('y') assert u == u_, (u, u_) u = b.add_expr('\S y / x: z') u_ = b.add_expr('z') assert u == u_, (u, u_) u = b.add_expr('\S y / x: x & z') u_ = b.add_expr('y & z') assert u == u_, (u, u_) # multiple substitution u = b.add_expr('\S y / x, w / z: x & z') u_ = b.add_expr('y & w') assert u == u_, (u, u_) u = b.add_expr('\S y / x, w / z: z | ! x') u_ = b.add_expr('w | ! y') assert u == u_, (u, u_)
def test_swap(): # x, y g = BDD({'x': 0, 'y': 1}) x = g.add_expr('x') y = g.add_expr('y') g.incref(x) g.incref(y) n = len(g) assert n == 3, n nold, n = g.swap('x', 'y') assert n == 3, n assert nold == n, nold assert g.ordering == {'y': 0, 'x': 1}, g.ordering assert g.assert_consistent() # functions remain invariant x_ = g.add_expr('x') y_ = g.add_expr('y') assert x == x_, (x, x_, g._succ) assert y == y_, (y, y_, g._succ) # external reference counts remain unchanged assert g._ref[abs(x)] == 1 assert g._ref[abs(y)] == 1 # x & y g = BDD({'x': 0, 'y': 1}) u = g.add_expr('x & y') g.incref(u) nold, n = g.swap('x', 'y') assert nold == n, (nold, n) assert g.ordering == {'y': 0, 'x': 1}, g.ordering u_ = g.add_expr('x & y') assert u == u_, (u, u_) assert g.assert_consistent() # reference counts unchanged assert g._ref[abs(u)] == 1 # x & !y # tests handling of complement edges e = 'x & !y' g = x_and_not_y() u = g.add_expr(e) g.incref(u) g.collect_garbage() n = len(g) assert n == 3, n nold, n = g.swap('x', 'y') assert n == 3, n assert nold == n, nold assert g.ordering == {'x': 1, 'y': 0} assert g.assert_consistent() u_ = g.add_expr(e) # function u must have remained unaffected assert u_ == u, (u, u_, g._succ) # invert swap of: # x & !y nold, n = g.swap('x', 'y') assert n == 3, n assert nold == n, nold assert g.ordering == {'x': 0, 'y': 1} assert g.assert_consistent() u_ = g.add_expr(e) assert u_ == u, (u, u_, g._succ) # Figs. 6.24, 6.25 Baier 2008 g = BDD({'z1': 0, 'y1': 1, 'z2': 2, 'y2': 3, 'z3': 4, 'y3': 5}) u = g.add_expr('(z1 & y1) | (z2 & y2) | (z3 & y3)') g.incref(u) n = len(g) assert n == 16, n g.collect_garbage() n = len(g) assert n == 7, n # sift to inefficient order g.swap('y1', 'z2') # z1, z2, y1, y2, z3, y3 g.swap('y2', 'z3') # z1, z2, y1, z3, y2, y3 g.swap('y1', 'z3') # z1, z2, z3, y1, y2, y3 n = len(g) assert n == 15, n assert g.assert_consistent() new_ordering = { 'z1': 0, 'z2': 1, 'z3': 2, 'y1': 3, 'y2': 4, 'y3': 5} assert g.ordering == new_ordering, g.ordering u_ = g.add_expr('(z1 & y1) | (z2 & y2) | (z3 & y3)') assert u_ == u, (u, u_, g._succ)
def test_preimage(): # exists: x, y # forall: z ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} rename = {0: 1, 2: 3, 4: 5} g = BDD(ordering) f = g.add_expr('!x') t = g.add_expr('x <-> !xp') qvars = {1, 3} p = preimage(t, f, rename, qvars, g) x = g.add_expr('x') assert x == p, (x, p) # a cycle # (x & y) -> (!x & y) -> # (!x & !y) -> (x & !y) -> wrap around t = g.add_expr( '((x & y) -> (!xp & yp)) && ' '((!x & y) -> (!xp & !yp)) && ' '((!x & !y) -> (xp & !yp)) && ' '((x & !y) -> (xp & yp))') f = g.add_expr('x && y') p = preimage(t, f, rename, qvars, g) assert p == g.add_expr('x & !y') f = g.add_expr('x && !y') p = preimage(t, f, rename, qvars, g) assert p == g.add_expr('!x & !y') # backward reachable set f = g.add_expr('x & y') oldf = None while oldf != f: p = preimage(t, f, rename, qvars, g) oldf = f f = g.apply('or', p, oldf) assert f == 1 # go around once f = g.add_expr('x & y') start = f for i in range(4): f = preimage(t, f, rename, qvars, g) end = f assert start == end # forall z exists x, y t = g.add_expr( '(' ' ((x & y) -> (zp & xp & !yp)) | ' ' ((x & y) -> (!zp & !xp & yp))' ') & ' '(!(x & y) -> False)') f = g.add_expr('x && !y') ep = preimage(t, f, rename, qvars, g) p = g.quantify(ep, {'zp'}, forall=True) assert p == -1 f = g.add_expr('(x & !y) | (!x & y)') ep = preimage(t, f, rename, qvars, g) p = g.quantify(ep, {'zp'}, forall=True) assert p == g.add_expr('x & y')
def test_preimage(): # exists: x, y # forall: z ordering = {'x': 0, 'xp': 1, 'y': 2, 'yp': 3, 'z': 4, 'zp': 5} rename = {0: 1, 2: 3, 4: 5} g = BDD(ordering) f = g.add_expr('!x') t = g.add_expr('x <-> !xp') qvars = {1, 3} p = preimage(t, f, rename, qvars, g) x = g.add_expr('x') assert x == p, (x, p) # a cycle # (x & y) -> (!x & y) -> # (!x & !y) -> (x & !y) -> wrap around t = g.add_expr('((x & y) -> (!xp & yp)) && ' '((!x & y) -> (!xp & !yp)) && ' '((!x & !y) -> (xp & !yp)) && ' '((x & !y) -> (xp & yp))') f = g.add_expr('x && y') p = preimage(t, f, rename, qvars, g) assert p == g.add_expr('x & !y') f = g.add_expr('x && !y') p = preimage(t, f, rename, qvars, g) assert p == g.add_expr('!x & !y') # backward reachable set f = g.add_expr('x & y') oldf = None while oldf != f: p = preimage(t, f, rename, qvars, g) oldf = f f = g.apply('or', p, oldf) assert f == 1 # go around once f = g.add_expr('x & y') start = f for i in xrange(4): f = preimage(t, f, rename, qvars, g) end = f assert start == end # forall z exists x, y t = g.add_expr('(' ' ((x & y) -> (zp & xp & !yp)) | ' ' ((x & y) -> (!zp & !xp & yp))' ') & ' '(!(x & y) -> False)') f = g.add_expr('x && !y') ep = preimage(t, f, rename, qvars, g) p = g.quantify(ep, {'zp'}, forall=True) assert p == -1 f = g.add_expr('(x & !y) | (!x & y)') ep = preimage(t, f, rename, qvars, g) p = g.quantify(ep, {'zp'}, forall=True) assert p == g.add_expr('x & y')