Esempio n. 1
0
def graph_map(f, graph):
    ''' Maps function f over the nodes in graph.

        >>> sorted( graph_map(str, Graph({1: [2, 3]})).edges() )
        [('1', '2'), ('1', '3')]
        >>> sorted( graph_map(str, DiGraph({1: [2, 3]})).edges() )
        [('1', '2'), ('1', '3')]
    '''
    g = graph
    return g.__class__(map_items(lambda k,v: (f(k), map_keys(f, v)), g.adj))
Esempio n. 2
0
def graph_map(f, graph):
    ''' Maps function f over the nodes in graph.

        >>> sorted( graph_map(str, Graph({1: [2, 3]})).edges() )
        [('1', '2'), ('1', '3')]
        >>> sorted( graph_map(str, DiGraph({1: [2, 3]})).edges() )
        [('1', '2'), ('1', '3')]
    '''
    g = graph
    return g.__class__(map_items(lambda k, v: (f(k), map_keys(f, v)), g.adj))
Esempio n. 3
0
    def transformAssign(self, node):

        # Only transform constant assignments
        if not is_const(node.expr):
            return self._transform_children(node)

        # '__foo' names come from each lhs name at the head of the assignment:
        #   'l = a,b = 0,1' -> 'l = a,b = __a,__b', { '__a':0, '__b':1 }
        #
        # Unpack the rhs enough to map each '__foo' name to a value.
        #   'a,l = 0,[1,2]' -> 'a,l = __a,__l', { '__a':0, '__l':[1,2] }
        #   'a,l = 2'       -> SyntaxError

        def lvalue_name(node):
            'Construct a "magic" name to represent an l-value.'
            prefix = sep = '__'
            dot = '_'
            if isinstance(node, AssName):
                return prefix + node.name
            elif isinstance(node, AssAttr):
                name = node.attrname
                expr = node.expr
                while isinstance(expr, Getattr):
                    name = sep.join([expr.attrname, name])
                    expr = expr.expr
                if isinstance(expr, Name):
                    expr_name = expr.name
                else:
                    expr_name = dot
                return prefix + sep.join([expr_name, name])

        # In these trees, strings and tuples are leaves
        leaves = (str, tuple, AssAttr, AssName)
        tree_zip = partial(tree.tree_zip, leaves=leaves)
        flatten = partial(tree.flatten, leaves=leaves)
        tree_embeds = partial(tree.tree_embeds, leaves=leaves)

        # Grab the (right-most) lhs and the rhs
        lhs, rhs = node.nodes[-1], node.expr

        # Associate constants with l-value names
        if not tree_embeds(lhs, rhs):
            raise SyntaxError('Not enough r-values to unpack: %s' % node)
        zipped = flatten(tree_zip(lhs, rhs))
        const_ast_for = map_keys(lambda v: lvalue_name(v), dict(zipped))

        # Gather name<->const mappings for names we haven't seen before
        name_for = {}
        for name in const_ast_for.keys():
            if name not in self.const_for.keys():
                self.const_for[name] = eval_ast(Expression(const_ast_for[name]))
                assert const_ast_for[name] not in name_for
                name_for[const_ast_for[name]] = name

        class C(Transformer):
            def transform(self, node):
                if isinstance(node, Node) and node in name_for.keys():
                    return Name(name_for[node])
                else:
                    return super(C, self).transform(node)
        return Assign(node.nodes, C().transform(rhs))
Esempio n. 4
0
    def restrict(self, inputs=(), outputs=()):
        ''' The minimal sub-block that computes 'outputs' from 'inputs'.

            'inputs' and 'outputs' must be subsets of 'self.inputs' and
            'self.outputs', respectively.
        ''' # TODO Elaborate docstring
        inputs = set(inputs)
        outputs = set(outputs)

        # TODO Restrict recursively

        # Look for results in the cache
        cache_key = (frozenset(inputs), frozenset(outputs))
        if cache_key in self.__restrictions:
            return self.__restrictions[cache_key]

        if not (inputs or outputs):
            raise ValueError('Must provide inputs or outputs')
        if not inputs.issubset(self.inputs):
            raise ValueError('Unknown inputs: %s' % (inputs - self.inputs))
        if not outputs.issubset(self.all_outputs):
            raise ValueError('Unknown outputs: %s' %(outputs-self.all_outputs))

        # If we don't decompose, then we are already as restricted as possible
        if self.sub_blocks is None:
            return self

        # We use the mock constructors `In` and `Out` to separate input and
        # output names in the dep graph in order to avoid cyclic graphs (in
        # case input and output names overlap)
        in_, out = object(), object() # (singletons)
        In = lambda x: (x, in_)
        Out = lambda x: (x, out)

        def wrap_names(wrap):
            "Wrap names and leave everything else alone"
            def g(x):
                if isinstance(x, basestring):
                    return wrap(x)
                else:
                    return x
            return g

        g = self._dep_graph

        # Decorate input names with `In` and output names with `Out` so that
        # `g` isn't cyclic. (Whose responsibility is this?)
        g = g.__class__(
            map_keys(wrap_names(Out),
                map_values(lambda l: map(wrap_names(In), l), g.adj))
        )

        # Find the subgraph reachable from inputs, and then find its subgraph
        # reachable from outputs. (We could also flip the order.)
        if inputs:
            inputs = set(map(In, inputs))
            g = reachable_graph(g.reverse(), *inputs).reverse()
        if outputs:
            outputs = set(map(Out, outputs))
            g = reachable_graph(g, *outputs.intersection(g.nodes()))

        # Create a new block from the remaining sub-blocks (ordered input to
        # output, ignoring the variables at the ends) and give it our filename
        b = Block(node for node in reversed(topological_sort(g))
                       if isinstance(node, Block))
        b.filename = self.filename

        # Cache result
        self.__restrictions[cache_key] = b

        return b
Esempio n. 5
0
    def transformAssign(self, node):

        # Only transform constant assignments
        if not is_const(node.expr):
            return self._transform_children(node)

        # '__foo' names come from each lhs name at the head of the assignment:
        #   'l = a,b = 0,1' -> 'l = a,b = __a,__b', { '__a':0, '__b':1 }
        #
        # Unpack the rhs enough to map each '__foo' name to a value.
        #   'a,l = 0,[1,2]' -> 'a,l = __a,__l', { '__a':0, '__l':[1,2] }
        #   'a,l = 2'       -> SyntaxError

        def lvalue_name(node):
            'Construct a "magic" name to represent an l-value.'
            prefix = sep = '__'
            dot = '_'
            if isinstance(node, AssName):
                return prefix + node.name
            elif isinstance(node, AssAttr):
                name = node.attrname
                expr = node.expr
                while isinstance(expr, Getattr):
                    name = sep.join([expr.attrname, name])
                    expr = expr.expr
                if isinstance(expr, Name):
                    expr_name = expr.name
                else:
                    expr_name = dot
                return prefix + sep.join([expr_name, name])

        # In these trees, strings and tuples are leaves
        leaves = (str, tuple, AssAttr, AssName)
        tree_zip = partial(tree.tree_zip, leaves=leaves)
        flatten = partial(tree.flatten, leaves=leaves)
        tree_embeds = partial(tree.tree_embeds, leaves=leaves)

        # Grab the (right-most) lhs and the rhs
        lhs, rhs = node.nodes[-1], node.expr

        # Associate constants with l-value names
        if not tree_embeds(lhs, rhs):
            raise SyntaxError('Not enough r-values to unpack: %s' % node)
        zipped = flatten(tree_zip(lhs, rhs))
        const_ast_for = map_keys(lambda v: lvalue_name(v), dict(zipped))

        # Gather name<->const mappings for names we haven't seen before
        name_for = {}
        for name in const_ast_for.keys():
            if name not in self.const_for.keys():
                self.const_for[name] = eval_ast(Expression(
                    const_ast_for[name]))
                assert const_ast_for[name] not in name_for
                name_for[const_ast_for[name]] = name

        class C(Transformer):
            def transform(self, node):
                if isinstance(node, Node) and node in name_for.keys():
                    return Name(name_for[node])
                else:
                    return super(C, self).transform(node)

        return Assign(node.nodes, C().transform(rhs))