def compare(u, bdd, h): g = _bdd.to_nx(bdd, [u]) # nx.drawing.nx_pydot.to_pydot(g).write_pdf('g.pdf') post = nx.descendants(g, u) post.add(u) r = g.subgraph(post) # nx.drawing.nx_pydot.to_pydot(r).write_pdf('r.pdf') # nx.drawing.nx_pydot.to_pydot(h).write_pdf('h.pdf') gm = iso.GraphMatcher(r, h, node_match=_nm, edge_match=_em) assert gm.is_isomorphic() d = gm.mapping assert d[1] == 1
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