Source code for priops.edge

from priops.node import EmptyNode

[docs]class Edge: """Edges describe connections between two :class:`~priops.Node` objects. An edge has a direction; there is an input node and an output node. An edge can be called, in that case the edge will transform an object list of the input node specification into an object list of the output node specification. This class is abstract. Derived classes should provide: * ``.process(self, input)``: Processes the non-internode input data to non-internode output data. Non-internode data is different from internode data format by the fact that inter-node data is always a list, while intra-edge data might be scalar. 1. If the input node is scalar, *input* will be scalar (the first element of the inter-node data stream). If the input node is not scalar, *input* will be the direct inter-node data stream. 2. If the output node is scalar, ``.process()`` should return a scalar, which will then be converted by the output node to inter-node list format. If the output node is not scalar, the output of ``.process()`` should already be a list."""
[docs] def __init__(self, input_node, output_node, weight=None, name=None): """*input_node* is the specification of the input, *output_node* is the specification of the output of the ``Edge``. *weight* is the effort to follow this edge (default 1). *name* is used for pretty printing.""" if weight is None: weight = 1 self.input_node = input_node self.output_node = output_node self.weight = weight self.name = name
[docs] def __str__(self): if self.name is None: return '(' + str(self.input_node) + ' -> ' + \ str(self.output_node) + ')' else: return '(' + self.name + ' ' + str(self.input_node) + ' -> ' + \ str(self.output_node) + ')'
[docs] def __add__(self, other_edge): """Combines this edge *self* with another edge *other_edge* via creating a :class:`CombinedEdge` instance.""" return CombinedEdge(constituents=[self, other_edge])
[docs] def __call__(self, inputs): """Processes the inter-edge data stream *inputs* into inter-edge data stream *outputs*. Inter-edge data are lists. Calls *self.process()* with appropriate arguments.""" intra_edge_input = self.input_node.frominter(inputs) intra_edge_processed = self.process(input=intra_edge_input) inter_edge_output = self.output_node.tointer(intra_edge_processed) return inter_edge_output
[docs]class IdentityEdge(Edge): """An edge with identical input and output nodes, returning its arguments on call. Has zero weight."""
[docs] def __init__(self, node): """*node* is the node to process by identity.""" Edge.__init__(self, input_node=node, output_node=node, weight=0, name='Identity')
[docs] def process(self, input): """Returns *input* unchanged.""" return input
[docs]class CombinedEdge(Edge): """Combined edges combine a number of :class:`Edge` objects into one big edge. The input node of the combined edge is the sum of all input nodes of the constituets. The output node of a combined edge is similarly the sum of all output nodes of the constituets. When being called, the combined edge dispatches the inputs to the constituents according to the length of their input nodes. Then the constituents will be called with the dispatched inputs."""
[docs] def __init__(self, constituents): """Combines *constituents* into a combined egde.""" self.constituents = constituents input_node = sum([constituent.input_node for constituent in \ constituents], EmptyNode()) output_node = sum([constituent.output_node for constituent in \ constituents], EmptyNode()) weight = sum([constituent.weight for constituent in constituents]) Edge.__init__(self, input_node=input_node, output_node=output_node, weight=weight, name='Combined Edge')
[docs] def process(self, input): """Dispatches the input object list *input* to the constituents.""" result = [] input_left = input for constituent in self.constituents: len_constituent = len(constituent.input_node) input_constituent = input_left[:len_constituent] result.extend(constituent(input_constituent)) input_left = input_left[len_constituent:] return result