Example #1
0
File: mdd.py Project: sysong13/dd
 def to_expr(self, u):
     if u == 1:
         return u
     elif u == -1:
         return 0
     t = self._succ[abs(u)]
     i = t[0]
     nodes = t[1:]
     var = self.var_at_level(i)
     # group per target node
     c = tuple(set(nodes))
     e = {x: self.to_expr(x) for x in c}
     cond = {v: set() for v in c}
     for j, x in enumerate(nodes):
         cond[x].add(j)
     # format
     cond_str = dict()
     for k, v in items(cond):
         if len(v) == 1:
             (j, ) = v
             cond_str[k] = '= {j}'.format(j=j)
         else:
             cond_str[k] = 'in {v}'.format(v=v)
     x = c[0]
     s = 'if ({var} {j}): {p}, '.format(var=var, j=cond_str[x], p=e[x])
     s += ', '.join(
         '\nelif ({var} {j}): {p}'.format(var=var, j=cond_str[x], p=e[x])
         for x in c[1:])
     if u < 0:
         s = '! {s}'.format(s=s)
     s = '({s})'.format(s=s)
     return s
Example #2
0
File: mdd.py Project: lummax/dd
 def to_expr(self, u):
     if u == 1:
         return u
     elif u == -1:
         return 0
     t = self._succ[abs(u)]
     i = t[0]
     nodes = t[1:]
     var = self.var_at_level(i)
     # group per target node
     c = tuple(set(nodes))
     e = {x: self.to_expr(x) for x in c}
     cond = {v: set() for v in c}
     for j, x in enumerate(nodes):
         cond[x].add(j)
     # format
     cond_str = dict()
     for k, v in items(cond):
         if len(v) == 1:
             (j,) = v
             cond_str[k] = '= {j}'.format(j=j)
         else:
             cond_str[k] = 'in {v}'.format(v=v)
     x = c[0]
     s = 'if ({var} {j}): {p}, '.format(
         var=var, j=cond_str[x], p=e[x])
     s += ', '.join(
         '\nelif ({var} {j}): {p}'.format(
             var=var, j=cond_str[x], p=e[x])
         for x in c[1:])
     if u < 0:
         s = '! {s}'.format(s=s)
     s = '({s})'.format(s=s)
     return s
Example #3
0
File: mdd.py Project: lummax/dd
 def var_at_level(self, i):
     """Return variable with level `i`."""
     if self._level_to_var is None:
         self._level_to_var = {
             d['level']: var
             for var, d in items(self.vars)}
     return self._level_to_var[i]
Example #4
0
File: mdd.py Project: sysong13/dd
 def var_at_level(self, i):
     """Return variable with level `i`."""
     if self._level_to_var is None:
         self._level_to_var = {
             d['level']: var
             for var, d in items(self.vars)
         }
     return self._level_to_var[i]
Example #5
0
File: mdd.py Project: lummax/dd
def to_pydot(mdd):
    import pydot
    g = pydot.Dot('mdd', graph_type='digraph')
    skeleton = list()
    subgraphs = dict()
    n = len(mdd.vars) + 1
    for i in xrange(n):
        h = pydot.Subgraph('', rank='same')
        g.add_subgraph(h)
        subgraphs[i] = h
        # add phantom node
        u = '-{i}'.format(i=i)
        skeleton.append(u)
        nd = pydot.Node(name=u, label=str(i), shape='none')
        h.add_node(nd)
    # auxiliary edges for ranking
    for i, u in enumerate(skeleton[:-1]):
        v = skeleton[i + 1]
        e = pydot.Edge(str(u), str(v), style='invis')
        g.add_edge(e)
    # add nodes
    for u, t in items(mdd._succ):
        assert u > 0, u
        i = t[0]
        nodes = t[1:]
        # terminal ?
        if nodes[0] is None:
            var = '1'
        else:
            var = mdd.var_at_level(i)
        # add node
        label = '{var}-{u}'.format(var=var, u=u)
        nd = pydot.Node(name=str(u), label=label)
        h = subgraphs[i]  # level i
        h.add_node(nd)
        # add edges
        if nodes[0] is None:
            continue
        # has successors
        for j, v in enumerate(nodes):
            label = str(j)
            # tail_label = '-1' if v < 0 else ' '
            if v < 0:
                style = 'dashed'
            else:
                style = 'solid'
            su = str(u)
            sv = str(abs(v))
            e = pydot.Edge(su, sv, label=label,
                           style=style)
            g.add_edge(e)
    return g
Example #6
0
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, levels, roots = parser.parse(fname)
    # reindex to ensure no blanks
    perm = {k: var for var, k in items(levels)}
    perm = {i: perm[k] for i, k in enumerate(sorted(perm))}
    new_levels = {var: k for k, var in items(perm)}
    old2new = {levels[var]: new_levels[var] for var in levels}
    # convert
    bdd = BDD(new_levels)
    umap = {-1: -1, 1: 1}
    for j in range(len(new_levels) - 1, -1, -1):
        for u, (k, v, w) in items(bdd_succ):
            # 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
Example #7
0
File: dddmp.py Project: roon63/dd
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 items(ordering)}
    perm = {i: perm[k] for i, k in enumerate(sorted(perm))}
    new_ordering = {var: k for k, var in items(perm)}
    old2new = {ordering[var]: new_ordering[var] for var in ordering}
    # convert
    bdd = BDD(new_ordering)
    umap = {-1: -1, 1: 1}
    for j in range(len(new_ordering) - 1, -1, -1):
        for u, (k, v, w) in items(bdd_succ):
            # 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
Example #8
0
File: mdd.py Project: sysong13/dd
def to_pydot(mdd):
    g = pydot.Dot('mdd', graph_type='digraph')
    skeleton = list()
    subgraphs = dict()
    n = len(mdd.vars) + 1
    for i in xrange(n):
        h = pydot.Subgraph('', rank='same')
        g.add_subgraph(h)
        subgraphs[i] = h
        # add phantom node
        u = '-{i}'.format(i=i)
        skeleton.append(u)
        nd = pydot.Node(name=u, label=str(i), shape='none')
        h.add_node(nd)
    # auxiliary edges for ranking
    for i, u in enumerate(skeleton[:-1]):
        v = skeleton[i + 1]
        e = pydot.Edge(str(u), str(v), style='invis')
        g.add_edge(e)
    # add nodes
    for u, t in items(mdd._succ):
        assert u > 0, u
        i = t[0]
        nodes = t[1:]
        # terminal ?
        if nodes[0] is None:
            var = '1'
        else:
            var = mdd.var_at_level(i)
        # add node
        label = '{var}-{u}'.format(var=var, u=u)
        nd = pydot.Node(name=str(u), label=label)
        h = subgraphs[i]  # level i
        h.add_node(nd)
        # add edges
        if nodes[0] is None:
            continue
        # has successors
        for j, v in enumerate(nodes):
            label = str(j)
            # tail_label = '-1' if v < 0 else ' '
            if v < 0:
                style = 'dashed'
            else:
                style = 'solid'
            su = str(u)
            sv = str(abs(v))
            e = pydot.Edge(su, sv, label=label, style=style)
            g.add_edge(e)
    return g
Example #9
0
class Lexer(object):
    """Token rules to build LTL lexer."""

    reserved = {
        'ver': 'VERSION',
        'add': 'ADD',
        'mode': 'FILEMODE',
        'varinfo': 'VARINFO',
        'dd': 'DD',
        'nnodes': 'NNODES',
        'nvars': 'NVARS',
        'orderedvarnames': 'ORDEREDVARNAMES',
        'nsuppvars': 'NSUPPVARS',
        'suppvarnames': 'SUPPVARNAMES',
        'ids': 'IDS',
        'permids': 'PERMIDS',
        'auxids': 'AUXIDS',
        'nroots': 'NROOTS',
        'rootids': 'ROOTIDS',
        'rootnames': 'ROOTNAMES',
        # 'nodes': 'NODES',
        # 'end': 'END'
    }
    reserved = {'.{k}'.format(k=k): v for k, v in items(reserved)}
    misc = ['MINUS', 'DOT', 'NAME', 'NUMBER']
    # token rules
    t_MINUS = r'-'
    t_DOT = r'\.'
    t_NUMBER = r'\d+'
    t_ignore = ' \t'

    def __init__(self, debug=False):
        self.tokens = self.misc + list(self.reserved.values())
        self.build(debug=debug)

    def t_KEYWORD(self, t):
        r"\.[a-zA-Z][a-zA-Z]*"
        t.type = self.reserved.get(t.value, 'NAME')
        return t

    def t_NAME(self, t):
        r"[a-zA-Z_][a-zA-Z_@0-9\'\.]*"
        t.type = self.reserved.get(t.value, 'NAME')
        return t

    def t_comment(self, t):
        r'\#.*'
        return

    def t_newline(self, t):
        r'\n+'
        t.lexer.lineno += t.value.count("\n")

    def t_error(self, t):
        raise Exception('Illegal character "{t}"'.format(t=t.value[0]))

    def build(self, debug=False, debuglog=None, **kwargs):
        """Create a lexer.

        @param kwargs: Same arguments as C{{ply.lex.lex}}:

          - except for C{{module}} (fixed to C{{self}})
          - C{{debuglog}} defaults to the logger C{{"{logger}"}}.
        """
        if debug and debuglog is None:
            debuglog = logging.getLogger(LEX_LOG)
        self.lexer = ply.lex.lex(module=self,
                                 debug=debug,
                                 debuglog=debuglog,
                                 **kwargs)
Example #10
0
File: mdd.py Project: sysong13/dd
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 items(dvars):
        bits = d['bitnames']
        b = {bit: var for bit in bits}
        bit_to_var.update(b)
    # find target bit order
    order = list()  # target
    levels = {d['level']: var for var, d in items(dvars)}
    m = len(levels)
    for j in xrange(m):
        var = levels[j]
        bits = dvars[var]['bitnames']
        order.extend(bits)
    bit_to_sort = {bit: k for k, bit in enumerate(order)}
    # 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 items(dvars):
        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 items(bdd._succ):
        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 items(pred):
        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 items(pred) 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)
    # 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
Example #11
0
File: mdd.py Project: lummax/dd
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 items(dvars):
        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 items(dvars)}
    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 items(dvars):
        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 items(bdd._succ):
        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 items(pred):
        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 items(pred) 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)
    # 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