예제 #1
0
    def remove_redundant(self):
        """
        Find and remove redundant edges. An edge is redundant
        if there there are multiple possibilities to reach an end node
        from a start node. Since the longer path triggers more needed
        database updates the shorter path gets discarded.
        Might raise a ``CycleNodeException``.

        Returns the removed edges.
        """
        paths = self.get_nodepaths()
        possible_replaces = []
        for p_path in paths:
            for q_path in paths:
                if self._can_replace_nodepath(q_path, p_path):
                    possible_replaces.append((q_path, p_path))
        removed = set()
        for candidate, _ in possible_replaces:
            edges = [Edge(*nodes) for nodes in pairwise(candidate)]
            for edge in edges:
                if edge in removed:
                    continue
                self.remove_edge(edge)
                removed.add(edge)
                # make sure all startpoints will still update all endpoints
                if not self._compare_startend_nodepaths(
                        self.get_nodepaths(), paths):
                    self.add_edge(edge)
                    removed.remove(edge)
        self._removed.update(removed)
        return removed
 def test_graph_cycle_detection(self):
     nodes = [
         Node('A'),
         Node('B'),
         Node('C'),
         Node('D'),
         Node('E'),
         Node('F')
     ]
     simple_edges = [Edge(a, b) for a, b in pairwise(nodes)]
     graph = Graph()
     for edge in simple_edges:
         graph.add_edge(edge)
     self.assertTrue(graph.is_cyclefree)
     self.assertFalse(graph.edge_cycles)
     self.assertFalse(graph.node_cycles)
     # add one cycle
     graph.add_edge(Edge(nodes[1], nodes[0]))
     self.assertFalse(graph.is_cyclefree)
     self.assertEqual(len(graph.node_cycles), 1)
     # add second cycle
     graph.add_edge(Edge(nodes[2], nodes[0]))
     self.assertEqual(len(graph.node_cycles), 2)
     # add third cycle
     graph.add_edge(Edge(nodes[5], nodes[4]))
     self.assertEqual(len(graph.node_cycles), 3)
     # add tricky edge (adds multiple cycles at once)
     graph.add_edge(Edge(nodes[4], nodes[2]))
     self.assertGreater(len(graph.node_cycles), 4)
     self.assertGreater(len(graph.edge_cycles), 4)
 def test_raise_cycle_exceptions(self):
     nodes = [
         Node('A'),
         Node('B'),
         Node('C'),
         Node('D'),
         Node('E'),
         Node('F')
     ]
     simple_edges = [Edge(a, b) for a, b in pairwise(nodes)]
     graph = Graph()
     for edge in simple_edges:
         graph.add_edge(edge)
     # should not raise CycleExceptions
     graph.get_nodepaths()
     graph.get_edgepaths()
     # add one cycle
     graph.add_edge(Edge(nodes[1], nodes[0]))
     # should raise suitable exceptions
     self.assertRaises(CycleNodeException, lambda: graph.get_nodepaths())
     self.assertRaises(CycleEdgeException, lambda: graph.get_edgepaths())
     # CycleNodeException message should contain
     # cycling nodes (order is undetermined)
     try:
         graph.get_nodepaths()
     except CycleNodeException as e:
         self.assertIn(e.args[0], [[nodes[0], nodes[1], nodes[0]],
                                   [nodes[1], nodes[0], nodes[1]]])
예제 #4
0
 def test_paths(self):
     nodes = [Node('A'), Node('B'), Node('C'), Node('D'), Node('E'), Node('F')]
     simple_edges = [Edge(a, b) for a, b in pairwise(nodes)]
     graph = Graph()
     for edge in simple_edges:
         graph.add_edge(edge)
     all_edge_paths = graph.get_edgepaths()
     all_node_paths = graph.get_nodepaths()
     self.assertEqual(len(all_node_paths), 15)  # should match 6 choose 2 (n!/((n-k)!*k!))
     self.assertEqual(all_edge_paths,
                      [graph.nodepath_to_edgepath(path) for path in all_node_paths])
     self.assertEqual(all_node_paths,
                      [graph.edgepath_to_nodepath(path) for path in all_edge_paths])
예제 #5
0
 def nodepath_to_edgepath(self, path):
     """
     Converts a list of nodes to a list of edges.
     """
     return [Edge(*pair) for pair in pairwise(path)]
예제 #6
0
 def nodepath_to_edgepath(path: Sequence[Node]) -> List[Edge]:
     """
     Converts a list of nodes to a list of edges.
     """
     return [Edge(*pair) for pair in pairwise(path)]