def show_graph(g: Graph): """ Displays the graph g. :param g: the graph to display """ vertices = g.vertices() edges = g.edges() dg = nx.DiGraph() dg.add_nodes_from(vertices, label=vertices) dg.add_weighted_edges_from([ (edge._origin, edge._destination, edge.element()) for edge in edges ]) plt.plot() layout = nx.circular_layout(dg) nx.draw(dg, layout, with_labels=True, connectionstyle='arc3, rad = 0.15') labels = nx.get_edge_attributes(dg, "weight") for key, weight in labels.items(): labels[key] = round(labels[key], 2) nx.draw_networkx_edge_labels(dg, pos=layout, font_color='b', edge_labels=labels, label_pos=0.25, font_size=8) plt.show()
def find_negative_cycle( graph: Graph, source: str) -> Tuple[bool, Optional[List[Graph.Edge]]]: """ Finds a negative cycle starting at source in graph. :param graph: the graph where source is :param source: the starting node of the cycle to find :return: found: True if a negative cycle exists, False otherwise cycle: the list of edges representing the cycle. It is None if found is False. """ # Step 1: Find all neighbors outgoing from source neighbors = { edge.opposite(source): edge for edge in graph.incident_edges(source, outgoing=True) } # Step 2: Find minimum edge weight in the graph minimum_edge_weight = min(edge.element() for edge in graph.edges()) # Step 3: Make all edges positive for edge in graph.edges(): edge._element += abs(minimum_edge_weight) # Step 4: Call compute_shortest_path from each vertex in neighbors to source paths = { vertex: compute_shortest_path(graph, vertex, source) for vertex in neighbors } # Step 5: Restore all edges weights for edge in graph.edges(): edge._element -= abs(minimum_edge_weight) # Step 6: Close cycles for vertex, path in paths.items(): if len(path) == 0: continue path_weight = sum(edge.element() for edge in path) first_edge = neighbors[vertex] first_weight = first_edge.element() cycle_weight = first_weight + path_weight cycle = [first_edge] + path if cycle_weight < 0: return True, cycle return False, None