def __init__(self, mode="directed"): ''' Selects (un)directed graph mode. ''' self._mode = mode if mode == "directed" else "undirected" self._adjlist = AdjacencyList() log.info("running in mode: {}".format(self._mode))
def test_adjacency_matrix(self): for table in [ # no edges ([],[],[[]]), (["a"], [], [ [inf] ]), (["a","b"], [], [ [inf]*2, [inf]*2 ]), (["a","b","c"], [], [ [inf]*3, [inf]*3, [inf]*3 ]), # with edges (1 node) (["a"], [("a","a",1)], [ [1] ]), (["a"], [("a","a",2)], [ [2] ]), # with edges (2 nodes) (["a","b"], [("a","a",1)], [ [1,inf], [inf,inf] ]), (["a","b"], [("a","a",1),("a","b",2)], [ [1,2], [inf,inf] ]), (["a","b"], [("a","a",1),("a","b",2),("b","a",3)], [ [1,2], [3,inf] ]), (["a","b"], [("a","a",1),("a","b",2),("b","a",3),("b","b",4)], [ [1,2], [3,4] ]), (["a","b"], [("a","b",2),("b","a",3),("b","b",4)], [ [inf,2], [3,4] ]), (["a","b"], [("b","a",3),("b","b",4)], [ [inf,inf], [3,4] ]), (["a","b"], [("b","b",4)], [ [inf,inf], [inf,4] ]), # with edges (3 nodes) (["a","b","c"], [("a","a",9),("b","b",2),("c","c",13)], [ [9,inf,inf], [inf,2,inf], [inf,inf,13] ]), (["a","b","c"], [("a","a",9),("a","c",1),("b","b",2),("c","a",7),("c","c",13)], [ [9,inf,1], [inf,2,inf], [7,inf,13] ]), # with edges (4 nodes) (["a","b","c","d"], [("a","b",1),("b","a",4),("b","d",2),("c","c",11),("d","a",3),("d","b",1)], [ [inf,1,inf,inf], [4,inf,inf,2], [inf,inf,11,inf], [3,1,inf,inf] ]), ]: in_nodes, in_edges, want = table l = AdjacencyList() for name in in_nodes: l = l.add_node(name) for (src, dst, weight) in in_edges: l = l.add_edge(src, dst, weight) self.assertEqual(l.adjacency_matrix(), want, "Added nodes {}, added edges {}".format(in_nodes, in_edges))
def test_edge_cardinality(self): for table in [ ([], [], 0), (["a"], [], 0), (["a","b"], [], 0), (["a"], [("a","a")], 1), (["a","b"], [("a","a")], 1), (["a","b"], [("a","a"),("a","b")], 2), (["a","b"], [("a","a"),("b","a")], 2), (["a","b"], [("a","a"),("b","b")], 2), (["a","b"], [("a","a"),("a","b"),("b","a")], 3), (["a","b"], [("a","a"),("a","b"),("b","b")], 3), (["a","b"], [("a","a"),("b","a"),("b","b")], 3), (["a","b"], [("a","a"),("a","b"),("b","a"),("b","b")], 4), (["a","b","c"], [("a","b"),("b","b"),("b","c"),("c","a"),("c","c")], 5), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a"),("c","c")], 6), (["a","b","c"], [("a","a"),("a","b"),("a","c"),("b","b"),("b","c"),("c","a"),("c","c")], 7), (["a","b","c"], [("a","a"),("a","b"),("a","c"),("b","a"),("b","b"),("b","c"),("c","a"),("c","c")], 8), (["a","b","c"], [("a","a"),("a","b"),("a","c"),("b","a"),("b","b"),("b","c"),("c","a"),("c","b"),("c","c")], 9), ]: in_nodes, in_edges, want = table l = AdjacencyList() for name in in_nodes: l = l.add_node(name) for (src, dst) in in_edges: l = l.add_edge(src, dst) self.assertEqual(l.edge_cardinality(), want, "Added nodes {}, added edges {}".format(in_nodes, in_edges))
def test_find_edge(self): for table in [ ([], [], ("a","a"), False), ([], [], ("a","b"), False), ([], [], ("b","a"), False), (["a"], [], ("a","a"), False), (["a"], [], ("a","b"), False), (["a"], [], ("b","a"), False), (["a"], [("a","a")], ("a","a"), True), (["a"], [("a","a")], ("a","b"), False), (["a"], [("a","a")], ("b","a"), False), (["a","b"], [], ("a","a"), False), (["a","b"], [], ("a","b"), False), (["a","b"], [], ("b","a"), False), (["a","b"], [("a","b"),("b","b")], ("a","a"), False), (["a","b"], [("a","b"),("b","b")], ("a","b"), True), (["a","b"], [("a","b"),("b","b")], ("b","b"), True), (["a","b"], [("a","b"),("b","b")], ("b","a"), False), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("a","a"), True), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("a","b"), True), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("a","c"), False), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("b","a"), False), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("b","b"), True), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("b","c"), True), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("c","a"), True), (["a","b","c"], [("a","a"),("a","b"),("b","b"),("b","c"),("c","a")], ("c","b"), False), ]: in_nodes, in_edges, target, want = table l = AdjacencyList() for name in in_nodes: l = l.add_node(name) for (src, dst) in in_edges: l = l.add_edge(src, dst) self.assertEqual(l.find_edge(target[0], target[1]), want, "Added nodes {}, added edges {}, find edge {}".format(in_nodes, in_edges, target))
def test_is_empty(self): for table in [ ([], True), (["a"], False), (["a","b"], False), (["b","a"], False), ]: in_sequence, want = table l = AdjacencyList() for name in in_sequence: l = l.add_node(name) self.assertEqual(l.is_empty(), want, "Added nodes {}".format(in_sequence))
def test_node_cardinality(self): for table in [ ([], 0), (["a"], 1), (["a","b"], 2), (["a","b","c"], 3), (["a","b","c","d"], 4), ]: in_sequence, want = table l = AdjacencyList() for name in in_sequence: l = l.add_node(name) self.assertEqual(l.node_cardinality(), want, "Added nodes {}".format(in_sequence))
def test_add_node(self): for in_sequence in [ ([]), (["a"]), (["a","b"]), (["b","a"]), (["a","b","c"]), (["a","c","b"]), (["b","a","c"]), (["b","c","a"]), (["c","a","b"]), (["c","b","a"]), ]: want = sorted(in_sequence) l = AdjacencyList() for name in in_sequence: l = l.add_node(name) self.assertEqual(l.list_nodes(), want, "Added nodes {}".format(in_sequence))
def test_find_node(self): for table in [ ([], "a", False), (["a"], "a", True), (["a"], "b", False), (["a"], "B", False), (["a","b"], "a", True), (["a","b"], "b", True), (["a","b"], "c", False), (["a","b"], "C", False), (["a","b","c"], "a", True), (["a","b","c"], "b", True), (["a","b","c"], "c", True), (["a","b","c"], "d", False), (["a","b","c"], "D", False), ]: in_sequence, target, want = table l = AdjacencyList() for name in in_sequence: l = l.add_node(name) self.assertEqual(l.find_node(target), want, "Added nodes {}, find node '{}'".format(in_sequence, target))
def test_delete_edges(self): for table in [ # empty ([], [], "a", []), # 1 node (["a"], [], "a", []), (["a"], [("a","a",1)], "a", []), #(["a"], [("a","a",1)], "b", [("a","a",1)]), # 2 nodes (["a","b"], [("a","a",1),("a","b",1),("b","a",1),("b","b",1)], "a", [("a","b",1),("b","b",1)]), (["a","b"], [("a","a",1),("a","b",1),("b","a",1),("b","b",1)], "b", [("a","a",1),("b","a",1)]), (["a","b"], [("a","a",1),("a","b",1),("b","a",1),("b","b",1)], "c", [("a","a",1),("a","b",1),("b","a",1),("b","b",1)]), # 3 nodes (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1),("c","c",1)], "a", [("a","b",1),("a","c",1),("b","b",1),("b","c",1),("c","b",1),("c","c",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1),("c","c",1)], "b", [("a","a",1),("a","c",1),("b","a",1),("b","c",1),("c","a",1),("c","c",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1),("c","c",1)], "c", [("a","a",1),("a","b",1),("b","a",1),("b","b",1),("c","a",1),("c","b",1)]), ]: in_nodes, in_edges, target, want = table l = AdjacencyList() for name in in_nodes: l = l.add_node(name) for (src, dst, weight) in in_edges: l = l.add_edge(src, dst, weight) l = l.delete_edges(target) self.assertEqual(l.list_edges(), want, "Added nodes {}, added edges {}, deleted edges towards node {}".format(in_nodes, in_edges, target))
def test_delete_node(self): for table in [ ([], "a", []), (["a"], "a", []), (["a"], "b", ["a"]), (["a"], "B", ["a"]), (["a","b"], "a", ["b"]), (["a","b"], "b", ["a"]), (["a","b"], "c", ["a","b"]), (["a","b"], "C", ["a","b"]), (["a","b","c"], "a", ["b","c"]), (["a","b","c"], "b", ["a","c"]), (["a","b","c"], "c", ["a","b"]), (["a","b","c"], "d", ["a","b","c"]), (["a","b","c"], "D", ["a","b","c"]), ]: in_sequence, target, want = table l = AdjacencyList() for name in in_sequence: l = l.add_node(name) l = l.delete_node(target) self.assertEqual(l.list_nodes(), want, "Added nodes {}, deleted '{}'".format(in_sequence, target))
def test_add_edge_update(self): for table in [ # 1 node (["a"], [], []), (["a"], [("a","a",1),("a","a",2)], [("a","a",2)]), # 2 nodes (["a","b"], [("a","a",1), ("a","a",2)], [("a","a",2)]), (["a","b"], [("a","a",1), ("a","b",1),("b","a",1), ("a","a",2)], [("a","a",2),("a","b",1),("b","a",1)]), (["a","b"], [("a","a",1), ("a","b",1),("b","a",1), ("a","b",2)], [("a","a",1),("a","b",2),("b","a",1)]), (["a","b"], [("a","a",1), ("a","b",1),("b","a",1), ("b","a",2)], [("a","a",1),("a","b",1),("b","a",2)]), # 3 nodes (["a","b","c"], [("a","b",1),("b","b",1),("b","c",1),("a","b",2)], [("a","b",2),("b","b",1),("b","c",1)]), (["a","b","c"], [("a","b",1),("b","b",1),("b","c",1),("b","b",2)], [("a","b",1),("b","b",2),("b","c",1)]), (["a","b","c"], [("a","b",1),("b","b",1),("b","c",1),("b","c",2)], [("a","b",1),("b","b",1),("b","c",2)]), ]: in_nodes, in_edges, want = table l = AdjacencyList() for name in in_nodes: l = l.add_node(name) for (src, dst, weight) in in_edges: l = l.add_edge(src, dst, weight) self.assertEqual(l.list_edges(), want, "Added nodes {}, added edges {}".format(in_nodes, in_edges))
def test_add_edge(self): for table in [ # no nodes ([], [("a","a",1)], []), ([], [("a","b",1)], []), ([], [("b","a",1)], []), # 1 node (["a"], [], []), (["a"], [("a","a",1)], [("a","a",1)]), (["a"], [("a","b",1)], []), (["a"], [("b","a",1)], []), # 2 nodes (["a","b"], [], []), (["a","b"], [("a","a",1)], [("a","a",1)]), (["a","b"], [("a","a",1), ("a","a",1)], [("a","a",1)]), (["a","b"], [("a","a",1), ("a","b",1)], [("a","a",1),("a","b",1)]), (["a","b"], [("a","a",1), ("a","b",1),("b","a",1)], [("a","a",1),("a","b",1),("b","a",1)]), # 3 nodes (["a","b","c"], [], []), (["a","b","c"], [("a","a",1)], [("a","a",1)]), (["a","b","c"], [("a","a",1),("a","b",1)], [("a","a",1),("a","b",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1)], [("a","a",1),("a","b",1),("a","c",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1)], [("a","a",1),("a","b",1),("a","c",1),("b","a",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1)], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1)], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1)], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1)], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1)]), (["a","b","c"], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1),("c","c",1)], [("a","a",1),("a","b",1),("a","c",1),("b","a",1),("b","b",1),("b","c",1),("c","a",1),("c","b",1),("c","c",1)]), ]: in_nodes, in_edges, want = table for _ in range(10): random.Random(1337).shuffle(in_edges) l = AdjacencyList() for name in in_nodes: l = l.add_node(name) for (src, dst, weight) in in_edges: l = l.add_edge(src, dst, weight) self.assertEqual(l.list_edges(), want, "Added nodes {}, added edges {}".format(in_nodes, in_edges))
class TerminalUI: def __init__(self, mode="directed"): ''' Selects (un)directed graph mode. ''' self._mode = mode if mode == "directed" else "undirected" self._adjlist = AdjacencyList() log.info("running in mode: {}".format(self._mode)) def run(self): ''' Provides a terminal-based UI to perform graph operations. ''' self.display_menu() while True: opt, err = self.get_choice() if err is not None: self.display_error(err) continue if opt == "m": self.display_menu() elif opt == "v": self.display_graph() elif opt == "a": self.add_node() elif opt == "b": self.add_edge() elif opt == "d": self.delete_node() elif opt == "r": self.delete_edge() elif opt == "f": self.find_node() elif opt == "g": self.find_edge() elif opt == "D": self.dijkstra() elif opt == "F": self.floyd() elif opt == "W": self.warshall() elif opt == "P": self.prim() elif opt == "q": break else: log.error("menu case '{}' is missing, aborting".format(opt)) return 1 def menu_options(self): ''' Returns a list of printable menu options. Blank entries are interpreted as new lines, and single characters before the colon as hotkeys. ''' return [ "m: menu", "v: view", "q: quit", "", "a: add node", "b: add edge", "", "d: delete node", "r: delete edge", "", "f: find node", "g: find edge", "", "W: Warshall", "F: Floyd", "D: Dijkstra", "P: Prim", ] def display_menu(self): ''' Shows a menu which is encapsulated between a top rule and a bottom rule. ''' print(self.menu_rule("top", self.menu_width())) for opt in self.menu_options(): print("\t{}".format(opt)) print(self.menu_rule("bot", self.menu_width())) def menu_rule(self, pos, width): ''' Returns a horizontal line using stars or tildes. ''' return ("*" if pos == "top" else "~") * width def menu_width(self): ''' Returns the menu width. ''' return 32 def menu_hotkeys(self): ''' Returns a list of symbols that the menu defined as valid hotkeys. ''' opts = self.menu_options() return [o.split(":")[0] for o in opts if len(o.split(":")[0]) == 1] def get_choice(self): ''' Attempts to read a valid menu option from the user. ''' c, err = self.get_char("menu") if err is not None: return None, err if c not in self.menu_hotkeys(): return None, "invalid choice" return c, None def get_node(self, msg, want): ''' Attempts to read a valid node name from the user. If `want` is False (True), an error is returned if the entered node is a (non-)member. ''' name, err = self.get_char(msg) if err is not None: return None, err if want != self._adjlist.find_node(name): return None, "node '{}' is a {}member".format( name, "non-" if want else "") return name, None def get_char(self, message): ''' Writes a message to stdout and waits for one-character from stdin. ''' buf = input("{}> ".format(message)) if len(buf) != 1: return None, "invalid input (not a single character)" return buf, None def get_int(self, message): ''' Writes a message to stdout and waits for an integer from stdin. ''' buf = input("{}> ".format(message)) try: return int(buf), None except ValueError: return None, "invalid input (not an integer)" def get_weight(self, message, low, high): ''' Writes a message to stdout and waits for an integer in [low,high]. ''' weight, err = self.get_int(message) if err is not None: return None, err if weight < low or weight > high: return None, "invalid input (weight must be in [{},{}])".format( low, high) return weight, None def display_graph(self): ''' Displays graph info. ''' if self._adjlist.is_empty(): self.display_empty() return nodes = self._adjlist.list_nodes() log.debug("all nodes: {}".format(nodes)) log.debug("all edges: {}".format(self._adjlist.list_edges())) self.display_matrix_head(nodes) self.display_matrix_data(nodes, self._adjlist.adjacency_matrix()) self.display_cardinality() def add_node(self): ''' Let the user add a node to the graph. ''' name, err = self.get_node("Enter node name", False) if err is not None: self.display_error(err) return self._adjlist = self._adjlist.add_node(name) def delete_node(self): ''' Let the user delete add a node from the graph. ''' name, err = self.get_node("Enter node name", True) if err is not None: self.display_error(err) return self._adjlist = self._adjlist.delete_edges(name) self._adjlist = self._adjlist.delete_node(name) def add_edge(self): ''' Let the user add an edge to the graph. ''' from_node, err = self.get_node("Enter from node", True) if err is not None: self.display_error(err) return to_node, err = self.get_node("Enter to node", True) if err is not None: self.display_error(err) return weight, err = self.get_weight("Enter weight", 1, 99) if err is not None: self.display_error(err) return self.adj_list = self._adjlist.add_edge(from_node, to_node, weight) if self._mode == "undirected": self._adjlist = self._adjlist.add_edge(to_node, from_node, weight) def delete_edge(self): ''' Let the user delete an edge from the graph. ''' from_node, err = self.get_node("Enter from node", True) if err is not None: self.display_error(err) return to_node, err = self.get_node("Enter to node", True) if err is not None: self.display_error(err) return if not self._adjlist.find_edge(from_node, to_node): self.display_error("edge ({},{}) is non-member".format( from_node, to_node)) return self._adjlist = self._adjlist.delete_edge(from_node, to_node) if self._mode == "undirected": self._adjlist = self._adjlist.delete_edge(to_node, from_node) def find_node(self): ''' Let the user search for a node in the graph. ''' name, err = self.get_char("Enter node name") if err is not None: self.display_error(err) return if self._adjlist.find_node(name): self.display_member_node(name) else: self.display_nonmember_node(name) def find_edge(self): ''' Let the user search for an edge in the graph. ''' from_node, err = self.get_char("Enter from node") if err is not None: self.display_error(err) return to_node, err = self.get_char("Enter to node") if err is not None: self.display_error(err) return if self._adjlist.find_edge(from_node, to_node): self.display_member_edge(from_node, to_node) else: self.display_nonmember_edge(from_node, to_node) def warshall(self): ''' Run Warshall's algorithm. ''' if self._adjlist.is_empty(): self.display_error("graph is empty") return nodes = self._adjlist.list_nodes() self.display_matrix_head(nodes) self.display_matrix_data(nodes, warshall(self._adjlist)) def floyd(self): ''' Run Floyds's algorithm. ''' if self._adjlist.is_empty(): self.display_error("graph is empty") return nodes = self._adjlist.list_nodes() self.display_matrix_head(nodes) self.display_matrix_data(nodes, floyd(self._adjlist)) def dijkstra(self): ''' Run Dijkstra's algorithm. ''' if self._adjlist.is_empty(): self.display_error("graph is empty") return start_node, err = self.get_node("Enter start node", True) if err is not None: self.display_error(err) return dist, prev = dijkstra(self._adjlist, start_node) self.display_sequence_head(self._adjlist.list_nodes()) self.display_sequence_data([ ("distance", dist, None), ("previous", prev, None), ]) def prim(self): ''' Run Prim's algorithm. ''' if self._mode == "directed": self.error("invalid graph mode") return if self._adjlist.is_empty(): self.display_error("graph is empty") return start_node, err = self.get_node("Enter start node", True) if err is not None: self.display_error(err) return lowcost, closest = prim(self._adjlist, start_node) self.display_sequence_head(self._adjlist.list_nodes()) self.display_sequence_data([ ("lowcost", lowcost, None), ("closest", closest, None), ]) self.display_mst_sum(lowcost) def display_mst_sum(self, lowcost): mst_sum = sum([v for v in lowcost if v is not None and v != inf]) print("\tMST sum: {}\n".format(mst_sum)) def display_empty(self): print("\n\tGraph is empty\n") def display_member_node(self, name): print("\tNode {} is a member".format(name)) def display_nonmember_node(self, name): print("\tNode {} is a non-member".format(name)) def display_member_edge(self, from_node, to_node): print("\tEdge ({},{}) is a member".format(from_node, to_node)) def display_nonmember_edge(self, from_node, to_node): print("\tEdge ({},{}) is a non-member".format(from_node, to_node)) def display_sequence_head(self, nodes): print("\n {: ^8}#".format(""), end="") for node in nodes: print(" {: ^3} ".format(node), end="") print("\n ========#" + "=" * 5 * len(nodes)) def display_sequence_data(self, data): for (name, sequence, star_val) in data: print(" {: >8}#".format(name), end="") for v in sequence: print(" {: ^3} ".format("*" if v == star_val else v), end="") print("") print("") def display_matrix_head(self, nodes): print("\n {: ^3}|".format(""), end="") for node in nodes: print(" {: ^3} ".format(node), end="") print("\n----+" + "-" * 5 * len(nodes)) def display_matrix_data(self, nodes, matrix): for name, row in zip(nodes, matrix): print(" {: >3}|".format(name), end="") for col in row: print(" {: ^3} ".format("*" if col == inf else col), end="") print("") print("") def display_cardinality(self): node_cardinality = self._adjlist.node_cardinality() edge_cardinality = self._adjlist.edge_cardinality() if self._mode == "undirected": self_loops = self._adjlist.self_loops() edge_cardinality = int((edge_cardinality - self_loops) / 2 + self_loops) print("node cardinality: {}".format(node_cardinality)) print("edge cardinality: {}".format(edge_cardinality)) print("") def display_error(self, err): print("error> {}".format(err))
def prim(adjlist, start_node): ''' Returns the result of running Prim's algorithm as two N-length lists: 1) lowcost l: here, l[i] contains the weight of the cheapest edge to connect the i:th node to the minimal spanning tree that started at `start_node`. 2) closest c: here, c[i] contains the node name that the i:th node's cheapest edge orignated from. If the index i refers to the start node, set the associated values to None. Pre: adjlist is setup as an undirected graph and start_node is a member. === Example === Suppose that we have the following adjacency matrix: a b c -+----- a|* 1 3 b|1 * 1 c|3 1 * For start node "a", the expected output would then be: l: [ None, 1, 1] c: [ None, 'a', 'b' ] ''' #log.info("TODO: prim()") print("nEW") connected = [start_node] tree = AdjacencyList() # keeps track of added nodes tree.add_node(start_node) # create initial edge and node while are_unconnected(adjlist, connected): curr_edge = Edge( weight=inf) # will be overridden by first legible node nod = adjlist while not nod.is_empty(): # find currently node with shortest edge edg = nod.edges() while not edg.is_empty(): # find best edge in node if not edg.dst() in connected and edg.weight( ) < curr_edge.weight() and edg.dst() != nod.name(): # better edge found, saving curr_node = nod curr_edge = edg edg = edg.tail() nod = nod.tail() print("edge to {} with weight {} from {}".format( curr_edge.dst(), curr_edge.weight(), curr_node.name())) # shortest edge found, find the node in the parallell tre nud = tree while not nud.is_empty(): if nud.name() == curr_node.name(): nud.edges().add(curr_edge.dst(), curr_edge.weight()) nud = nud.tail() tree.add_node(curr_edge.dst()) # find corresponding node for undirectional edge """ nad = tree while not nad.is_empty(): if nad.name() == curr_edge.dst(): nad.edges().add(curr_node.name(), curr_edge.weight()) nad = nad.tail() """ connected.append(curr_edge.dst()) input() print(connected) print(connected) n = adjlist.node_cardinality() l = [inf] * n c = [None] * n nodelist = adjlist.list_nodes() for index, item in enumerate(nodelist): if not item in connected: l[index] = inf c[index] = None continue elif item == start_node: l[index] = None c[index] = None continue nad = tree while not nad.is_empty(): edg = nad.edges() while not edg.is_empty(): l[nodelist.index(edg.dst())] = edg.weight() c[nodelist.index(edg.dst())] = nad.name() edg = edg.tail() nad = nad.tail() print("prim prom") print(l) print("--") print(c) return l, c