def test_top_cofactor(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) x = ordering['x'] y = ordering['y'] u = g.find_or_add(y, -1, 1) assert g._top_cofactor(u, x) == (u, u) assert g._top_cofactor(u, y) == (-1, 1) u = g.find_or_add(x, -1, 1) assert g._top_cofactor(u, x) == (-1, 1) assert g._top_cofactor(-u, x) == (1, -1)
def test_top_cofactor(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) x = ordering['x'] y = ordering['y'] u = g.find_or_add(y, -1, 1) assert g._top_cofactor(u, x) == (u, u) assert g._top_cofactor(u, y) == (-1, 1) u = g.find_or_add(x, -1, 1) assert g._top_cofactor(u, x) == (-1, 1) assert g._top_cofactor(-u, x) == (1, -1)
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_ite(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) # x ix = ordering['x'] x = g.find_or_add(ix, -1, 1) h = ref_var(ix) compare(x, g, h) # y iy = ordering['y'] y = g.find_or_add(iy, -1, 1) h = ref_var(iy) compare(y, g, h) # x and y u = g.ite(x, y, -1) h = ref_x_and_y() compare(u, g, h) # x or y u = g.ite(x, 1, y) h = ref_x_or_y() compare(u, g, h) # negation assert g.ite(x, -1, 1) == -x, g._succ assert g.ite(-x, -1, 1) == x, g._succ
def test_ite(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) # x ix = ordering['x'] x = g.find_or_add(ix, -1, 1) h = ref_var(ix) compare(x, g, h) # y iy = ordering['y'] y = g.find_or_add(iy, -1, 1) h = ref_var(iy) compare(y, g, h) # x and y u = g.ite(x, y, -1) h = ref_x_and_y() compare(u, g, h) # x or y u = g.ite(x, 1, y) h = ref_x_or_y() compare(u, g, h) # negation assert g.ite(x, -1, 1) == -x, g._succ assert g.ite(-x, -1, 1) == x, g._succ
def load(fname): """Return a `BDD` loaded from DDDMP file `fname`. If no `.orderedvarnames` appear in the file, then `.suppvarnames` and `.permids` are used instead. In the second case, the variable levels contains blanks. To avoid blanks, the levels are re-indexed here. This has no effect if `.orderedvarnames` appears in the file. DDDMP files are dumped by [CUDD](http://vlsi.colorado.edu/~fabio/CUDD/). """ parser = Parser() bdd_succ, n_vars, ordering, roots = parser.parse(fname) # reindex to ensure no blanks perm = {k: var for var, k in ordering.iteritems()} perm = {i: perm[k] for i, k in enumerate(sorted(perm))} new_ordering = {var: k for k, var in perm.iteritems()} old2new = {ordering[var]: new_ordering[var] for var in ordering} # convert bdd = BDD(new_ordering) umap = {-1: -1, 1: 1} for j in xrange(len(new_ordering) - 1, -1, -1): for u, (k, v, w) in bdd_succ.iteritems(): # terminal ? if v is None: assert w is None, w continue # non-terminal i = old2new[k] if i != j: continue p, q = umap[abs(v)], umap[w] if v < 0: p = -p r = bdd.find_or_add(i, p, q) umap[abs(u)] = r bdd.roots.update(roots) return bdd
def load(fname): """Return a `BDD` loaded from DDDMP file `fname`. If no `.orderedvarnames` appear in the file, then `.suppvarnames` and `.permids` are used instead. In the second case, the variable levels contains blanks. To avoid blanks, the levels are re-indexed here. This has no effect if `.orderedvarnames` appears in the file. DDDMP files are dumped by [CUDD](http://vlsi.colorado.edu/~fabio/CUDD/). """ parser = Parser() bdd_succ, n_vars, ordering, roots = parser.parse(fname) # reindex to ensure no blanks perm = {k: var for var, k in ordering.iteritems()} perm = {i: perm[k] for i, k in enumerate(sorted(perm))} new_ordering = {var: k for k, var in perm.iteritems()} old2new = {ordering[var]: new_ordering[var] for var in ordering} # convert bdd = BDD(new_ordering) umap = {-1: -1, 1: 1} for j in xrange(len(new_ordering) - 1, -1, -1): for u, (k, v, w) in bdd_succ.iteritems(): # terminal ? if v is None: assert w is None, w continue # non-terminal i = old2new[k] if i != j: continue p, q = umap[abs(v)], umap[w] if v < 0: p = -p r = bdd.find_or_add(i, p, q) umap[abs(u)] = r bdd.roots.update(roots) return bdd
def test_find_or_add(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) # init n = len(g) m = g._min_free assert n == 1, n assert m == 2, m # elimination rule i = 0 v = -1 w = 1 n = len(g) u = g.find_or_add(i, v, v) n_ = len(g) assert n == n_, (n, n_) assert u == v, (u, v) assert not g._pred, g._pred # unchanged min_free v = 1 m = g._min_free g.find_or_add(i, v, v) m_ = g._min_free assert m_ == m, (m_, m) # add new node g = BDD(ordering) v = -1 w = 1 n = len(g) m = g._min_free assert n == 1, n u = g.find_or_add(i, v, w) n_ = len(g) m_ = g._min_free assert u != v, (u, v) assert n_ == n + 1, (n, n_) assert m_ == m + 1, (m, m_) assert g._succ[u] == (i, -1, 1) assert (i, v, w) in g._pred assert abs(u) in g._ref assert g._ref[abs(u)] == 0 assert g._ref[abs(v)] == 2, g._ref # independent increase of reference counters v = u w = w refv = g._ref[abs(v)] refw = g._ref[w] u = g.find_or_add(i, v, w) refv_ = g._ref[abs(v)] refw_ = g._ref[w] assert refv + 1 == refv_, (refv, refv_) assert refw + 1 == refw_, (refw, refw_) # add existing n = len(g) m = g._min_free refv = g._ref[abs(v)] refw = g._ref[w] r = g.find_or_add(i, v, w) n_ = len(g) m_ = g._min_free refv_ = g._ref[abs(v)] refw_ = g._ref[w] assert n == n_, (n, n_) assert m == m_, (m, m_) assert u == r, u assert refv == refv_, (refv, refv_) assert refw == refw_, (refw, refw_) # only non-terminals can be added with nt.assert_raises(AssertionError): g.find_or_add(2, -1, 1) # low and high must already exist with nt.assert_raises(AssertionError): g.find_or_add(0, 3, 4) # canonicity of complemented edges # v < 0, w > 0 g = BDD(ordering) i = 0 v = -1 w = 1 u = g.find_or_add(i, v, w) assert u > 0, u # v > 0, w < 0 v = 1 w = -1 u = g.find_or_add(i, v, w) assert u < 0, u assert abs(u) in g._succ, u _, v, w = g._succ[abs(u)] assert v < 0, v assert w > 0, w # v < 0, w < 0 v = -1 w = -2 u = g.find_or_add(i, v, w) assert u < 0, u _, v, w = g._succ[abs(u)] assert v > 0, v assert w > 0, w
def test_find_or_add(): ordering = {'x': 0, 'y': 1} g = BDD(ordering) # init n = len(g) m = g._min_free assert n == 1, n assert m == 2, m # elimination rule i = 0 v = -1 w = 1 n = len(g) u = g.find_or_add(i, v, v) n_ = len(g) assert n == n_, (n, n_) assert u == v, (u, v) assert not g._pred, g._pred # unchanged min_free v = 1 m = g._min_free g.find_or_add(i, v, v) m_ = g._min_free assert m_ == m, (m_, m) # add new node g = BDD(ordering) v = -1 w = 1 n = len(g) m = g._min_free assert n == 1, n u = g.find_or_add(i, v, w) n_ = len(g) m_ = g._min_free assert u != v, (u, v) assert n_ == n + 1, (n, n_) assert m_ == m + 1, (m, m_) assert g._succ[u] == (i, -1, 1) assert (i, v, w) in g._pred assert abs(u) in g._ref assert g._ref[abs(u)] == 0 assert g._ref[abs(v)] == 2, g._ref # independent increase of reference counters v = u w = w refv = g._ref[abs(v)] refw = g._ref[w] u = g.find_or_add(i, v, w) refv_ = g._ref[abs(v)] refw_ = g._ref[w] assert refv + 1 == refv_, (refv, refv_) assert refw + 1 == refw_, (refw, refw_) # add existing n = len(g) m = g._min_free refv = g._ref[abs(v)] refw = g._ref[w] r = g.find_or_add(i, v, w) n_ = len(g) m_ = g._min_free refv_ = g._ref[abs(v)] refw_ = g._ref[w] assert n == n_, (n, n_) assert m == m_, (m, m_) assert u == r, u assert refv == refv_, (refv, refv_) assert refw == refw_, (refw, refw_) # only non-terminals can be added with nt.assert_raises(AssertionError): g.find_or_add(2, -1, 1) # low and high must already exist with nt.assert_raises(AssertionError): g.find_or_add(0, 3, 4) # canonicity of complemented edges # v < 0, w > 0 g = BDD(ordering) i = 0 v = -1 w = 1 u = g.find_or_add(i, v, w) assert u > 0, u # v > 0, w < 0 v = 1 w = -1 u = g.find_or_add(i, v, w) assert u < 0, u assert abs(u) in g._succ, u _, v, w = g._succ[abs(u)] assert v < 0, v assert w > 0, w # v < 0, w < 0 v = -1 w = -2 u = g.find_or_add(i, v, w) assert u < 0, u _, v, w = g._succ[abs(u)] assert v > 0, v assert w > 0, w