def test_function_properties(): bdd = _bdd.BDD() bdd.declare('x', 'y') order = dict(x=0, y=1) bdd.reorder(order) u = bdd.add_expr('x \/ y') y = bdd.add_expr('y') # Assigned first because in presence of a bug # different property calls could yield # different values. level = u.level assert level == 0, level var = u.var assert var == 'x', var low = u.low assert low == y, low high = u.high assert high == bdd.true, high ref = u.ref assert ref == 1, ref assert not u.negated support = u.support assert support == {'x', 'y'}, support # terminal u = bdd.false assert u.var is None, u.var assert u.low is None, u.low assert u.high is None, u.high
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_reorder_2(): bdd = _bdd.BDD() vrs = [ 'x', 'y', 'z', 'a', 'b', 'c', 'e', 'z1', 'z2', 'z3', 'y1', 'y2', 'y3' ] bdd = _bdd.BDD() bdd.declare(*vrs) expr_1 = '(~ z \/ (c /\ b)) /\ e /\ (a /\ (~ x \/ y))' # Figs. 6.24, 6.25 Baier 2008 expr_2 = '(z1 /\ y1) \/ (z2 /\ y2) \/ (z3 /\ y3)' u = bdd.add_expr(expr_1) v = bdd.add_expr(expr_2) bdd.collect_garbage() n = len(bdd) assert n == 23, n bdd.reorder() n_ = len(bdd) assert n > n_, (n, n_) bdd.assert_consistent()
def test_reorder(): bdd = _bdd.BDD() bdd.declare('x', 'y', 'z') u = bdd.add_expr('(x /\ y) \/ z') bdd.reorder() assert u in bdd
def reorder(bdd, order=None): """Apply Rudell's sifting algorithm to `bdd`.""" _bdd.reorder(bdd._bdd, order=order)
def bdd_to_mdd(bdd, dvars): """Return MDD for given BDD. Caution: collects garbage. `dvars` must map each MDD variable to the corresponding bits in BDD. Also, it should give the order as "level" keys. """ # i = level in BDD # j = level in MDD # bit = BDD variable # var = MDD variable # # map from bits to integers bit_to_var = dict() for var, d in dvars.iteritems(): bits = d['bitnames'] b = {bit: var for bit in bits} bit_to_var.update(b) # find target bit ordering ordering = list() # target levels = {d['level']: var for var, d in dvars.iteritems()} m = len(levels) for j in xrange(m): var = levels[j] bits = dvars[var]['bitnames'] ordering.extend(bits) bit_to_sort = {bit: k for k, bit in enumerate(ordering)} # reorder bdd.collect_garbage() _bdd.reorder(bdd, order=bit_to_sort) # BDD -> MDD mdd = MDD(dvars) # zones of bits per integer var zones = dict() for var, d in dvars.iteritems(): bits = d['bitnames'] lsb = bits[0] msb = bits[-1] min_level = bit_to_sort[lsb] max_level = bit_to_sort[msb] zones[var] = (min_level, max_level) # reverse edges pred = {u: set() for u in bdd} for u, (_, v, w) in bdd._succ.iteritems(): assert u > 0, u # terminal ? if u == 1: continue # non-terminal pred[abs(v)].add(u) pred[abs(w)].add(u) # find BDD nodes mentioned from above rm = set() for u, p in pred.iteritems(): rc = bdd.ref(u) k = len(p) # number of predecessors # has external refs ? if rc > k: continue # has refs from outside zone ? i, _, _ = bdd._succ[u] bit = bdd.var_at_level(i) var = bit_to_var[bit] min_level, _ = zones[var] pred_levels = {bdd._succ[v][0] for v in p} min_pred_level = min(pred_levels) if min_pred_level < min_level: continue # referenced only from inside zone rm.add(u) pred = {u: p for u, p in pred.iteritems() if u not in rm} # build layer by layer # TODO: use bins, instad of iterating through all nodes bdd.assert_consistent() g = to_nx(bdd, roots=[u]) for u in pred: g.add_node(u, color='red') for u in g: if u == 1: continue i, _, _ = bdd._succ[u] var = bdd.var_at_level(i) label = '{var}-{u}'.format(var=var, u=u) g.add_node(u, label=label) pd = nx.to_pydot(g) pd.write_pdf('bdd_colored.pdf') bdd.dump('bdd.pdf') umap = dict() umap[1] = 1 for u, i, v, w in bdd.levels(skip_terminals=True): # ignore function ? if u not in pred: continue # keep `u` bit = bdd.var_at_level(i) var = bit_to_var[bit] bits = dvars[var]['bitnames'] bit_succ = list() for d in _enumerate_integer(bits): x = bdd.cofactor(u, d) bit_succ.append(x) # map edges int_succ = [umap[abs(z)] if z > 0 else -umap[abs(z)] for z in bit_succ] # add new MDD node at level j j = dvars[var]['level'] r = mdd.find_or_add(j, *int_succ) # cache # signed r, because low never inverted, # opposite to canonicity chosen for BDDs umap[u] = r return mdd, umap