def setUp(self): g = DirectedGraph() g.add_edge(1, 2, 2) g.add_edge(1, 3, 6) g.add_edge(2, 3, 3) g.add_edge(2, 4, 1) g.add_edge(3, 4, 1) g.add_edge(3, 5, 4) g.add_edge(4, 5, 6) self.graph = g
def test_question_2(self): directed = DirectedGraph() directed.add_edge(1, 2, 2) directed.add_edge(1, 3, 6) directed.add_edge(2, 3, 3) directed.add_edge(2, 4, 1) directed.add_edge(3, 4, 1) directed.add_edge(3, 5, 4) directed.add_edge(4, 5, 6) assert points_are_connected(directed, 1, 5) assert not points_are_connected(directed, 5, 1)
def find_path_with_capacity_dfs(graph: DirectedGraph, current_node, end_node, visited, flows: Dict): """ Finds a path with available capacity from current node to end node Returns none if no such paths exist """ visited.add(current_node) for edge in graph.get_edges(current_node): origin, destination = (edge.a, edge.b) if edge.a == current_node else (edge.b, edge.a) if (edge.weight > flows[edge] and edge.a == current_node) or (0 < flows[edge] and edge.b == current_node): if destination in visited: continue if destination == end_node: return [edge] result = find_path_with_capacity_dfs(graph, destination, end_node, visited, flows) if result: return [edge] + result visited.remove(current_node)
def topological_sort(graph: DirectedGraph) -> List: """ Called Kahns algorithm Sorts the vertices of a graph in a topological order or raises an exception when the graph is cyclical :param graph: The graph to be sorted toplogically """ graph = copy.deepcopy(graph) sorted_nodes = [] nodes = Queue() # Add the nodes without incoming edges to the starting nodes for vertex in graph.get_vertices(): if not graph.has_incoming_edge(vertex): nodes.enqueue(vertex) # Keep removing nodes and edges while nodes with no incoming edges exist while not nodes.is_empty(): node = nodes.dequeue() sorted_nodes.append(node) for edge in graph.get_edges(node)[:]: graph.delete_edge(edge.a, edge.b) if not graph.has_incoming_edge(edge.b): nodes.enqueue(edge.b) if len(list(graph.get_all_edges())): raise RuntimeError('Graph is cyclical') return sorted_nodes
def setUp(self): self.undirected = UndirectedGraph() self.undirected.add_edge(1, 2, 2) self.undirected.add_edge(1, 3, 6) self.undirected.add_edge(2, 3, 3) self.undirected.add_edge(2, 4, 1) self.undirected.add_edge(3, 4, 1) self.undirected.add_edge(3, 5, 4) self.undirected.add_edge(4, 5, 6) self.directed = DirectedGraph() self.directed.add_edge(1, 2, 2) self.directed.add_edge(1, 3, 6) self.directed.add_edge(2, 3, 3) self.directed.add_edge(2, 4, 1) self.directed.add_edge(3, 4, 1) self.directed.add_edge(3, 5, 4) self.directed.add_edge(4, 5, 6)
def test_dijkstra_2(self): g = DirectedGraph() for i in range(100): g.add_vertex(i) for _ in range(250): a = random.randint(1, 100) b = random.randint(1, 100) if a != b: g.add_edge(a, b, random.randint(1, 100)) distance, path = dijkstra(g, 1, 100) if path: cur_dist = 0 start = 1 for i in path: for edge in g.adjacency_list[start]: if edge.b == i: cur_dist += edge.weight break start = i if cur_dist == 0: cur_dist = sys.maxsize assert cur_dist == distance
def ford_fulkerson(graph: DirectedGraph, source, sink) -> Tuple[Dict[Any, int], int]: """ In optimization theory, maximum flow problems involve finding a feasible flow through a single-source, single-sink flow network that is maximum. :param graph: Directed graph with the capacity of each edge as the weight :param source: Source node (from which the flow originates) :param sink: Sink node (where the flow leaves the system """ # Store the current flows in a dict flows = {edge: 0 for edge in graph.get_all_edges()} max_flow = 0 while True: # Find a path with capacity from source to sink and stop is none is available next_path = find_path_with_capacity_dfs(graph, source, sink, set(), flows) if next_path is None: break # Calculate the max flow for the current path current_max_flow = sys.maxsize start = source for edge in next_path: if edge.a == start: current_max_flow = min(current_max_flow, edge.weight - flows[edge]) start = edge.b else: current_max_flow = min(current_max_flow, flows[edge]) start = edge.a # Add this flow to the found path start = source for edge in next_path: if edge.a == start: flows[edge] += current_max_flow start = edge.b else: flows[edge] -= current_max_flow start = edge.a max_flow += current_max_flow # Return the optimal flows per edge and the total max flow return flows, max_flow
class TestGraph(unittest.TestCase): def setUp(self): self.undirected = UndirectedGraph() self.undirected.add_edge(1, 2, 2) self.undirected.add_edge(1, 3, 6) self.undirected.add_edge(2, 3, 3) self.undirected.add_edge(2, 4, 1) self.undirected.add_edge(3, 4, 1) self.undirected.add_edge(3, 5, 4) self.undirected.add_edge(4, 5, 6) self.directed = DirectedGraph() self.directed.add_edge(1, 2, 2) self.directed.add_edge(1, 3, 6) self.directed.add_edge(2, 3, 3) self.directed.add_edge(2, 4, 1) self.directed.add_edge(3, 4, 1) self.directed.add_edge(3, 5, 4) self.directed.add_edge(4, 5, 6) def test_get_edges(self): assert self.undirected.get_all_edges() == self.directed.get_all_edges() assert self.undirected.get_vertices() == self.directed.get_vertices() def test_directed_graph(self): assert len(self.directed.get_successive_vertices(4)) == 1 assert len(self.undirected.get_successive_vertices(4)) == 3 assert self.undirected.edge_exists(4, 3) assert not self.directed.edge_exists(4, 3) self.directed.delete_edge(4, 3) self.undirected.delete_edge(4, 3) assert len(self.directed.get_all_edges()) == len(self.undirected.get_all_edges()) + 1 def test_undirected_graph(self): g = UndirectedGraph()
class TestGraph(unittest.TestCase): def setUp(self): self.undirected = UndirectedGraph() self.undirected.add_edge(1, 2, 2) self.undirected.add_edge(1, 3, 6) self.undirected.add_edge(2, 3, 3) self.undirected.add_edge(2, 4, 1) self.undirected.add_edge(3, 4, 1) self.undirected.add_edge(3, 5, 4) self.undirected.add_edge(4, 5, 6) self.directed = DirectedGraph() self.directed.add_edge(1, 2, 2) self.directed.add_edge(1, 3, 6) self.directed.add_edge(2, 3, 3) self.directed.add_edge(2, 4, 1) self.directed.add_edge(3, 4, 1) self.directed.add_edge(3, 5, 4) self.directed.add_edge(4, 5, 6) def test_get_edges(self): assert self.undirected.get_all_edges() == self.directed.get_all_edges() assert self.undirected.get_vertices() == self.directed.get_vertices() def test_directed_graph(self): assert len(self.directed.get_successive_vertices(4)) == 1 assert len(self.undirected.get_successive_vertices(4)) == 3 assert self.undirected.edge_exists(4, 3) assert not self.directed.edge_exists(4, 3) self.directed.delete_edge(4, 3) self.undirected.delete_edge(4, 3) assert len(self.directed.get_all_edges()) == len( self.undirected.get_all_edges()) + 1 def test_undirected_graph(self): g = UndirectedGraph()