예제 #1
0
 def test_min_weight_matching(self):
     algorithm = MinimumWeightMatchingWithEdges(self.G)
     algorithm.run()
     expected_cardinality = 2
     expected_weight = 9  # best minimum 8
     # Best solution.
     #expected_mate = {0: Edge(0, 2, 3), 1: Edge(1, 3, 5),
     #    2: Edge(2, 0, 3), 3: Edge(3, 1, 5)}
     expected_mate = {
         0: Edge(0, 3, 2),
         1: Edge(1, 2, 7),
         2: Edge(2, 1, 7),
         3: Edge(3, 0, 2)
     }
     self.assertEqual(algorithm.cardinality, expected_cardinality)
     # Krawedzie sa po dwa razy w slowniku.
     weight = sum(algorithm.mate[node].weight
                  for node in algorithm.mate if algorithm.mate[node]) / 2
     self.assertEqual(weight, expected_weight)
     self.assertEqual(algorithm.mate, expected_mate)
     # Is it matching?
     for source in algorithm.mate:
         if algorithm.mate[source] is not None:
             edge = algorithm.mate[source]
             self.assertEqual(algorithm.mate[edge.target], ~edge)
예제 #2
0
 def _reduce_triangle(self, a, b, c):
     """Collapse nodes from a triangle with distinct neighbors."""
     Na = self.other_neighbor(b, a, c)
     Nb = self.other_neighbor(a, b, c)
     Nc = self.other_neighbor(a, c, b)
     if Na == Nb or Nb == Nc or Na == Nc:
         return  # need to have three distinct neighbors
     # BEGIN HALIN
     if a in self.outer and b in self.outer and c in self.outer:
         return  # can't collapse when all three are outer
     # If node belongs to the outer face, mark its neighbor as outer.
     for node, neighbor in [(a, Na), (b, Nb), (c, Nc)]:
         if node in self.outer:
             self.outer.add(neighbor)
     # Add also the collapsed node to the outer set.
     new_node = "{0}_{1}_{2}".format(a, b, c)
     self.outer.add(new_node)
     self._calls.append(("triangle", a, b, c, Na, Nb, Nc, new_node))
     # END HALIN
     # Make the change!
     self._graph_copy.del_node(a)
     self._graph_copy.del_node(b)
     self._graph_copy.del_node(c)
     self._graph_copy.add_edge(Edge(Na, new_node))
     self._graph_copy.add_edge(Edge(Nb, new_node))
     self._graph_copy.add_edge(Edge(Nc, new_node))
     # Update the active nodes.
     for node in (new_node, Na, Nb, Nc):
         if self._graph_copy.degree(node) == 3:
             self.degree3.add(node)
예제 #3
0
 def setUp(self):
     self.N = 5
     self.G = Graph(self.N)
     self.nodes = range(self.N)
     self.edges = [
         Edge(0, 1),
         Edge(0, 2),
         Edge(1, 2),
         Edge(1, 3),
         Edge(1, 4)
     ]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
     #self.G.show()
     node1 = Node(0, 1, "edge")
     node2 = Node(0, 2, "edge")
     node3 = Node(2, 1, "edge")
     node4 = Node(1, 3, "edge")
     node5 = Node(1, 4, "edge")
     node6 = Node(0, 1, "series", node2, node3)
     node7 = Node(0, 1, "parallel", node1, node6)
     node8 = Node(0, 1, "jackknife", node7, node4)
     node9 = Node(0, 1, "jackknife", node8, node5)
     self.root = node9
예제 #4
0
 def run(self):
     """Executable pseudocode."""
     size = self.graph.v()
     # Create flow network.
     network = self.graph.__class__(size + 2, directed=True)
     self.source = size
     self.sink = size + 1
     network.add_node(self.source)
     network.add_node(self.sink)
     for node in self.graph.iternodes():  # O(V) time
         network.add_node(node)
     for node in self.v1:  # edges from source to V1
         network.add_edge(Edge(self.source, node))
     for edge in self.graph.iteredges():  # edges from V1 to V2
         if edge.source in self.v1:  # weights are 1
             network.add_edge(Edge(edge.source, edge.target))
         else:
             network.add_edge(Edge(edge.target, edge.source))
     for node in self.v2:  # edges from V2 to sink
         network.add_edge(Edge(node, self.sink))
     algorithm = FordFulkersonSparse(network)
     algorithm.run(self.source, self.sink)  # O(V*E) time
     for source in self.v1:
         for target in self.v2:
             if algorithm.flow[source].get(target, 0) == 1:
                 self.mate[source] = target
                 self.mate[target] = source
     self.cardinality = algorithm.max_flow
예제 #5
0
 def make_triangle(self, size=3):
     """Create a weighted triangle graph with boundary,
     |V| = size * size, |E| = 2 * size * (size-1) + (size-1) * (size-1).
     """
     if size < 3:
         raise ValueError("size too small")
     n = size * size
     graph = self.cls(n, directed=False)
     weights = list(range(1, 1 + 3 * size * size - 4 * size +
                          1))  # different weights
     random.shuffle(weights)
     for node in xrange(n):
         graph.add_node(node)
     for node in xrange(n):
         row = node // size
         col = node % size
         if col != size - 1:
             graph.add_edge(Edge(node, node + 1, weights.pop()))  # line ---
         if row != size - 1:
             graph.add_edge(Edge(node, node + size,
                                 weights.pop()))  # line |
         if col != size - 1 and row != size - 1:
             graph.add_edge(Edge(node, node + 1 + size,
                                 weights.pop()))  # line /
     return graph
예제 #6
0
 def make_triangle_periodic(self, size=3):
     """Create a weighted triangle network with periodic boundary 
     conditions. |V| = size * size, |E| = 3 * |V|.
     """
     if size < 3:
         raise ValueError("size too small")
     n = size * size
     graph = self.cls(n, directed=False)
     weights = list(range(1, 1 + 3 * n))  # different weights
     random.shuffle(weights)
     for node in xrange(n):
         graph.add_node(node)
     for node in xrange(n):
         row = node // size
         col = node % size
         graph.add_edge(
             Edge(node, row * size + (col + 1) % size,
                  weights.pop()))  # line ---
         graph.add_edge(
             Edge(node, ((row + 1) % size) * size + col,
                  weights.pop()))  # line |
         graph.add_edge(
             Edge(node, ((row + 1) % size) * size + (col + 1) % size,
                  weights.pop()))  # line /
     return graph
예제 #7
0
 def test_is_biconnected(self):
     self.assertFalse(is_biconnected(self.G))
     self.G.add_edge(Edge(4, 5))
     self.assertFalse(is_biconnected(self.G))
     self.G.add_edge(Edge(1, 2))
     self.assertFalse(is_biconnected(self.G))
     self.G.add_edge(Edge(6, 7))
     self.assertTrue(is_biconnected(self.G))
예제 #8
0
 def setUp(self):
     self.N = 4           # number of nodes
     self.G = Graph(self.N, directed=True)
     self.edges = [
         Edge(0, 1, 2), Edge(1, 2, 4), Edge(2, 0, 6), Edge(2, 3, 3), 
         Edge(3, 1, 5)]
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #9
0
 def test_tree_three_nodes(self):
     T = Graph(3)
     for node in (0, 1, 2):
         T.add_node(node)
     for edge in (Edge(0, 1), Edge(1, 2)):
         T.add_edge(edge)
     algorithm = TreePlot(T)
     algorithm.run()
     self.assertEqual(len(algorithm.point_dict), 3)
예제 #10
0
 def iterinedges(self, source):
     """Generate the inedges from the graph on demand."""
     if self.is_directed():  # O(V) time
         for target in self.iternodes():
             if source in self[target]:
                 yield Edge(target, source, self[target][source])
     else:
         for target in self[source]:
             yield Edge(target, source, self[target][source])
예제 #11
0
 def setUp(self):
     self.N = 8           # number of nodes
     self.G = Graph(self.N)
     self.edges = [
         Edge(0, 1), Edge(0, 2), Edge(2, 3), Edge(1, 3), 
         Edge(2, 4), Edge(3, 5), Edge(4, 6), Edge(4, 5), 
         Edge(5, 7), Edge(6, 7)]
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #12
0
 def setUp(self):
     self.N = 6
     self.G = Graph(self.N)
     self.nodes = range(self.N)
     self.edges = [Edge(0, 1), Edge(1, 2), Edge(2, 3),
         Edge(3, 4), Edge(4, 5)]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #13
0
 def test_3prism(self):
     N = 6
     G = Graph(N, False)
     edges = [
         Edge(0, 1),
         Edge(1, 2),
         Edge(2, 3),
         Edge(3, 4),
         Edge(4, 5),
         Edge(0, 5),
         Edge(1, 4),
         Edge(2, 0),
         Edge(3, 5)
     ]
     for node in range(N):
         G.add_node(node)
     for edge in edges:
         G.add_edge(edge)
     #print "3prism"
     algorithm = HalinNodeColoring(G, outer=set([0, 2, 3, 5]))
     #algorithm = HalinNodeColoring(G, outer=set([0, 1, 4, 5]))
     #algorithm = HalinNodeColoring(G, outer=set([1, 2, 3, 4]))
     algorithm.run()
     #print "3prism outer", algorithm.outer
     parent = {0: 1, 1: None, 2: 1, 3: 4, 4: 1, 5: 4}
     self.assertEqual(algorithm.parent, parent)
     for node in G.iternodes():
         self.assertNotEqual(algorithm.color[node], None)
     for edge in G.iteredges():
         self.assertNotEqual(algorithm.color[edge.source],
                             algorithm.color[edge.target])
     all_colors = set(algorithm.color[node] for node in G.iternodes())
     self.assertEqual(len(all_colors), 3)
예제 #14
0
 def test_3prism(self):
     N = 6
     G = Graph(N, False)
     edges = [
         Edge(0, 1),
         Edge(1, 2),
         Edge(2, 3),
         Edge(3, 4),
         Edge(4, 5),
         Edge(0, 5),
         Edge(1, 4),
         Edge(2, 0),
         Edge(3, 5)
     ]
     for node in range(N):
         G.add_node(node)
     for edge in edges:
         G.add_edge(edge)
     #print "3prism ..."
     algorithm = HalinGraphTreeDecomposition(G, outer=set([0, 2, 3, 5]))
     #algorithm = HalinGraphTreeDecomposition(G, outer=set([0, 1, 4, 5]))
     #algorithm = HalinGraphTreeDecomposition(G, outer=set([1, 2, 3, 4]))
     algorithm.run()
     #print "3prism outer", algorithm.outer
     parent = {0: 1, 1: None, 2: 1, 3: 4, 4: 1, 5: 4}
     self.assertEqual(algorithm.parent, parent)
     #order = [1, 0, 2, 3, 5, 4]
     order = [4, 0, 2, 3, 5, 1]
     self.assertEqual(algorithm.order, order)
     self.assertEqual(len(algorithm.cliques), G.v() - 3)
예제 #15
0
    def test_dijkstra_for_path_not_found(self):
        print("Testing Matrix 2nd time")
        self.N = 8  # number of nodes
        self.G = Graph(self.N, directed=True)
        self.nodes = range(self.N)
        self.edges = [
            Edge(0, 1, 65),
            Edge(1, 8, 41),
            Edge(1, 2, 35),
            Edge(2, 3, 56),
            Edge(3, 4, 4),
            Edge(3, 6, 20),
            Edge(5, 2, 30),
            Edge(6, 5, 18),
            Edge(6, 7, 15),
            Edge(8, 3, 28)
        ]
        for node in self.nodes:
            self.G.add_node(node)
        for edge in self.edges:
            self.G.add_edge(edge)
        # self.G.show()

        algorithm = Dijkstra(self.G)
        source = 0
        algorithm.run(source)

        target = 7
        path_expected = [0, 1, 8, 3, 6, 7]
        distance_expected = 169
        self.assertEqual(path_expected, algorithm.path(target))
        self.assertEqual(distance_expected, algorithm.distance[target])

        algorithm2 = DijkstraMatrix(self.G)
        algorithm2.run(source)
        self.assertEqual(path_expected, algorithm.path(target))
        self.assertEqual(distance_expected, algorithm.distance[target])

        source = 2
        target = 8
        algorithm.run(source)
        try:
            algorithm.path(target)
        except:
            pass
        else:
            self.fail("Path exception was not raised!")

        algorithm2.run(source)
        try:
            algorithm2.path(target)
        except:
            pass
        else:
            self.fail("Path exception was not raised!")
예제 #16
0
 def setUp(self):
     self.N = 4           # number of nodes
     self.G = Graph(self.N, directed=True) # directed graph
     self.nodes = range(self.N)
     self.edges = [
         Edge(0, 1, 1), Edge(0, 2, 5), Edge(1, 2, 1), Edge(1, 3, 3), 
         Edge(2, 3, 1)]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #17
0
 def setUp(self):
     self.N = 4           # number of nodes
     self.G = Graph(self.N, directed=True)
     self.nodes = ["A", "B", "C", "D"]
     self.edges = [
         Edge("A", "B"), Edge("B", "C"), Edge("C", "A"), 
         Edge("C", "D"), Edge("D", "B")]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #18
0
 def setUp(self):
     self.N = 4           # number of nodes
     self.G = Graph(self.N)
     self.nodes = ["A", "B", "C", "D"]
     self.edges = [
         Edge("A", "B", 2), Edge("B", "C", 4), Edge("C", "A", 6), 
         Edge("C", "D", 3), Edge("D", "B", 5)]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #19
0
 def test_del_edge(self):
     edge1 = Edge(2, 3, 23)
     self.G.add_edge(edge1)
     self.assertEqual(self.G.e(), len(self.edges) + 1)
     self.G.del_edge(edge1)
     self.assertEqual(self.G.e(), len(self.edges))
     #print self.G
     edge2 = Edge(1, 1, 11)
     self.assertTrue(self.G.has_edge(edge2))
     self.G.del_edge(edge2)
     self.assertFalse(self.G.has_edge(edge2))
예제 #20
0
 def setUp(self):
     #  Knuth s.273 t.1
     self.N = 10           # number of nodes
     self.G = Graph(self.N, directed=True)
     self.nodes = range(self.N)
     self.edges = [
         Edge(9, 2), Edge(3, 7), Edge(7, 5), Edge(5, 8), Edge(8, 6), 
         Edge(4, 6), Edge(1, 3), Edge(7, 4), Edge(9, 5), Edge(2, 8)]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #21
0
 def test_borie_matching(self):
     algorithm = BorieMatching(self.G)
     algorithm.run()
     expected1 = set([Edge(1, 3), Edge(2, 5)])
     self.assertEqual(algorithm.cardinality, len(expected1))
     self.assertEqual(algorithm.mate_set, expected1)
     # Testing matching.
     S = set()
     for edge in algorithm.mate_set:
         S.add(edge.source)
         S.add(edge.target)
     self.assertEqual(len(S), 2 * len(algorithm.mate_set))
예제 #22
0
 def test_euler_dfs_with_edges(self):
     algorithm = EulerianCycleDFSWithEdges(self.G)
     algorithm.run(6)
     #expected_cycle = [6, 4, 0, 1, 4, 5, 2, 3, 5, 6]
     expected_cycle = [
         Edge(6, 4), Edge(4, 0), Edge(0, 1), Edge(1, 4),
         Edge(4, 5), Edge(5, 2), Edge(2, 3), Edge(3, 5), Edge(5, 6)]
     self.assertEqual(len(algorithm.eulerian_cycle), len(self.edges))
     self.assertEqual(algorithm.eulerian_cycle, expected_cycle)
예제 #23
0
def find_peo_spgraph2(graph):  # graph has to be connected
    """Find PEO for a supergraph (2-tree) of an sp-graph."""
    if graph.is_directed():
        raise ValueError("the graph is directed")
    order = list()  # PEO of 2-tree
    graph_copy = graph.copy()
    degree2 = set(node for node in graph.iternodes()
                  if graph.degree(node) == 2)  # active nodes with degree 2
    # Dopoki sa wierzcholki stopnia 2 wykonuj odrywanie.
    while degree2:
        source = degree2.pop()
        if graph_copy.degree(source) != 2:
            # Czasem stopien wierzcholka moze sie zmniejszyc!
            continue
        order.append(source)
        node1, node2 = tuple(graph_copy.iteradjacent(source))
        edge = Edge(node1, node2)
        if graph_copy.has_edge(edge):
            # Jezeli ma krawedz, to trzeba poprawic stopnie wierzcholkow,
            # bo przy usuwaniu krawedzi przy source zmniejsza sie stopnie.
            if graph_copy.degree(node1) == 3:
                degree2.add(node1)
            if graph_copy.degree(node2) == 3:
                degree2.add(node2)
        else:  # tu nie trzeba poprawiac stopni
            graph_copy.add_edge(edge)
        # Usuwamy krawedzie z source.
        graph_copy.del_edge(Edge(source, node1))
        graph_copy.del_edge(Edge(source, node2))
    # Sprawdzamy co zostalo.
    degree1 = set(node for node in graph_copy.iternodes()
                  if graph_copy.degree(node) == 1)
    if len(degree1) == 2 and len(order) + 2 == graph.v():
        # Zostala jedna krawedz, dodajemy konce do PEO.
        order.append(degree1.pop())
        order.append(degree1.pop())
    elif len(order) + len(degree1) + 1 == graph.v():
        # Zostala gwiazda, jest jackknife.
        # Szukam centrum gwiazdy.
        for node in graph_copy.iternodes():
            deg = graph_copy.degree(node)
            if deg > 1:
                if deg == len(degree1):
                    break
                else:
                    raise ValueError("not an sp-graph")
        while degree1:
            order.append(degree1.pop())
        order.append(node)
    else:
        raise ValueError("not an sp-graph")
    return order
예제 #24
0
 def setUp(self):
     # The graph from Cormen p.607 changed.
     self.N = 8           # number of nodes
     self.G = Graph(self.N)
     self.nodes = range(self.N)
     self.edges = [
         Edge(0, 4, 2), Edge(0, 1, 3), Edge(1, 4, 12), Edge(1, 5, 4), 
         Edge(5, 2, 5), Edge(5, 6, 6), Edge(2, 6, 7), Edge(2, 3, 8), 
         Edge(2, 7, 9), Edge(3, 7, 11)]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #25
0
 def test_cmp(self):
     self.assertTrue(self.edge1 == Edge(2, 4))
     self.assertFalse(self.edge1 == self.edge3)
     self.assertTrue(self.edge1 != self.edge3)
     self.assertFalse(self.edge1 != Edge(2, 4))
     self.assertTrue(self.edge1 < self.edge3)
     self.assertFalse(self.edge3 < self.edge4)
     self.assertTrue(self.edge1 <= self.edge3)
     self.assertFalse(self.edge1 <= self.edge4)
     self.assertTrue(self.edge1 > self.edge4)
     self.assertFalse(self.edge1 > self.edge3)
     self.assertTrue(self.edge3 >= self.edge4)
     self.assertFalse(self.edge1 >= self.edge3)
예제 #26
0
 def test_sorted_edge_with_edges(self):
     algorithm = SortedEdgeTSPWithEdges(self.G)
     algorithm.run(0)
     expected_hamiltonian_cycle = [
         Edge(2, 3, 12),
         Edge(3, 0, 35),
         Edge(0, 1, 20),
         Edge(1, 2, 30)
     ]
     self.assertEqual(algorithm.hamiltonian_cycle,
                      expected_hamiltonian_cycle)
     weight = sum(edge.weight for edge in algorithm.hamiltonian_cycle)
     self.assertEqual(weight, self.best_weight)
예제 #27
0
 def test_wheel_true(self):
     v = 10
     G = Graph(v, False)
     for node in range(v):
         G.add_node(node)
     hub = 0
     for node in range(1, v):
         G.add_edge(Edge(hub, node))
         G.add_edge(Edge(node, node+1 if node < v-1 else 1))
     self.assertTrue(is_wheel(G))
     algorithm = WheelGraph(G)
     algorithm.run()
     self.assertEqual(algorithm.hub, hub)
예제 #28
0
 def setUp(self):
     # The graph from Cormen p.666, negative weights.
     self.N = 5           # number of nodes
     self.G = Graph(self.N, directed=True)
     self.nodes = range(self.N)
     self.edges = [
         Edge(0, 1, 6), Edge(0, 3, 7), Edge(1, 3, 8), Edge(1, 2, 5), 
         Edge(1, 4, -4), Edge(2, 1, -2), Edge(3, 2, -3), Edge(3, 4, 9),
         Edge(4, 0, 2), Edge(4, 2, 7)]
     for node in self.nodes:
         self.G.add_node(node)
     for edge in self.edges:
         self.G.add_edge(edge)
예제 #29
0
 def test_repeated_nearest_neighbor_with_edges(self):
     algorithm = RepeatedNearestNeighborTSPWithEdges(self.G)
     algorithm.run(0)
     expected_hamiltonian_cycle = [
         Edge(0, 1, 20),
         Edge(1, 2, 30),
         Edge(2, 3, 12),
         Edge(3, 0, 35)
     ]
     self.assertEqual(algorithm.hamiltonian_cycle,
                      expected_hamiltonian_cycle)
     weight = sum(edge.weight for edge in algorithm.hamiltonian_cycle)
     self.assertEqual(weight, self.best_weight)
예제 #30
0
 def make_wheel(self, n=4, directed=False):
     """Create a weighted wheel graph. The hub is equal to 0."""
     if n < 4:
         raise ValueError("number of nodes must be greater than 3")
     graph = self.cls(n, directed)
     weights = list(range(1, 1 + 2 * n - 2))
     random.shuffle(weights)
     for node in xrange(n):
         graph.add_node(node)
     hub = 0
     for i in xrange(1, n):
         graph.add_edge(Edge(hub, i, weights.pop()))
         graph.add_edge(Edge(i, i + 1 if (i < n - 1) else 1, weights.pop()))
     return graph