Example #1
0
def test_graph_augmentation():

    #  a  b  c
    #  |  |  |
    # n0 n1 n2
    #  |\/|\/|
    #  |/\|/\|
    # n3 n4 n5
    #  |  |  |
    #  d  e  f

    a, b, c, d, e, f = Wire('a'), Wire('b'), Wire('c'), Wire('d'), Wire(
        'e'), Wire('f')
    n0, n1, n2, n3, n4, n5 = Node('0'), Node('1'), Node('2'), Node('3'), Node(
        '4'), Node('5')
    e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13 = \
        Edge('0', a, n0), Edge('1', b, n1), Edge('2', c, n2), \
        Edge('3', n0, n3), Edge('4', n0, n4), \
        Edge('5', n1, n3), Edge('6', n1, n4), Edge('7', n1, n5), \
        Edge('8', n2, n4), Edge('9', n2, n5), \
        Edge('10', d, n3), Edge('11', e, n4), Edge('12', f, n5), \
        Edge('13', n0, n0)
    inputs = [a, b, c]
    outputs = [d, e, f]
    nodes = [n0, n1, n2, n3, n4, n5]
    edges = [e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13]
    graph = Graph(nodes, edges, inputs, outputs)
    inputs_graph = Graph(inputs=inputs, nodes=[n0], edges=[e0, e13])
    inputs_graph.augment(graph)
    expected_result = Graph([n0, n1, n2, n3, n4],
                            [e0, e1, e2, e3, e4, e5, e6, e8, e13], inputs, [])
    assert inputs_graph == expected_result
Example #2
0
def connected_graphs_split(graph: Graph) -> (Graph, Graph):
    """ If possible, splits a graph in two separate graphs, the first one has to be connected.

    Args:
        graph (Graph): graph to be split in two

    Returns:
        (Graph, Graph): a connected graph and the rest of the edges, nodes and so on ...
    """
    # possible improvement, return balanced graphs
    if graph.nodes:
        increasing_graph = Graph(nodes=[graph.nodes[0]])
        # the potential loops must be included
        edges = [
            edge for edge in graph.edges
            if edge.n1 == graph.nodes[0] and edge.n2 == graph.nodes[0]
        ]
        increasing_graph.edges = edges
    elif graph.inputs:
        increasing_graph = Graph(inputs=[graph.inputs[0]])
    elif graph.outputs:
        increasing_graph = Graph(outputs=[graph.outputs[0]])
    else:
        # graph empty
        return Graph([], [], [], []), deepcopy(graph)
    while increasing_graph.augment(graph):
        pass
    leftover = graph - increasing_graph
    return increasing_graph, leftover
Example #3
0
def split_and_reunite(graph: Graph) -> GenericMatrix:
    """Recursive function taking in a graph and returning the corresponding matrix.

    To do so, split the graph in two, passes the two halves to it's next iteration and reunite the two matrix obtained
    using the :ref:`fusion_matrices <fusion_matrices>` method from :ref:`divide_conquer`.

    The main part of this function is converting the graph format to the matrix format. tmp

    Args:
        graph (Graph): diagram considered

    Returns:
        GenericMatrix: matrix corresponding to the given diagram
    """
    if len(graph.nodes) == 0:
        return no_node_matrix(graph.edges, graph.inputs, graph.outputs)
    elif len(graph.nodes) == 1 and not no_node_edges_detection(graph.edges):
        try:
            return UsedFragment.node_to_matrix(graph.nodes[0],
                                               len(graph.inputs),
                                               len(graph.outputs))
        except AttributeError:
            return fallback_node_to_matrix(graph.nodes[0], len(graph.inputs),
                                           len(graph.outputs))
    else:
        graph1, graph2 = connected_graphs_split(graph)
        if not graph2:
            # we rewrite graph1 and graph2 so they contain two parts of the current graph1
            if no_node_edges_detection(graph.edges):
                # probably dead code since if a graph has such an edge (containing no node, only I/O), and has nodes,
                # the connected_graphs_split function would return two distinct graphs
                #
                # degenerate cases, when a graph contains only wires
                # in this case, graph1 will contain the I/O connected to another I/O and graph2 will contain the rest
                graph2 = Graph(nodes=graph.nodes)

                graph2 += filter_edges_inputs_outputs_by_nodes(
                    graph2.nodes, graph)
                graph1 = graph - graph2
            else:
                if graph.inputs:
                    graph1 = Graph(inputs=[graph.inputs[0]])
                    graph1.augment(graph)
                elif graph.nodes:
                    graph1 = Graph(nodes=[graph.nodes[0]])
                else:
                    raise RuntimeError(
                        'A graph with no node shouldn\'t enter in this branch')

                graph1 += graph1.neighbouring_i_o(graph)
                graph2 = graph - graph1

                in_between_edges = between_graphs_edges(graph1, graph2, graph)

                graph1.edges += in_between_edges

                in_between_wires = []
                for edge in in_between_edges:
                    in_between_wires.append(Wire(edge.name))

                graph1.outputs += in_between_wires
                graph2.inputs += in_between_wires

            first_half_matrix = split_and_reunite(graph1)
            second_half_matrix = split_and_reunite(graph2)

            inter_matrix_link = matrix_linker(graph1, graph2)
        else:
            first_half_matrix = split_and_reunite(graph1)
            second_half_matrix = split_and_reunite(graph2)
            inter_matrix_link = []

        input_connections = wires_to_connection_point_node_sorted(
            graph.inputs, graph.edges, graph1.nodes, graph2.nodes, False)
        output_connections = wires_to_connection_point_node_sorted(
            graph.outputs, graph.edges, graph1.nodes, graph2.nodes, True)

        return divide_conquer.fusion_matrices(first_half_matrix,
                                              second_half_matrix,
                                              input_connections,
                                              output_connections,
                                              inter_matrix_link)