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)
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)
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
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
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
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
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))
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)
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)
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])
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)
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)
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)
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)
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!")
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)
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)
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)
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))
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)
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))
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)
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
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)
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)
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)
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)
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)
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)
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