Exemple #1
0
def eq(g1, g2):
    return map_values(set, g1) == map_values(set, g2)
Exemple #2
0
def eq(g1, g2):
    return map_values(set, g1) == map_values(set, g2)
Exemple #3
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