Пример #1
0
    def test_self_loops_2(self):
        graph = Graph()

        node_1 = Node(graph)

        branch_a = Branch(node_1, node_1, "a")

        cycles = [[branch.id for branch in cycle]
                  for cycle in simple_cycles(graph)]

        self.assertCountEqual([[branch_a.id]], cycles)

        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_1, "c")
        Branch(node_3, node_4, "d")
        branch_e = Branch(node_1, node_1, "e")
        branch_f = Branch(node_2, node_2, "f")
        branch_g = Branch(node_3, node_3, "g")
        branch_h = Branch(node_4, node_4, "h")

        cycles = [[branch.id for branch in cycle]
                  for cycle in simple_cycles(graph)]

        self.assertTrue(self.__check_loop_order(
            [[branch_e.id],
             [branch_a.id, branch_b.id, branch_c.id],
             [branch_f.id], [branch_g.id], [branch_h.id]], cycles))
Пример #2
0
    def test_graph_copy(self):
        # Create graph
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)

        Branch(node_1, node_2)
        Branch(node_2, node_2)
        Branch(node_2, node_3)
        Branch(node_3, node_1)
        Branch(node_1, node_4)

        # Make copy
        graph_copy = graph.copy()

        # Assert
        nodes_original = list(graph.nodes)
        nodes_original.sort(key=lambda n: n.id)
        nodes_copy = list(graph_copy.nodes)
        nodes_copy.sort(key=lambda n: n.id)

        branches_original = list(graph.branches)
        branches_original.sort(key=lambda n: n.id)
        branches_copy = list(graph_copy.branches)
        branches_copy.sort(key=lambda n: n.id)

        for node_original, node_copy in zip(nodes_original, nodes_copy):
            self.assertTrue(self.__node_equals(node_original, node_copy))

        for branch_original, branch_copy in zip(branches_original,
                                                branches_copy):
            self.assertTrue(self.__branch_equals(branch_original, branch_copy))
Пример #3
0
    def test_add_remove_branches(self):
        graph = Graph()
        branch1 = MagicMock(Branch)
        branch2 = MagicMock(Branch)
        branch3 = MagicMock(Branch)
        branch1.start = MagicMock(Node)
        branch1.end = MagicMock(Node)
        branch1.graph = graph
        branch2.start = MagicMock(Node)
        branch2.end = MagicMock(Node)
        branch2.graph = graph
        branch3.start = MagicMock(Node)
        branch3.end = MagicMock(Node)
        branch3.graph = graph

        graph.add_branch(branch1)
        self.assertSetEqual({branch1}, graph.branches)

        graph.add_branch(branch2)
        graph.add_branch(branch3)
        self.assertSetEqual({branch1, branch2, branch3}, graph.branches)

        def add_branch_again():
            graph.add_branch(branch1)

        self.assertRaises(ValueError, add_branch_again)

        branch4 = MagicMock(Branch)
        branch4.start = MagicMock(Node)
        branch4.end = MagicMock(Node)
        branch4.graph = None

        def add_branch4():
            graph.add_branch(branch4)

        branch4.end = None
        self.assertRaises(ValueError, add_branch4)
        self.assertSetEqual({branch1, branch2, branch3}, graph.branches)

        branch1.start = None
        branch1.end = None
        branch2.start = None
        branch2.end = None
        branch3.start = None
        branch3.end = None
        graph.remove_branch(branch1)
        self.assertSetEqual({branch2, branch3}, graph.branches)
        graph.remove_branch(branch2)
        graph.remove_branch(branch3)
        self.assertSetEqual(set(), graph.branches)
Пример #4
0
    def test_not_touching_loops(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)

        branch_a = Branch(node_1, node_1, "a")
        branch_b = Branch(node_2, node_2, "b")
        branch_c = Branch(node_3, node_3, "c")

        res = find_loop_groups([
            [branch_a],
            [branch_b],
            [branch_c]
        ])

        loops = [(loopGroup.loops, loopGroup.loop_count) for loopGroup
                 in res]

        expected = [
            ([[branch_a]], 1),
            ([[branch_b]], 1),
            ([[branch_c]], 1),
            ([[branch_b], [branch_a]], 2),
            ([[branch_c], [branch_b]], 2),
            ([[branch_c], [branch_a]], 2),
            ([[branch_c], [branch_b], [branch_a]], 3),
        ]

        self.assertCountEqual(expected, loops)
Пример #5
0
    def test_johnson_4(self):
        graph = Graph()
        node_a = Node(graph)
        node_b = Node(graph)
        node_c = Node(graph)
        node_d = Node(graph)

        branch_ac = Branch(node_a, node_c, "ac")
        branch_ca = Branch(node_c, node_a, "ca")
        branch_ab = Branch(node_a, node_b, "ab")
        branch_ba = Branch(node_b, node_a, "ba")
        branch_bc = Branch(node_b, node_c, "bc")
        branch_cd = Branch(node_c, node_d, "cd")
        branch_db = Branch(node_d, node_b, "db")

        actual = strongly_connected_components(graph)
        expected = [[node_a, node_b, node_c, node_d]]

        self.assertTrue(self.__check_strongly_connected_components(
            expected, actual))

        cycles = [[branch.id for branch in cycle]
                  for cycle in simple_cycles(graph)]

        self.assertTrue(
            self.__check_loop_order([[branch_ac.id, branch_ca.id],
                                     [branch_ab.id, branch_ba.id],
                                     [branch_ab.id, branch_bc.id,
                                      branch_ca.id],
                                     [branch_ac.id, branch_cd.id,
                                      branch_db.id, branch_ba.id],
                                     [branch_bc.id, branch_cd.id,
                                      branch_db.id]],
                                    cycles))
Пример #6
0
    def test_johnson_3(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_6 = Node(graph)
        node_7 = Node(graph)

        Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_4, "c")
        Branch(node_4, node_5, "d")
        branch_e = Branch(node_5, node_6, "e")
        Branch(node_6, node_7, "f")
        branch_g = Branch(node_6, node_5, "g")
        branch_h = Branch(node_4, node_3, "h")
        branch_i = Branch(node_4, node_2, "i")
        Branch(node_2, node_6, "j")

        cycles = cycles = [[branch.id for branch in cycle]
                           for cycle in simple_cycles(graph)]

        self.assertTrue(self.__check_loop_order(
            [[branch_b.id, branch_c.id, branch_i.id],
             [branch_h.id, branch_c.id],
             [branch_e.id, branch_g.id]],
            cycles))
Пример #7
0
    def test_johnson_2(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_1, "b")
        branch_c = Branch(node_2, node_4, "c")
        branch_d = Branch(node_4, node_3, "d")
        branch_e = Branch(node_3, node_1, "e")
        branch_f = Branch(node_1, node_3, "f")

        components = strongly_connected_components(graph)
        self.assertEqual(1, len(components))
        self.assertCountEqual([node_3, node_4, node_2, node_1], components[0])

        cycles = [[branch.id for branch in cycle]
                  for cycle in simple_cycles(graph)]

        self.assertTrue(self.__check_loop_order(
            [[branch_f.id, branch_e.id],
             [branch_a.id, branch_c.id, branch_d.id, branch_e.id],
             [branch_a.id, branch_b.id],
             ], cycles))
Пример #8
0
    def test_add_remove_nodes(self):
        graph = Graph()
        node1 = MagicMock(Node)
        node2 = MagicMock(Node)
        node3 = MagicMock(Node)
        node1.graph = graph
        node2.graph = graph
        node3.graph = graph

        graph.add_node(node1)
        self.assertSetEqual({node1}, graph.nodes)

        graph.add_node(node2)
        graph.add_node(node3)

        def add_node_again():
            graph.add_node(node1)

        self.assertRaises(ValueError, add_node_again)
        self.assertSetEqual({node1, node2, node3}, graph.nodes)

        node4 = MagicMock(Node)
        node4.graph = MagicMock(Graph)

        def add_node4():
            graph.add_node(node4)

        self.assertRaises(ValueError, add_node4)
        self.assertSetEqual({node1, node2, node3}, graph.nodes)
        node4.graph = graph
        node4.ingoing = [1, 2, 3]
        self.assertRaises(ValueError, add_node4)
        self.assertSetEqual({node1, node2, node3}, graph.nodes)

        graph.remove_node(node1)
        self.assertSetEqual({node2, node3}, graph.nodes)

        graph.remove_node(node2)
        graph.remove_node(node3)

        self.assertSetEqual(set(), graph.nodes)
Пример #9
0
    def test_find_paths_line(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")

        self.assertCountEqual([[branch_a, branch_b]],
                              find_paths(node_1, node_3))
Пример #10
0
    def test_loop_to_expression_1(self):
        graph = Graph()

        node_1 = Node(graph)

        branch_a = Branch(node_1, node_1, "a")

        branches = [branch_a]

        expectedExpression = Symbol(branch_a.weight)

        expression = loop_to_expression(branches)

        self.assertEqual(srepr(expression), srepr(expectedExpression))
Пример #11
0
    def test_johnson_1(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_1, "c")

        cycles = [[branch.id for branch in cycle]
                  for cycle in simple_cycles(graph)]
        self.assertTrue(self.__check_loop_order(
            [[branch_a.id, branch_b.id, branch_c.id]], cycles))
Пример #12
0
    def test_find_paths_self_loop4(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        Branch(node_1, node_3, "b")
        Branch(node_3, node_4, "c")
        Branch(node_4, node_1, "d")

        paths = find_paths(node_1, node_2)
        self.assertCountEqual([[branch_a]], paths)
Пример #13
0
    def test_strongly_connected_components(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)

        Branch(node_1, node_2, "a")
        Branch(node_2, node_3, "b")
        Branch(node_2, node_3, "c")
        Branch(node_3, node_1, "d")

        components = strongly_connected_components(graph)
        self.assertEqual(1, len(components))
        component = components[0]
        self.assertCountEqual([node_3, node_2, node_1], component)
Пример #14
0
    def test_loop_to_expression_3(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_6 = Node(graph)
        node_7 = Node(graph)
        node_8 = Node(graph)
        node_9 = Node(graph)
        node_10 = Node(graph)
        node_11 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_4, "c")
        branch_d = Branch(node_4, node_5, "d")
        branch_e = Branch(node_5, node_6, "e")
        branch_f = Branch(node_6, node_7, "f")
        branch_g = Branch(node_7, node_8, "g")
        branch_h = Branch(node_8, node_9, "h")
        branch_j = Branch(node_9, node_10, "j")
        branch_k = Branch(node_10, node_11, "k")
        branch_l = Branch(node_11, node_1, "l")

        branches = [
            branch_a, branch_b, branch_c, branch_d, branch_e, branch_f,
            branch_g, branch_h, branch_j, branch_k, branch_l
        ]

        expectedExpression = Mul(Symbol(branch_a.weight),
                                 Symbol(branch_b.weight),
                                 Symbol(branch_c.weight),
                                 Symbol(branch_d.weight),
                                 Symbol(branch_e.weight),
                                 Symbol(branch_f.weight),
                                 Symbol(branch_g.weight),
                                 Symbol(branch_h.weight),
                                 Symbol(branch_j.weight),
                                 Symbol(branch_k.weight),
                                 Symbol(branch_l.weight))

        expression = loop_to_expression(branches)

        self.assertEqual(srepr(expression), srepr(expectedExpression))
Пример #15
0
    def test_loop_to_expression_2(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_1, "b")

        branches = [branch_a, branch_b]

        expectedExpression = Mul(Symbol(branch_a.weight),
                                 Symbol(branch_b.weight))

        expression = loop_to_expression(branches)

        self.assertEqual(srepr(expression), srepr(expectedExpression))
Пример #16
0
    def test_find_paths_self_loop3(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_4, "c")
        branch_d = Branch(node_4, node_5, "d")
        Branch(node_4, node_2, "e")

        paths = find_paths(node_1, node_5)
        self.assertCountEqual([[branch_a, branch_b, branch_c, branch_d]],
                              paths)
Пример #17
0
    def test_mason_1(self):
        # Create graph
        graph = Graph()

        # Add nodes
        node_x = Node(graph)  # input node
        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_z = Node(graph)  # output node

        # Add branches
        Branch(node_x, node_1, "a")
        Branch(node_1, node_2, "b")
        Branch(node_2, node_3, "c")
        Branch(node_3, node_4, "d")
        Branch(node_4, node_5, "e")
        Branch(node_5, node_z, "f")
        Branch(node_5, node_4, "g")
        Branch(node_3, node_2, "h")
        Branch(node_3, node_1, "j")
        Branch(node_1, node_5, "k")

        # Execute
        result = mason(graph, node_x, node_z)

        # Assert
        expected = [
            "(a*b*c*d*e*f + a*f*k*(-c*h + 1))",
            "/(b*c*e*g*j - b*c*j + c*e*g*h - c*h - e*g + 1)"
        ]

        T = result.transfer_function[0][0]
        actual = T.subs(result.transfer_function) \
            .subs(result.numerator) \
            .subs(result.denominator) \
            .subs(result.determinant) \
            .subs(result.paths) \
            .subs(result.loops)

        self.assertEqual(expected[0] + expected[1], str(actual))
Пример #18
0
    def test_johson_multiple_scc(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_6 = Node(graph)
        node_7 = Node(graph)
        node_8 = Node(graph)
        node_9 = Node(graph)

        Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_4, "c")
        branch_d = Branch(node_4, node_2, "d")
        branch_e = Branch(node_1, node_5, "e")
        branch_f = Branch(node_5, node_6, "f")
        branch_g = Branch(node_6, node_1, "g")
        branch_h = Branch(node_9, node_7, "h")
        branch_i = Branch(node_7, node_8, "i")
        branch_j = Branch(node_8, node_9, "j")
        Branch(node_6, node_9, "k")

        actual = strongly_connected_components(graph)
        expected = [[node_9, node_8, node_7],
                    [node_3, node_2, node_4],
                    [node_6, node_5, node_1]]

        self.assertTrue(self.__check_strongly_connected_components(
            expected, actual))

        cycles = [[branch.id for branch in cycle]
                  for cycle in simple_cycles(graph)]

        self.assertTrue(
            self.__check_loop_order([[branch_b.id, branch_c.id, branch_d.id],
                                     [branch_e.id, branch_f.id, branch_g.id],
                                     [branch_h.id, branch_i.id, branch_j.id]],
                                    cycles))
Пример #19
0
    def test_find_paths_self_loops(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)

        branch_a = Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_2, node_3, "c")

        Branch(node_2, node_2, "d")
        branch_e = Branch(node_2, node_1, "e")
        branch_f = Branch(node_3, node_1, "f")

        self.assertCountEqual([[branch_a, branch_b], [branch_a, branch_c]],
                              find_paths(node_1, node_3))

        paths = find_paths(node_2, node_1)
        self.assertCountEqual(
            [[branch_c, branch_f], [branch_e], [branch_b, branch_f]], paths)
Пример #20
0
    def test_mason_3(self):
        # Create graph
        graph = Graph()

        # Add nodes
        node_x = Node(graph)  # input node
        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_z = Node(graph)  # output node

        # Add branches
        Branch(node_x, node_z, "g7")
        Branch(node_z, node_x, "h7")
        Branch(node_z, node_1, "g8")
        Branch(node_1, node_2, "C")
        Branch(node_2, node_3, "g3")
        Branch(node_3, node_4, "g4")
        Branch(node_4, node_5, "g5")
        Branch(node_5, node_x, "g6")
        Branch(node_2, node_1, "h2")
        Branch(node_4, node_3, "N")

        # Execute
        result = mason(graph, node_x, node_z)

        # Assert
        expected_num = "g7*(C*N*g4*h2 - C*h2 - N*g4 + 1)"

        actual_num = result.numerator[0][1] \
            .subs(result.numerator) \
            .subs(result.denominator) \
            .subs(result.determinant) \
            .subs(result.paths) \
            .subs(result.loops)

        self.assertEqual(expected_num, str(actual_num))
Пример #21
0
    def test_find_paths_loop_over_loop(self):
        #           <--j ------------|
        #          |         <--h----|         <--g----
        #          |        |        |        |        |
        # X --a--> 1 --b--> 2 --c--> 3 --d--> 4 --e--> 5 --f--> Z
        #          |                                   |
        #           -------------------------------k-->

        # Create graph
        graph = Graph()

        # Create nodes
        node_x = Node(graph)  # input node
        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_z = Node(graph)  # output node

        # Create branches and connect nodes
        branch_a = Branch(node_x, node_1, "a")
        branch_b = Branch(node_1, node_2, "b")
        branch_c = Branch(node_2, node_3, "c")
        branch_d = Branch(node_3, node_4, "d")
        branch_e = Branch(node_4, node_5, "e")
        branch_f = Branch(node_5, node_z, "f")

        Branch(node_5, node_4, "g")
        Branch(node_3, node_2, "h")
        Branch(node_3, node_1, "j")
        branch_k = Branch(node_1, node_5, "k")

        # Assert
        paths = find_paths(node_x, node_z)
        self.assertCountEqual(
            [[branch_a, branch_b, branch_c, branch_d, branch_e, branch_f],
             [branch_a, branch_k, branch_f]], paths)
Пример #22
0
    def test_touching_loops(self):
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)
        node_5 = Node(graph)
        node_6 = Node(graph)
        node_7 = Node(graph)

        Branch(node_1, node_2, "a")
        branch_b = Branch(node_2, node_3, "b")
        branch_c = Branch(node_3, node_4, "c")
        Branch(node_4, node_5, "d")
        branch_e = Branch(node_5, node_6, "e")
        Branch(node_6, node_7, "f")
        branch_g = Branch(node_6, node_5, "g")
        branch_h = Branch(node_4, node_3, "h")
        branch_i = Branch(node_4, node_2, "i")
        Branch(node_2, node_6, "j")

        res = find_loop_groups([[branch_h, branch_c], [branch_g, branch_e],
                                [branch_i, branch_b, branch_c]])

        loops = [(loopGroup.loops, loopGroup.loop_count) for loopGroup
                 in res]

        expected = [
            ([[branch_h, branch_c]], 1),
            ([[branch_g, branch_e]], 1),
            ([[branch_i, branch_b, branch_c]], 1),
            ([[branch_g, branch_e], [branch_h, branch_c]], 2),
            ([[branch_i, branch_b, branch_c], [branch_g, branch_e]], 2)
        ]

        self.assertCountEqual(expected, loops)
Пример #23
0
    def test_subgraph(self):
        graph = Graph()
        node = Node(graph)
        subgraph = graph.subgraph({node})
        self.assertEqual(1, len(subgraph.nodes))
        self.assertEqual(0, len(graph.nodes))
        self.assertEqual(node, list(subgraph.nodes)[0])
        self.assertEqual(node.graph, subgraph)

        graph = Graph()
        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)

        branch_1 = Branch(node_1, node_2, "1")
        branch_2 = Branch(node_2, node_1, "2")
        Branch(node_2, node_3, "3")
        Branch(node_3, node_1, "4")
        branch_5 = Branch(node_3, node_3, "5")
        branch_6 = Branch(node_2, node_2, "6")

        subgraph = graph.subgraph([node_1, node_2])

        self.assertCountEqual([node_1, node_2], subgraph.nodes)
        self.assertCountEqual([node_3], graph.nodes)
        self.assertCountEqual([branch_1, branch_2, branch_6],
                              subgraph.branches)
        self.assertCountEqual([branch_5], graph.branches)

        self.assertEqual(node_1.graph, subgraph)
        self.assertEqual(node_2.graph, subgraph)
        self.assertEqual(node_3.graph, graph)

        self.assertEqual(branch_1.graph, subgraph)
        self.assertEqual(branch_2.graph, subgraph)
        self.assertEqual(branch_5.graph, graph)
        self.assertEqual(branch_6.graph, subgraph)
Пример #24
0
def simple_cycles(g: Graph) -> List[List[Branch]]:
    """Find all simple cycles in a graph"""
    # Make copy because the graph gets altered during the algorithm
    graph_copy = g.copy()
    branch_map = {}
    copy_result = list()

    # Create map to allow returning original branches
    for branch in g.branches:
        branch_map[branch.id] = branch

    # Yield every elementary cycle in python graph G exactly once
    # Expects a dictionary mapping from vertices to iterables of vertices
    def _unblock(thisnode, blocked, B):
        stack = set([thisnode])
        while stack:
            node = stack.pop()
            if node in blocked:
                blocked.remove(node)
                stack.update(B[node])
                B[node].clear()

    sccs = [(graph_copy, scc)
            for scc in strongly_connected_components(graph_copy)]
    while sccs:
        current_graph, scc = sccs.pop()
        startnode = scc.pop()
        path = [startnode.id]
        pathBranches = []
        blocked = set()
        closed = set()
        blocked.add(startnode.id)
        B = defaultdict(set)
        stack = [(startnode, list(startnode.outgoing))]
        while stack:
            thisnode, nbrs = stack[-1]
            if nbrs:
                branch = nbrs.pop()
                nextnode = branch.end
                if nextnode.id == startnode.id:
                    result = pathBranches[:]
                    result.append(branch)
                    copy_result.append(result)
                    closed.update(path)
                elif nextnode.id not in blocked:
                    path.append(nextnode.id)
                    pathBranches.append(branch)
                    stack.append((nextnode, list(nextnode.outgoing)))
                    closed.discard(nextnode.id)
                    blocked.add(nextnode.id)
                    continue
            if not nbrs:
                if thisnode.id in closed:
                    _unblock(thisnode.id, blocked, B)
                else:
                    for nbr in map(lambda x: x.end, thisnode.outgoing):
                        if thisnode.id not in B[nbr.id]:
                            B[nbr.id].add(thisnode.id)
                stack.pop()
                path.pop()
                if (pathBranches):
                    pathBranches.pop()
        startnode.remove()
        subgraph = current_graph.subgraph(set(scc))
        new_scc = strongly_connected_components(subgraph)
        sccs.extend([(subgraph, scc) for scc in new_scc])

    for loop in copy_result:
        yield list(map(lambda b: branch_map[b.id], loop))