def test_topo_order(self): g = DiGraph(4) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(1, 3) g.add_edge(2, 3) self.assertFalse(HamiltonPathDag(g).has_hamilton_path)
def from_networkx(G): """ Convert a NetworkX graph into a Zen graph object. In creating the object, the NetworkX node object and node/edge data will be copied over (a shallow copy). **Returns**: The return type depends on the input type. * :py:class:`zen.Graph` if the input graph was a :py:class:`networkx.Graph`. * :py:class:`zen.DiGraph` if the input graph was a :py:class:`networkx.DiGraph`. """ Gdest = None if type(G) == networkx.DiGraph: Gdest = DiGraph() elif type(G) == networkx.Graph: Gdest = Graph() else: raise Exception, 'Unable to convert graph object type %s' % str( type(G)) # add nodes for n, nd in G.nodes_iter(data=True): Gdest.add_node(n, nd) # add edges for x, y, ed in G.edges_iter(data=True): Gdest.add_edge(x, y, ed) return Gdest
def from_networkx(G): """ Convert a NetworkX graph into a Zen graph object. In creating the object, the NetworkX node object and node/edge data will be copied over (a shallow copy). **Returns**: The return type depends on the input type. * :py:class:`zen.Graph` if the input graph was a :py:class:`networkx.Graph`. * :py:class:`zen.DiGraph` if the input graph was a :py:class:`networkx.DiGraph`. """ Gdest = None if type(G) == networkx.DiGraph: Gdest = DiGraph() elif type(G) == networkx.Graph: Gdest = Graph() else: raise Exception, 'Unable to convert graph object type %s' % str(type(G)) # add nodes for n,nd in G.nodes_iter(data=True): Gdest.add_node(n,nd) # add edges for x,y,ed in G.edges_iter(data=True): Gdest.add_edge(x,y,ed) return Gdest
class WordLadder: # Create a graph from the file of four letter words def __init__(self, filename): self.word_graph = DiGraph() # Use with for opening file with open(filename) as file: d = defaultdict(list) for line in file: word = line.strip().lower() # Get the word # add 'word' in '_ord', 'w_rd', 'wo_d' and 'wor_' for i in range(4): # we know its 4 letter words temp = word[:i] + '_' + word[i+1:] d[temp].append(word) # from dictionary, make graph for l in d.values(): # For each dictionary list, # add edge between all nodes # in 'wor_', 'work' and 'word' are neighbours for frm in range(len(l)): for to in range(len(l)): if frm != to: self.word_graph.add_edge(l[frm], l[to]) @staticmethod def print_path(previous, from_word, to_word): l = [] node_id = to_word while node_id != from_word: l.append(node_id) node_id = previous[node_id] l.append(from_word) print(l[::-1]) def find_path(self, from_word, to_word): if from_word == to_word: return q = Queue() # q for BFS previous = {} # Previous to store predecessor nodes q.put(from_word) # add the start node to q previous[from_word] = None while not q.empty(): node_id = q.get() start = self.word_graph.vert_list[node_id] for neigh in start.get_neighs(): if neigh in previous: # If neighbour is visited, continue continue previous[neigh] = node_id if neigh == to_word: # Found a path self.print_path(previous, from_word, to_word) return q.put(neigh) # add neighbours to q # end of graph traversal print('No Path')
def test_destination_is_not_reachable_if_path_does_not_exists(): dg = DiGraph() dg.add_nodes_from([1, 2, 3, 4, 5]) dg.add_edge(1, 2) dg.add_edge(2, 3) dg.add_edge(3, 4) assert not is_reachable(dg, 1, 5)
def test_get_path_returns_path_when_path_exists(): dg = DiGraph() dg.add_nodes_from([1, 2, 3, 4, 5]) dg.add_edge(1, 2) dg.add_edge(2, 3) dg.add_edge(3, 4) dg.add_edge(4, 2) assert get_path(dg, 1, 4) == [1, 2, 3, 4]
def test_bfs_on_directed_graph(): dg = DiGraph() dg.add_nodes_from([1, 2, 3, 4, 5]) dg.add_edge(1, 2) dg.add_edge(1, 3) dg.add_edge(2, 4) dg.add_edge(3, 4) assert bfs(dg, 1) == [1, 2, 3, 4]
def test_get_path_raises_path_not_found_error_if_no_path_exists(): dg = DiGraph() dg.add_nodes_from([1, 2, 3, 4, 5]) dg.add_edge(1, 2) dg.add_edge(2, 3) dg.add_edge(3, 4) dg.add_edge(4, 2) with pytest.raises(PathNotFoundError): get_path(dg, 1, 5)
class StronglyConnectedComponent: def __init__(self, g): self.g = g self.rg = None self.done = [False]*self.g.V self.topo_order = [] self.cc_count = 0 self.cc_id = [-1]*self.g.V #Valid id are positive integeres starting from 1 self.generate_reverse_graph() self.populate_topo_order() self.populate_strongly_cc() def populate_topo_order(self): for i in range(self.rg.V): if not self.done[i]: self.topo_util(i) def get_reverse_topo_order(self): return list(reversed(self.topo_order)) def topo_util(self, v): self.done[v] = True for each in self.rg.adj(v): if not self.done[each]: self.topo_util(each) self.topo_order.append(v) def generate_reverse_graph(self): self.rg = DiGraph(self.g.V) for i in range(self.rg.V): for j in self.g.adj(i): self.rg.add_edge(j, i) def populate_strongly_cc(self): self.done = [False]*self.g.V for each in self.get_reverse_topo_order(): if not self.done[each]: self.cc_count += 1 self.cc_dfs(each) def cc_dfs(self, v): self.done[v] = True self.cc_id[v] = self.cc_count for each in self.g.adj(v): if not self.done[each]: self.cc_dfs(each) def get_component_count(self): return self.cc_count def get_component_id(self, v): return self.cc_id[v] def are_strongly_connected(self, v, w): return self.get_component_id(v) == self.get_component_id(w)
def test_length1(self): g = DiGraph(7) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(1, 3) g.add_edge(3, 4) g.add_edge(3, 6) g.add_edge(6, 3) g.add_edge(4, 5) g.add_edge(5, 3) g.add_edge(5, 0) l = SmallestCycle(g).get_smallest_cycle_length() self.assertEqual(l, 2)
def test_strongly_connected(self): g = DiGraph(6) g.add_edge(0, 1) g.add_edge(1, 2) g.add_edge(2, 0) g.add_edge(2, 3) g.add_edge(3, 4) g.add_edge(4, 3) g.add_edge(5, 3) self.assertTrue(DigraphHasReachableVertex(g).has_rechable_vertex())
def test_component_count(self): g = DiGraph(6) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.add_edge(4, 5) g.add_edge(5, 4) self.assertFalse(DigraphHasReachableVertex(g).has_rechable_vertex())
def test_component_count(self): g = DiGraph(6) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.add_edge(4, 5) g.add_edge(5, 4) self.assertEqual(StronglyConnectedComponent(g).get_component_count(), 3)
def test_does_not_exists(self): g = DiGraph(8) g.add_edge(0, 5) g.add_edge(0, 4) g.add_edge(6, 5) g.add_edge(7, 5) g.add_edge(3, 1) g.add_edge(1, 0) g.add_edge(4, 6) v = ReachableVertexDAG(g).get_reachable_vertex() self.assertEqual(v, None)
def test_topo_order(self): g = DiGraph(6) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.add_edge(4, 5) g.add_edge(5, 4) rto = DigraphHasReachableVertex(g).get_reverse_topo_order() self.assertListEqual(rto, [4, 5, 1, 0, 3, 2])
def test_topo_order(self): g = DiGraph(6) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.add_edge(4, 5) g.add_edge(5, 4) rto = StronglyConnectedComponent(g).get_reverse_topo_order() self.assertListEqual(rto, [4, 5, 1, 0, 3, 2])
def test_strongly_connected(self): g = DiGraph(6) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(2, 3) g.add_edge(3, 0) g.add_edge(2, 4) g.add_edge(4, 5) g.add_edge(5, 4) self.assertTrue(StronglyConnectedComponent(g).are_strongly_connected(0, 2)) self.assertTrue(StronglyConnectedComponent(g).are_strongly_connected(3, 2)) self.assertTrue(StronglyConnectedComponent(g).are_strongly_connected(4, 5)) self.assertFalse(StronglyConnectedComponent(g).are_strongly_connected(4, 2))
def from_networkx(G): """ This function converts a graph from a networkx data structure into a Zen graph. """ Gdest = None if type(G) == networkx.DiGraph: Gdest = DiGraph() elif type(G) == networkx.Graph: Gdest = Graph() else: raise Exception, 'Unable to convert graph object type %s' % str(type(G)) # add nodes for n,nd in G.nodes_iter(data=True): Gdest.add_node(n,nd) # add edges for x,y,ed in G.edges_iter(data=True): Gdest.add_edge(x,y,ed) return Gdest
def test_topo_order(self): g = DiGraph(6) g.add_edge(2, 1) g.add_edge(1, 0) g.add_edge(0, 4) g.add_edge(4, 3) g.add_edge(3, 5) self.assertTrue(HamiltonPathDag(g).has_hamilton_path)
def test_no_cycle(self): g = DiGraph(7) g.add_edge(0, 1) g.add_edge(0, 2) g.add_edge(1, 3) g.add_edge(3, 4) g.add_edge(4, 5) l = SmallestCycle(g).get_smallest_cycle_length() self.assertEqual(l, None)
# we need 3 flags (0, 1, 2) to check if there is a cycle. # 0=not visited, 1=in the process, 2=visited for node in g.get_vertices(): visited[node] = 0 # Go through each non-visited node and start a DFS from that node for node in g.get_vertices(): if visited[node] != 2: depth_traversal(g, node, visited, topology) # Reverse the topology and print print(topology[::-1]) return topology[::-1] if __name__ == '__main__': g = DiGraph() g.add_edge(6, 3) g.add_edge(3, 7) g.add_edge(3, 2) g.add_edge(1, 2) g.add_edge(10, 1) # g.add_edge(2, 8) # g.add_edge(5, 9) # g.add_edge(5, 4) # g.add_edge(4, 8) # g.add_edge(8, 6) try: topological_sort(g) except CycleException: print('Graph contains Cycle')
maxim_path = m_path.copy() # NBNBNBNB: Do a copy(). path.pop() visited.remove(neigh) return maxim, maxim_path # If not connected, return (0, []) def maximum_cost_path(g, start, end): # COPIED visited = set() visited.add(start) path = [start] return _maximum_cost_path(g, start, end, visited, path, 0) if __name__ == '__main__': g = DiGraph() g.add_edge(0, 1) g.add_edge(0, 6) g.add_edge(1, 2) g.add_edge(1, 5) g.add_edge(1, 6) g.add_edge(2, 3) g.add_edge(3, 4) g.add_edge(5, 2) g.add_edge(5, 3) g.add_edge(5, 4) g.add_edge(6, 5) g.add_edge(7, 1) g.add_edge(7, 6) print(count_paths(g, 1, 5)) print(paths_with_m_edges(g, 0, 3, 4)) print('***')
return False def cycle_undirected(g): visited = [False] * (g.num_vert + 1) for node in g: # loop through all the nodes if visited[node.key] != True: if cycle_dfs_u(g, node.key, visited, -1): return True print('No cycle') if __name__ == '__main__': g = DiGraph() g.add_edge(3, 2) g.add_edge(4, 5) g.add_edge(5, 2) g.add_edge(5, 3) g.add_edge(3, 1) g.add_edge(6, 5) # cycle_directed(g) g = NGraph() g.add_edge(1, 5) g.add_edge(4, 5) g.add_edge(4, 6) g.add_edge(3, 6) g.add_edge(3, 2) g.add_edge(2, 6) cycle_undirected(g)
class DigraphHasReachableVertex: def __init__(self, g): self.g = g self.rg = None self.done = [False]*self.g.V self.topo_order = [] self.cc_count = 0 self.cc_id = [-1]*self.g.V #Valid id are positive integeres starting from 1 self.generate_reverse_graph() self.populate_topo_order() self.cc_dag = DiGraph(0) self.populate_strongly_cc_dag() def populate_topo_order(self): for i in range(self.rg.V): if not self.done[i]: self.topo_util(i, self.rg) def get_reverse_topo_order(self): return list(reversed(self.topo_order)) def topo_util(self, v, g): self.done[v] = True for each in g.adj(v): if not self.done[each]: self.topo_util(each, g) self.topo_order.append(v) def generate_reverse_graph(self): self.rg = DiGraph(self.g.V) for i in range(self.rg.V): for j in self.g.adj(i): self.rg.add_edge(j, i) def populate_strongly_cc_dag(self): self.done = [False]*self.g.V for each in self.get_reverse_topo_order(): if not self.done[each]: self.cc_count += 1 self.cc_dag.add_vertex() self.cc_dfs(each) def cc_dfs(self, v): self.done[v] = True self.cc_id[v] = self.cc_count-1 for each in self.g.adj(v): if self.done[each] and self.cc_id[each] != self.cc_id[v]: self.cc_dag.add_edge(self.cc_count-1, self.cc_id[each]) if not self.done[each]: self.cc_dfs(each) def has_rechable_vertex(self): zero_degree_count = 0 for i in range(self.cc_dag.V): if len(self.cc_dag.adj(i))==0: zero_degree_count += 1 if zero_degree_count > 1: return False if zero_degree_count == 0: return False return True
class KnightsTour: def __init__(self, row, column): self.board = DiGraph() # Directed graph self.row = row self.column = column for r in range(row): for c in range(column): pos = (r * column) + c # For each position, find the valid moves and add as edges for neigh in self.get_neighs(r, c): self.board.add_edge(pos, neigh) def get_neighs(self, row, column): # For each position, there can be up to 8 valid moves moves = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)] ret = [] for x, y in moves: n_row = row + x n_clm = column + y # If a valid move, add it to return list if 0 <= n_row < self.row and 0 <= n_clm < self.column: neigh = n_row * self.column + n_clm ret.append(neigh) return ret def order_by_avail(self, start, visited): ret = [] node = self.board.vert_list[start] for neigh in node.get_neighs(): if neigh in visited: continue c = 0 for next in self.board.vert_list[neigh].get_neighs(): if next not in visited: c += 1 # Out of for loop. C can be 0 also. Still need to include in ret ret.append((neigh, c)) # wrong because ret.sort return None # return [y[0] for y in ret.sort(key=lambda x:x[1])] return [y[0] for y in sorted(ret, key=lambda x: x[1])] def solve(self, start): visited = set() path = [] # passing of path technique happens with DFS return self._solve(start, path, visited) def _solve(self, start, path, visited): path.append(start) visited.add(start) # mark this node as visited if len(visited) == self.board.num_vert: # Visited all nodes print(path) return 1 count = 0 # for neigh in node.get_neighs(): for neigh in self.order_by_avail(start, visited): if neigh in visited: # neigh may get visited after getting it as list in order_by_avail continue count += self._solve(neigh, path, visited) # if self._solve(neigh, path, visited): # solve using neigh # If solved, Done # return True # Done with start. No path found through it. visited.remove(start) path.pop() return count