def test_is_connected_graph(self): g = DirectedGraph(3) g.connect(1, 2) g.connect(1, 3) g.connect(2, 3) assert not g.is_connected_graph() g.connect(3, 1) assert g.is_connected_graph()
def test_incidence_matrix_file(self): g = DirectedGraph(8) g.add_random_edges(15) before = g.to_adjacency_matrix() g.save("test", "im") g.load("test.im") after = g.to_adjacency_matrix() assert before == after
def example04(): g = DirectedGraph().from_adjacency_list(adjacency_list_2) print(g) rank = page_rank(g, algorithm="matrix") display_pagerank(rank) g.save("pr_matrix_2", "png", engine="dot", color_components=True, alphabetical=True)
def test_incidence_matrix(self): g = DirectedGraph(8) g.add_random_edges(15) before = g.to_adjacency_list() g.from_incidence_matrix(g.to_incidence_matrix()) after = g.to_adjacency_list() assert before == after
def example01(): g = DirectedGraph().from_adjacency_list(adjacency_list_1) print(g) rank = page_rank(g, algorithm="random_walk") display_pagerank(rank) g.save( "pr_random_walk_1", "png", engine="dot", color_components=True, alphabetical=True, )
def test_ford_fulkerson(self, graph, f_max): g = DirectedGraph().from_adjacency_matrix(graph) f = ford_fulkerson(g) gf_max = sum(weight for ((begin, end), weight) in f.items() if begin == 1) assert gf_max == f_max
def test_adjacency_matrix(self): g = DirectedGraph(8) g.add_random_edges(15) before = g.to_adjacency_matrix() g.from_adjacency_matrix(before) after = g.to_adjacency_matrix() assert before == after
def _page_rank_matrix(g: DirectedGraph, d) -> Dict[int, float]: n = len(g.nodes) P = np.zeros((n, n)) A = np.array(g.to_adjacency_matrix()) for i in range(n): for j in range(n): P[i][j] = (1.0 - d) * A[i][j] / g.node_degree(i + 1) + d / float(n) p0 = np.full(n, 1 / n) p1 = np.zeros(n) i = 0 err = float("inf") while err > 1e-11: p1 = p0.dot(P) diff = p1 - p0 err = sum(x**2 for x in diff) p0 = p1 i += 1 print(f"Zbieżność uzyskano po {i} iteracjach.") return {k: p1[k - 1] for k in range(1, n + 1)}
def find_shortest_path_bellman_ford( g: DirectedGraph, source: Node) -> Tuple[Dict[Node, int], Dict[Node, Node]]: """ Przyjmuje graf i zrodlo (wierzcholek). Zwraca: - slownik odleglosci od zrodla - slownik poprzednikow """ predecessors = {} distance = {} for node in g.nodes: distance[node] = float("inf") predecessors[node] = None distance[source] = 0 for _ in range(1, len(g)): for edge in g.edges: u = edge.begin v = edge.end new_distance = distance[u] + g.edge_to_node(u, v).weight old_distance = distance[v] if new_distance < old_distance: distance[v] = new_distance predecessors[v] = u # sprawdz, czy nie ma cykli o ujemnych wagach: for edge in g.edges: u = edge.begin v = edge.end if distance[v] > distance[u] + g.edge_to_node(u, v).weight: print("Wystepuje cykl o ujemnych wagach.") import sys sys.exit(-1) d = {node: int(distance[node]) for node in g.nodes} p = {node: predecessors[node] for node in g.nodes} return d, p
def test_components(self): g = DirectedGraph(3) g.connect(2, 1) g.connect(1, 3) g.connect(3, 1) comps = g.components() assert comps[1] == comps[3] assert comps[2] != comps[1] assert comps[2] != comps[3]
def test_component_list(self): g = DirectedGraph(3) g.connect(2, 1) g.connect(1, 3) g.connect(3, 1) comps = g.component_list() assert [1, 3] in comps.values() assert [2] in comps.values() assert [2, 1] not in comps.values()
def _page_rank_random_walk(g: DirectedGraph, d) -> Dict[int, float]: adj_l = g.to_adjacency_list() visited = {n: 0 for n in g.nodes} current_node = random.choice(list(g.nodes)) N = 0 while N < 100000: if random.random() > d and len(adj_l[current_node]) != 0: current_node = random.choice(list(adj_l[current_node])) else: current_node = random.choice(list(g.nodes)) visited[current_node] += 1 N += 1 return {n: v / sum(visited.values()) for n, v in visited.items()}
def ford_fulkerson(g: DirectedGraph, verbose: bool = False) -> Dict[Tuple[int, int], int]: """Edmonds–Karp implementation""" # sieć rezydualna gf = copy.deepcopy(g) # źródło s: Node = 1 # ujście t: Node = len(g) # przepływ krawędzi f = {(e.begin, e.end): 0 for e in g.edges} step = 0 while True: p = get_trail_to_node(breadth_first_search(gf, s, t), t) if p == [t]: if verbose: print("nie istnieje kolejna ścieżka rozszerzająca") break if verbose: print(f"ścieżka rozszerzająca: {p}") p_edges = [gf.edge_to_node(p[i - 1], p[i]) for i in range(1, len(p))] cf_p = min(e.weight for e in p_edges) if verbose: print(f"przepustowość rezydualna ścieżki: {cf_p}") for edge in p_edges: u = edge.begin v = edge.end if g.is_connected(u, v): f[(u, v)] = f[(u, v)] + cf_p else: f[(v, u)] = f[(v, u)] - cf_p if verbose: print(f"kasowanie przepływu, krawędź: ({u}, {v})") # update residual network weights gf.edges = set() for u, v, c in {(e.begin, e.end, e.weight) for e in g.edges}: w1 = c - f[(u, v)] w2 = f[(u, v)] if w1 != 0: gf.connect(u, v, w1) if w2 != 0: gf.connect(v, u, w2) step += 1 return f
def main(): print("Wywołanie:\n./lab05.py gen save_dir N\n./lab05.py ff save_dir") print("Sieć przykładowa: ./lab05.py gen example\n") if len(sys.argv) < 2: return if sys.argv[1] == "gen": save_dir = sys.argv[2] if save_dir == "example": print(f"Używanie sieci przykładowej (z input_5.pdf)") g = get_example() else: N = int(sys.argv[3]) print(f"Generowanie sieci przepływowej, N={N}") g = generate_network(N=N) prep_dir(save_dir) g.save(save_dir + "/G", file_format="am") g.save(save_dir + "/G", file_format="png", engine="dot") print(f"Zapisano do katalogu {save_dir}") elif sys.argv[1] == "ff": save_dir = sys.argv[2] g = DirectedGraph() g.load(save_dir + "/G.am") # odświeżenie diagramu w razie ręcznej edycji macierzy sąsiedztwa g.save(save_dir + "/G", file_format="png", engine="dot") print(f"Odczytano sieć przepływową z katalogu {save_dir}") f = ford_fulkerson(g, verbose=True) f_max = sum(weight for ((begin, end), weight) in f.items() if begin == 1) print(f"maksymalny przepływ: {f_max}") labels = {(e.begin, e.end): f"{f[(e.begin, e.end)]}/{e.weight}" for e in g.edges} g.save(save_dir + "/G-ff", file_format="png", engine="dot", edge_labels=labels)
def page_rank(g: DirectedGraph, d=0.15, algorithm="matrix") -> Dict[int, float]: """ Zwraca ranking węzłów w grafie skierowanym d - prawdopodobieństwo teleportacji """ if d < 0 or d > 1: raise ValueError("Nieprawidłowa wartość dla prawdopodobieństwa") if g.has_dangling_nodes(): raise ValueError( "Nieprawidłowy graf: posiada wierzchołki bez krawędzi wyjściowych." ) if algorithm == "random_walk": return _page_rank_random_walk(g, d=d) elif algorithm == "matrix": return _page_rank_matrix(g, d=d) else: raise ValueError("Nieprawidłowy wybór algorytmu.")
def get_random_flow_network(N: int) -> DirectedGraph: """ Losowa sieć przepływu N - liczba warstw sieci źródło - Node #1 ujście - Node #len(graph) """ assert N >= 2 print(f"liczba warstw: {N}") # krok 1: tworzenie warstw node_count_in_layer = [1] + [random.randint(2, N) for _ in range(N)] + [1] node_layer = [None] layer_nodes = [] total = 1 for i, count in enumerate(node_count_in_layer): node_layer.extend([i] * count) layer_nodes.append(list(range(total, total + count))) total += count print(f"liczba wierzchołków w warstwie: {node_count_in_layer}") print(f"wierzchołki w warstwie: {layer_nodes}") # krok 2: losowanie krawędzi między warstwami g = DirectedGraph(size=sum(node_count_in_layer)) for i in range(1, N + 1): for node in layer_nodes[i]: # losowa krawędź wchodząca g.connect(random.choice(layer_nodes[i - 1]), node) # losowa krawędź wychodząca g.connect(node, random.choice(layer_nodes[i + 1])) # krok 3: odajemy 2N losowych łuków edges_added = 0 while edges_added < 2 * N: # brak krawędzi wychodzącej z ujścia n1 = random.randint(1, len(g) - 1) # brak krawędzi wchodzącej do źródła n2 = random.randint(2, len(g)) if n1 == n2 or g.is_connected(n1, n2) or g.is_connected(n2, n1): continue g.connect(n1, n2) edges_added += 1 # krok 4: przypisanie każdej krawędzi losowej przepustowości g.assign_random_weights() return g
def get_random_digraph(max_size=20) -> DirectedGraph: size = random.randint(2, max_size) g = DirectedGraph(size) g.connect_random(random.random()) return g
def test_connect(self): g = DirectedGraph(8) n1 = 1 n2 = 2 g.connect(n1, n2) assert g.is_connected(n1, n2) assert not g.is_connected(n2, n1) g.disconnect(n1, n2) assert not g.is_connected(n1, n2) g.connect(n1, n2) g.connect(n2, n1) assert g.is_connected(n1, n2) assert g.is_connected(n2, n1)
def get_example(): exg = DirectedGraph(11) s = 1 a = 2 b = 3 c = 4 d = 5 e = 6 f = 7 g = 8 h = 9 i = 10 t = 11 exg.connect(s, a, 10) exg.connect(s, b, 3) exg.connect(s, c, 6) exg.connect(a, b, 8) exg.connect(a, d, 8) exg.connect(a, e, 6) exg.connect(b, e, 2) exg.connect(b, f, 10) exg.connect(c, d, 9) exg.connect(c, f, 1) exg.connect(d, h, 5) exg.connect(e, d, 1) exg.connect(e, i, 7) exg.connect(f, g, 9) exg.connect(g, t, 7) exg.connect(h, t, 5) exg.connect(i, t, 7) return exg
def load_graph_to_work_on(args): g = DirectedGraph() if args.load: g.load(args.load) elif args.n: g.add_nodes(int(args.n)) if args.l: g.add_random_edges(int(args.l)) elif args.p: g.connect_random(float(args.p)) if args.w is not None: if args.w[0]: g.assign_random_weights(int(args.w[0][0]), int(args.w[0][1])) else: g.assign_random_weights() return g