def test_ugraph_edges(self): # Checks for antisimetry g = UndirectedGraph.rand(5) self.assertTrue(g.is_antisymmetric()) with self.assertRaises(IsNotUndirectedGraphError): UndirectedGraph(3, [[0, 0], [0, 2], [2, 0], [1, 0]])
def test_adj(self): graph = UndirectedGraph(5, [(0, 1), (2, 3), (0, 4)]) self.assertEqual(graph.adj(0), [1, 4]) self.assertEqual(graph.adj(1), [0]) self.assertEqual(graph.adj(2), [3]) self.assertEqual(graph.adj(3), [2]) self.assertEqual(graph.adj(4), [0])
def explore(graph: UndirectedGraph, reporter: Reporter) -> None: """Naive Bron-Kerbosch algorithm, optimized""" if candidates := graph.connected_vertices(): visit(graph=graph, reporter=reporter, candidates=candidates, excluded=set(), clique=[])
def from_networkx(ngraph): if ngraph.is_directed(): raise NotImplementedError() else: graph = UndirectedGraph(ngraph.number_of_nodes()) for edge in ngraph.edges_iter(): graph.add_edge(int(edge[0]), int(edge[1])) return graph
def test_degeneracy_ordering_nonempty(adjacencies: List[Set[Vertex]]) -> None: g = UndirectedGraph(adjacencies=adjacencies) connected_vertices = g.connected_vertices() ordering = list(degeneracy_ordering(g)) assert set(ordering) == connected_vertices assert all(g.degree(ordering[0]) <= g.degree(v) for v in ordering[1:]) ordering_min1 = list(degeneracy_ordering(g, drop=1)) assert ordering_min1 == ordering[:-1]
def explore(graph: UndirectedGraph, reporter: Reporter) -> None: """Bron-Kerbosch algorithm with pivot of highest degree within remaining candidates chosen from candidates only (IK_GP)""" if candidates := graph.connected_vertices(): visit(graph=graph, reporter=reporter, pivot_choice_X=False, candidates=candidates, excluded=set(), clique=[])
def random_undirected_graph(order: int, size: int) -> UndirectedGraph: adjacencies: List[Set[Vertex]] = [set() for _ in range(order)] print(f"order={order}, size={size}") for v, w in generate_n_edges(order, size): adjacencies[v].add(w) adjacencies[w].add(v) print(adjacencies) g = UndirectedGraph(adjacencies=adjacencies) assert g.order == order assert g.size() == size return g
def test_find_shortest_path(self): dg = UndirectedGraph("A", "B", "C", "D") dg.add_new_edge("A", "B") dg.add_new_edge("B", "D") dg.add_new_edge("B", "C") dg.add_new_edge("A", "C") dg.add_new_edge("C", "D") result = dg.find_shortest_path("A", "D") assert result == [vt("A"), vt("B"), vt("D")] or result == [ vt("A"), vt("C"), vt("D") ]
def degeneracy_ordering(graph: UndirectedGraph, drop: int = 0) -> Generator[Vertex, None, None]: """ Iterate connected vertices, lowest degree first. drop=N: omit last N vertices """ assert drop >= 0 priority_per_node = [-2] * graph.order max_degree = 0 num_candidates = 0 for c in range(graph.order): if degree := graph.degree(c): priority_per_node[c] = degree max_degree = max(max_degree, degree) num_candidates += 1
def setUp(self): self.graph = UndirectedGraph() self.filled_graph = UndirectedGraph() for i in range(6): self.filled_graph.add_vertex(i + 1) self.filled_graph.add_edge(1, 2) self.filled_graph.add_edge(1, 4) self.filled_graph.add_edge(2, 4) self.filled_graph.add_edge(2, 3) self.filled_graph.add_edge(4, 3) self.filled_graph.add_edge(3, 6) self.filled_graph.add_edge(4, 5) self.filled_graph.add_edge(5, 6)
def test_load_graph_duplicate_non_conflicting_lines(self): try: UndirectedGraph( "test/graph-with-duplicate-non-conflicting-lines.csv") except ValueError: self.fail( "Graph file contains duplicate, but non-conflicting edges.")
def main(): graph_filename = input("Graph filename: ") graph = UndirectedGraph(graph_filename) start_node = input("Start node: ") end_node = input("End node: ") shortest_path = graph.shortest_path(start_node, end_node) path = shortest_path['path'] cost = shortest_path['cost'] if path is None: print(f"There is no path connecting {start_node} to {end_node}.") else: print( f"Path from {start_node} to {end_node} is {path_to_string(path)},", f"and have cost {cost}.")
def test_traverse(self): vertexes_names = [] def traverse_visit_callback(vertex): vertexes_names.append(vertex.name) un = UndirectedGraph("A", "B", "C", "D") un.add_new_edge("A", "B") un.add_new_edge("B", "C") un.add_new_edge("C", "D") # bfs un.bfs_traverse("A", traverse_visit_callback) assert vertexes_names == ["A", "B", "C", "D"] vertexes_names = [] # dfs un.dfs_traverse("A", traverse_visit_callback) assert vertexes_names == ["A", "B", "C", "D"]
def journeyToMoon(n, astronaut): ''' Function signature supplied by Hackerrank, and my implementation using supplied arguments: n, astronaut. ''' graph = UndirectedGraph(n, astronaut) subset_sizes = disjoint_subset_sizes(graph) return number_of_pairs(subset_sizes)
def visit(graph: UndirectedGraph, reporter: Reporter, pivot_choice_X: bool, candidates: Set[Vertex], excluded: Set[Vertex], clique: List[Vertex]) -> None: assert all(graph.degree(v) > 0 for v in candidates) assert all(graph.degree(v) > 0 for v in excluded) assert candidates.isdisjoint(excluded) assert len(candidates) >= 1 if len(candidates) == 1: # Same logic as below, stripped down for this common case for v in candidates: neighbours = graph.adjacencies[v] assert neighbours if excluded.isdisjoint(neighbours): reporter.record(clique + [v]) return # Quickly handle locally unconnected candidates while finding pivot remaining_candidates = [] seen_local_degree = 0 for v in candidates: neighbours = graph.adjacencies[v] local_degree = len(candidates.intersection(neighbours)) if local_degree == 0: # Same logic as below, stripped down if neighbours.isdisjoint(excluded): reporter.record(clique + [v]) else: if seen_local_degree < local_degree: seen_local_degree = local_degree pivot = v remaining_candidates.append(v) if seen_local_degree == 0: return if pivot_choice_X: for v in excluded: neighbours = graph.adjacencies[v] local_degree = len(candidates.intersection(neighbours)) if seen_local_degree < local_degree: seen_local_degree = local_degree pivot = v for v in remaining_candidates: neighbours = graph.adjacencies[v] assert neighbours if pivot not in neighbours: candidates.remove(v) if neighbouring_candidates := candidates.intersection(neighbours): neighbouring_excluded = excluded.intersection(neighbours) visit(graph=graph, reporter=reporter, pivot_choice_X=pivot_choice_X, candidates=neighbouring_candidates, excluded=neighbouring_excluded, clique=clique + [v]) elif excluded.isdisjoint(neighbours): reporter.record(clique + [v]) excluded.add(v)
def testIndependentSet(self): n = 100 e = 5 * n g = UndirectedGraph() for i in range(e): u = int(random() * n) v = int(random() * n) if u == v: continue if not g.contains(u): g.add_node(u) if not g.contains(v): g.add_node(v) g.connect(u, v) ind_set = g.independent_set(8) for i in ind_set: neighbors = g.e[i] self.assertEqual(neighbors.intersection(ind_set), set([]))
def read_random_graph(orderstr: str, size: Optional[int]) -> Tuple[UndirectedGraph, int]: order = to_int(orderstr) fully_meshed_size = order * (order - 1) // 2 if size is None: size = fully_meshed_size elif size > fully_meshed_size: raise ValueError( f"{order} nodes accommodate at most {fully_meshed_size} edges") edges_name = f"random_edges_order_{orderstr}" stats_name = f"random_stats" edges_path = os.path.join(os.pardir, "data", edges_name + ".txt") stats_path = os.path.join(os.pardir, "data", stats_name + ".txt") adjacencies = read_edges(edges_path, orderstr, order, size) clique_count = read_stats(stats_path, orderstr, size) g = UndirectedGraph(adjacencies=adjacencies) assert g.order == order assert g.size() == size return g, clique_count
def dijkstra(g: UndirectedGraph, initial_node: int = 0) -> List[int]: """ Initialise all distances to infinity, except for initial_node which is 0. For each unseen vertex: - cur: vertex with minimal distance. - Mark cur as seen. - For each unseen neighbour of cur: - alt: cumulative distance to cur + distance to neighbour. - If alt < dist[neighbour]: - Set dist[neighbour] = alt - Set prev[neighbour] = cur # We have essentially found a better way to reach this neighbour. # We progressively update this until we have the best way # to reach this node from our initial node. """ dist = [math.inf for _ in range(g.num_vertices)] dist[initial_node] = 0 prev = [None for _ in range(g.num_vertices)] unseen_vertices = [v for v in range(g.num_vertices)] while unseen_vertices: min_node, min_value = unseen_vertices[0], dist[0] for v in unseen_vertices: if dist[v] < min_value: min_node, min_value = v, dist[v] cur = min_node unseen_vertices.remove(cur) for neighbour in g.get_neighbours(cur): if neighbour in unseen_vertices: alt = dist[cur] + g.get_weight(cur, neighbour) if alt < dist[neighbour]: dist[neighbour] = alt prev[neighbour] = cur return dist, prev
def test_simple(self): graph = UndirectedGraph(4) graph.add(0, 1, 10) graph.add(0, 2, 4) graph.add(1, 2, 5) graph.add(1, 3, 6) graph.add(2, 3, 5) value = stoer_wagner(graph) expected_value = 11 # (0, 1, 2) & 3 self.assertEqual(value, expected_value)
def __init__(self): self.walls = {} self.starts = [] self.goals = [] self.keys = [] self.max_cols = None self.max_rows = None self.undirected_graph = UndirectedGraph() self.directed_graph = DirectedGraph() self.distance_node = {} self.node_distance = {}
def createEdge(self, vertex): vertexLoc = vertex.data try: boundary = self.whichBoundary(vertex) if boundary == 'BOTTOMRIGHT': return for rowOffset, colOffset in MOVES[boundary]: v = self.vertices.find_by_data( (vertexLoc[0] + rowOffset, vertexLoc[1] + colOffset)) edge = UndirectedGraph.Edge(1, vertex, v) self.add_edge(edge) except KeyError: return
def test_adjacency_matrix(self): ug = UndirectedGraph("A", "B", "C", "D") ug.add_new_edge("A", "B") ug.add_new_edge("B", "C") ug.add_new_edge("C", "D") assert ug.adjacency_matrix == [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]
def test_create(self): ug = UndirectedGraph("A", "B", "C") ug.add_new_edge("A", "B") ug.add_new_edge("B", "C") assert [v.name for v in ug.vertexes] == ["A", "B", "C"] assert ug.adjacency_dict == { vt("A"): [vt("B")], vt("B"): [vt("A"), vt("C")], vt("C"): [vt("B")] } with pytest.raises(exceptions.VertexNotExistError): ug.get_vertex_by_name("E") with pytest.raises(exceptions.VertexNotExistError): ug.add_new_edge("C", "E")
class SymmetricHopfieldNetwork(object): """ The SymmetricHopfieldNetwork is a edge weighted graph with binary units on the vertecies. The energy of the network is calculated by adding the edge weight between two activated units and then adding a bias term to activated units. """ weights = None # EdgeWeightedGraph units = None biases = None def __init__(self, V): self.weights = UndirectedGraph(V) self.units = numpy.random.random(V) < 0.5 self.biases = numpy.zeros(V) @property def size(self): return len(self.units) @property def polarization(self): """Average number of activated units.""" return numpy.mean(self.units) @property def gaps(self): """Energy gaps for each unit to go from True --> False.""" return self.biases + self.weights.matrix.dot(self.units) @property def energy(self): """Total energy of the network.""" return numpy.dot( self.units, self.biases + 0.5 * self.weights.matrix.dot(self.units)) def __str__(self): ret = 'Units: ' + self.units.__str__() + linesep ret += 'Biases: ' + self.biases.__str__() + linesep ret += 'Weights: ' + self.weights.__str__() + linesep ret += 'Energy: ' + self.energy.__str__() + linesep return ret
class SymmetricHopfieldNetwork(object): """ The SymmetricHopfieldNetwork is a edge weighted graph with binary units on the vertecies. The energy of the network is calculated by adding the edge weight between two activated units and then adding a bias term to activated units. """ weights = None # EdgeWeightedGraph units = None biases = None def __init__(self, V): self.weights = UndirectedGraph(V) self.units = numpy.random.random(V) < 0.5 self.biases = numpy.zeros(V) @property def size(self): return len(self.units) @property def polarization(self): """Average number of activated units.""" return numpy.mean(self.units) @property def gaps(self): """Energy gaps for each unit to go from True --> False.""" return self.biases + self.weights.matrix.dot(self.units) @property def energy(self): """Total energy of the network.""" return numpy.dot(self.units, self.biases + 0.5 * self.weights.matrix.dot(self.units)) def __str__(self): ret = 'Units: ' + self.units.__str__() + linesep ret += 'Biases: ' + self.biases.__str__() + linesep ret += 'Weights: ' + self.weights.__str__() + linesep ret += 'Energy: ' + self.energy.__str__() + linesep return ret
def visit(graph: UndirectedGraph, reporter: Reporter, candidates: Set[Vertex], excluded: Set[Vertex], clique: List[Vertex]) -> None: assert all(graph.degree(v) > 0 for v in candidates) assert all(graph.degree(v) > 0 for v in excluded) assert candidates.isdisjoint(excluded) assert candidates while candidates: v = candidates.pop() neighbours = graph.adjacencies[v] neighbouring_candidates = candidates.intersection(neighbours) if neighbouring_candidates: neighbouring_excluded = excluded.intersection(neighbours) visit(graph, reporter, candidates=neighbouring_candidates, excluded=neighbouring_excluded, clique=clique + [v]) elif excluded.isdisjoint(neighbours): reporter.record(clique + [v]) excluded.add(v)
def build_graph(adj, features, labels): edges = np.array(adj.nonzero()).T y_values = np.array(labels.nonzero()).T domain_labels = [] for i in range(labels.shape[1]): domain_labels.append("c" + str(i)) # create graph graph = UndirectedGraph() id_obj_map = [] for i in range(adj.shape[0]): n = Node(i, features[i, :], domain_labels[y_values[i, 1]]) graph.add_node(n) id_obj_map.append(n) for e in edges: graph.add_edge(Edge(id_obj_map[e[1]], id_obj_map[e[0]])) return graph, domain_labels
def createVertices(self): for r in range(self.size): for c in range(self.size): vertex = UndirectedGraph.Vertex((r, c)) self.add_vertex(vertex)
if child not in self.depth: # (node -> child) is a forward edge self.dfs(child, current_depth + 1) self.low[node] = min(self.low[node], self.low[child]) self._edge_stack.append((node, child)) if self.low[child] >= current_depth: self.articulations.add(node) # Each articulation point closes a biconnected component. self._current_bcc += 1 while self._edge_stack: i, j = self._edge_stack[-1] if max(self.depth[i], self.depth[j]) > current_depth: self.bcc[self._edge_stack.pop()] = self._current_bcc else: break if self.low[child] > current_depth: self.bridges.append((node, child)) elif self.depth[child] < current_depth - 1: # (node -> child) is a back edge, update low[node] self.low[node] = min(self.low[node], self.depth[child]) self._edge_stack.append((node, child)) if __name__ == '__main__': graph = UndirectedGraph.from_file('graph.in') bc = BiconnectedComponents(graph) bc.compute()
def test_degeneracy_ordering_empty() -> None: g = UndirectedGraph(adjacencies=[]) assert list(degeneracy_ordering(g)) == [] assert list(degeneracy_ordering(g, drop=1)) == []
class FileLoader(object): def __init__(self): self.walls = {} self.starts = [] self.goals = [] self.keys = [] self.max_cols = None self.max_rows = None self.undirected_graph = UndirectedGraph() self.directed_graph = DirectedGraph() self.distance_node = {} self.node_distance = {} def read_map(self, file_name): print 'Reading File' f = open(file_name, 'r') # Reading walls: [row, col, up, left, down, right] print '\t> Parsing walls' [self.max_rows, self.max_cols] = f.readline().split(' ') self.max_rows = int(self.max_rows) self.max_cols = int(self.max_cols) for i in range(0, self.max_rows*self.max_cols): data = f.readline().split(' ') print 'data: ', data data = map(int, data) self.walls[(data[0],data[1])] = (data[2],data[3],data[4], data[5]) # Reading starts print '\t> Parsing ', f.readline() MAX_START = int(f.readline()) for i in range(0, MAX_START): data = f.readline().split(' ') if data[2][0] == 'u': orientation = 0 elif data[2][0] == 'l': orientation = 1 elif data[2][0] == 'd': orientation = 2 else: orientation = 3 self.starts.append((int(data[0]),int(data[1]),orientation)) # Reading Goals print '\t> Parsing ', f.readline() MAX_GOALS = int(f.readline()) for i in range(0, MAX_GOALS): data = f.readline().split(' ') row = int(data[0]) col = int(data[1]) self.goals.append((row,col)) # Reading Keys print '\t> Parsing ', f.readline() MAX_KEYS = int(f.readline()) for i in range(0, MAX_KEYS): data = f.readline().split(' ') row = int(data[0]) col = int(data[1]) self.keys.append((row,col)) f.close() def generate_undirected_graph(self): orientations = [Orientation.up, Orientation.left, Orientation.down, Orientation.right] for w in self.walls.keys(): row = w[0] col = w[1] for o in orientations: self.undirected_graph.add_node((row,col,o)) self.undirected_graph.add_edge((row,col,Orientation.up), (row,col,Orientation.left)) self.undirected_graph.add_edge((row,col,Orientation.left), (row,col,Orientation.down)) self.undirected_graph.add_edge((row,col,Orientation.down), (row,col,Orientation.right)) self.undirected_graph.add_edge((row,col,Orientation.right), (row,col,Orientation.up)) for node, ws in self.walls.items(): if ws[0] == 0: self.undirected_graph.add_edge((node[0],node[1],Orientation.up), (node[0]+1,node[1],Orientation.up)) if ws[1] == 0: self.undirected_graph.add_edge((node[0],node[1],Orientation.left), (node[0],node[1]-1,Orientation.left)) if ws[2] == 0: self.undirected_graph.add_edge((node[0],node[1],Orientation.down), (node[0]-1,node[1],Orientation.down)) if ws[3] == 0: self.undirected_graph.add_edge((node[0],node[1],Orientation.right), (node[0],node[1]+1,Orientation.right)) def generate_directed_graph(self): orientations = [Orientation.up, Orientation.left, Orientation.down, Orientation.right] for w in self.walls.keys(): row = w[0] col = w[1] for o in orientations: self.directed_graph.add_node((row,col,o)) self.directed_graph.add_edge((row,col,Orientation.up), (row,col,Orientation.left)) self.directed_graph.add_edge((row,col,Orientation.left), (row,col,Orientation.up)) self.directed_graph.add_edge((row,col,Orientation.left), (row,col,Orientation.down)) self.directed_graph.add_edge((row,col,Orientation.down), (row,col,Orientation.left)) self.directed_graph.add_edge((row,col,Orientation.down), (row,col,Orientation.right)) self.directed_graph.add_edge((row,col,Orientation.right), (row,col,Orientation.down)) self.directed_graph.add_edge((row,col,Orientation.right), (row,col,Orientation.up)) self.directed_graph.add_edge((row,col,Orientation.up), (row,col,Orientation.right)) for node, ws in self.walls.items(): if ws[0] == 0: self.directed_graph.add_edge((node[0],node[1],Orientation.up), (node[0]+1,node[1],Orientation.up)) if ws[1] == 0: self.directed_graph.add_edge((node[0],node[1],Orientation.left), (node[0],node[1]-1,Orientation.left)) if ws[2] == 0: self.directed_graph.add_edge((node[0],node[1],Orientation.down), (node[0]-1,node[1],Orientation.down)) if ws[3] == 0: self.directed_graph.add_edge((node[0],node[1],Orientation.right), (node[0],node[1]+1,Orientation.right)) def estimate_distances(self): #print '> Exploring distances' nodes = self.undirected_graph.nodes for node in nodes: #print '\t>>Localization::estimate_distances Node ', node distance = 0 orientation = node[2] aux_node = node test_node = node while True: if orientation == Orientation.up: test_node = (aux_node[0] + 1, aux_node[1], aux_node[2]) elif orientation == Orientation.left: test_node = (aux_node[0], aux_node[1] - 1, aux_node[2]) elif orientation == Orientation.down: test_node = (aux_node[0] - 1, aux_node[1], aux_node[2]) elif orientation == Orientation.right: test_node = (aux_node[0], aux_node[1] + 1, aux_node[2]) if not test_node in self.undirected_graph.edges[aux_node]: #BUG break aux_node = test_node distance = distance + 1 self.distance_node.setdefault(distance, []) self.distance_node[distance].append(node) self.node_distance[node] = distance
def dfs_iterative(graph, start_node): visited = [start_node] stack = [start_node] print('Visited', start_node) while stack != []: popped = stack.pop() if popped not in visited: print('Visited', popped) visited.append(popped) for node in graph.adjacents(popped): if node not in visited: stack.append(node) if __name__ == '__main__': g = UndirectedGraph() g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(0, 3) g.add_edge(1, 4) g.add_edge(1, 5) g.add_edge(2, 6) g.add_edge(2, 7) g.add_edge(3, 7) bfs(g, 0) print('=' * 50) dfs(g, 0) print('=' * 50) dfs_iterative(g, 0)
def remove_independent_set(regions): """ Processes a set of regions, detecting and removing an independent set of vertices from the regions' graph representation, and re-triangulating the resulting holes. Arguments: regions -- a set of non-overlapping polygons that tile some part of the plane Returns: a new set of regions covering the same subset of the plane, with fewer vertices """ # Take note of which points are in which regions points_to_regions = {} for idx, region in enumerate(regions): for point in region.points: if point in points_to_regions: points_to_regions[point].add(idx) continue points_to_regions[point] = set([idx]) # Connect graph g = UndirectedGraph() for region in regions: for idx in range(region.n): u = region.points[idx % region.n] v = region.points[(idx + 1) % region.n] if not g.contains(u): g.add_node(u) if not g.contains(v): g.add_node(v) g.connect(u, v) # Avoid adding points from outer triangle removal = g.independent_set(8, avoid=bounding_triangle.points) # Track unaffected regions unaffected_regions = set([i for i in range(len(regions))]) new_regions = [] for p in removal: # Take note of affected regions affected_regions = points_to_regions[p] unaffected_regions.difference_update(points_to_regions[p]) def calculate_bounding_polygon(p, affected_regions): edges = [] point_locations = {} for j, i in enumerate(affected_regions): edge = set(regions[i].points) edge.remove(p) edges.append(edge) for v in edge: if v in point_locations: point_locations[v].add(j) else: point_locations[v] = set([j]) boundary = [] edge = edges.pop() for v in edge: point_locations[v].remove(len(edges)) boundary.append(v) for k in range(len(affected_regions) - 2): v = boundary[-1] i = point_locations[v].pop() edge = edges[i] edge.remove(v) u = edge.pop() point_locations[u].remove(i) boundary.append(u) return shapes.Polygon(boundary) # triangulate hole poly = calculate_bounding_polygon(p, affected_regions) triangles = spatial.triangulatePolygon(poly) for triangle in triangles: self.dag.add_node(triangle) for j in affected_regions: region = regions[j] self.dag.connect(triangle, region) new_regions.append(triangle) for i in unaffected_regions: new_regions.append(regions[i]) return new_regions
def __init__(self, V): self.weights = UndirectedGraph(V) self.units = numpy.random.random(V) < 0.5 self.biases = numpy.zeros(V)
self._marked[a] = True self.queue.append(a) def has_path_to(self, v: int): return self._marked[v] def path_to(self, v: int): if self.has_path_to(v) == False: return None path = [] x = v while x != self._s: path.append(x) x = self._edgeto[x] path.append(self._s) for i in reversed(path): print(f"{i}->", end='') def marked(self, v: int): return self._marked[v] G1 = UndirectedGraph(5) G1.add_edge(0, 1) G1.add_edge(1, 2) G1.add_edge(2, 3) print(G1) bfs = BFS(G1, 0) print(bfs.has_path_to(3)) print(bfs.path_to(4)) print(bfs.path_to(3))
def create_map(self, file_name): walls = {} print 'Reading File' f = open(file_name, 'r') # Reading walls: [row, col, up, left, down, right] print '\t> Parsing walls' [MAX_ROW, MAX_COL] = f.readline().split(' ') MAX_ROW = int(MAX_ROW) MAX_COL = int(MAX_COL) for i in range(0, MAX_ROW*MAX_COL): data = f.readline().split(' ') print 'data: ', data data = map(int, data) walls[(data[0],data[1])] = (data[2],data[3],data[4], data[5]) f.close() # Generating graph print 'Generating graph' graph = UndirectedGraph() for i in range(0, MAX_ROW): for j in range(0, MAX_COL): graph.add_node((i,j,Orientation.up)) graph.add_node((i,j,Orientation.left)) graph.add_node((i,j,Orientation.down)) graph.add_node((i,j,Orientation.right)) graph.add_edge((i,j,Orientation.up), (i,j,Orientation.left)) graph.add_edge((i,j,Orientation.left), (i,j,Orientation.down)) graph.add_edge((i,j,Orientation.down), (i,j,Orientation.right)) graph.add_edge((i,j,Orientation.right), (i,j,Orientation.up)) for node, ws in walls.items(): if ws[0] == 0: graph.add_edge((node[0],node[1],Orientation.up), (node[0]+1,node[1],Orientation.up)) if ws[1] == 0: graph.add_edge((node[0],node[1],Orientation.left), (node[0],node[1]-1,Orientation.left)) if ws[2] == 0: graph.add_edge((node[0],node[1],Orientation.down), (node[0]-1,node[1],Orientation.down)) if ws[3] == 0: graph.add_edge((node[0],node[1],Orientation.right), (node[0],node[1]+1,Orientation.right)) return graph
class TestUndirectedGraphMethods(unittest.TestCase): def setUp(self): self.graph = UndirectedGraph() self.filled_graph = UndirectedGraph() for i in range(6): self.filled_graph.add_vertex(i + 1) self.filled_graph.add_edge(1, 2) self.filled_graph.add_edge(1, 4) self.filled_graph.add_edge(2, 4) self.filled_graph.add_edge(2, 3) self.filled_graph.add_edge(4, 3) self.filled_graph.add_edge(3, 6) self.filled_graph.add_edge(4, 5) self.filled_graph.add_edge(5, 6) def test_adjacent(self): # Edge does exist. self.assertTrue(self.filled_graph.adjacent(1, 2)) # Edge does not exist. self.assertFalse(self.filled_graph.adjacent(1, 3)) # Vertices to test do not exist. self.assertFalse(self.filled_graph.adjacent(5, 8)) def test_neighbors(self): self.assertCountEqual(self.filled_graph.neighbors(4), [1, 2, 3, 5]) self.assertCountEqual(self.filled_graph.neighbors(6), [3, 5]) self.assertEqual(self.filled_graph.neighbors(199), []) def test_add_vertex(self): old_len = len(self.graph) self.graph.add_vertex(0) self.assertEqual(len(self.graph), old_len + 1) def test_remove_vertex(self): # Remove a vertex that exists and verify its neighbors are updated. target = 6 old_len = len(self.filled_graph) self.filled_graph.remove_vertex(target) self.assertEqual(len(self.filled_graph), old_len - 1) self.assertNotIn(target, self.filled_graph.vertices) self.assertNotIn(target, self.filled_graph.neighbors(3)) self.assertNotIn(target, self.filled_graph.neighbors(5)) # Attempt to remove a vertex that doesn't exist. target = 100 old_len = len(self.filled_graph) self.filled_graph.remove_vertex(target) self.assertEqual(len(self.filled_graph), old_len) self.assertNotIn(target, self.filled_graph.vertices) def test_add_edge(self): # Add edge between existing vertices. self.assertFalse(self.filled_graph.adjacent(2, 6)) self.filled_graph.add_edge(2, 6) self.assertTrue(self.filled_graph.adjacent(2, 6)) # Attempt to add edge to vertex that doesn't exist. self.filled_graph.add_edge(2, 100) self.assertNotIn(100, self.filled_graph.neighbors(2)) def test_remove_edge(self): # Remove existing edge. self.assertIn(3, self.filled_graph.neighbors(6)) self.filled_graph.remove_edge(3, 6) self.assertNotIn(3, self.filled_graph.neighbors(6)) # Attempt to remove non-existing edge. self.assertNotIn(1, self.filled_graph.neighbors(5)) self.filled_graph.remove_edge(1, 5) self.assertNotIn(1, self.filled_graph.neighbors(5))