class SymbolDigraph: def __init__(self, file_name, separator): self.__symbols = {} with open(file_name, 'r') as f: for line in f: tokens = line.strip().split(separator) for token in tokens: if token not in self.__symbols: self.__symbols[token] = len(self.__symbols) self.__keys = [0] * len(self.__symbols) for k, v in self.__symbols.items(): self.__keys[v] = k self.__g = Digraph(len(self.__symbols)) with open(file_name, 'r') as f: for line in f: tokens = line.strip().split(separator) v = self.__symbols[tokens[0]] for token in tokens[1:]: self.__g.add_edge(v, self.__symbols[token]) def contains(self, s): return s in self.__symbols def index_of(self, s): return self.__symbols[s] def name_of(self, v): return self.__keys[v] def digraph(self): return self.__g
def has_cycle_b(self): d = Digraph() d.add_edge(1, 2) d.add_edge(2, 3) d.add_edge(3, 1) dc = DirectedCycle(d) self.assertEquals(True, dc.has_cycle())
def graph_from_adj_matrix(matrix): """ Devuelve el Digrafo generado a partir de la matriz de ady. """ graph = Digraph(len(matrix)) for i in range(len(matrix)): for j in range(len(matrix[i])): if matrix[i][j] != 0: graph.add_edge(i, j, matrix[i][j]) return graph
def test_add_edge_to_empty(self): d = Digraph() self.assertEquals(0, d.count_vertices()) d.add_vertice() d.add_vertice() d.add_vertice() d.add_edge(0, 1) d.add_edge(2, 0) self.assertEquals(2, d.count_edges())
def save_dot(self, dot_file): assert self.root is not None g = Digraph(len(self.nodes)) for n in self.nodes: g.set_vertex_label(n.idx, n.op) if n.pred is not None: g.add_edge(n.pred.idx, n.idx) g.save_dot(dot_file)
def save_dot(self, dot_file): g = Digraph(len(self.obj.infos)) for infos in self.obj.infos: n = infos.node g.set_vertex_label(n.idx, get_label(infos)) if n.pred is not None: g.add_edge(n.pred.idx, n.idx) g.save_dot(dot_file)
def test_add_edge(self): """ test add_edge """ dgraph = Digraph() node_list = ['one', 'two', 'three'] for n in node_list: dgraph.add_node(n) dgraph.add_edge(('one', 'two')) self.assertIn('two', dgraph.nodes['one'])
def test4(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [], {1 : 0.8, 0 : 0.2}) bn.set_pd("v2", ["v1"], {1 : {"1" : 0.4, "0" : 0.9}, 0 : {"1" : 0.6, "0" : 0.1}}) bn.set_pd("v3", ["v2"], {1 : {"1" : 0.7, "0" : 0.5}, 0 : {"1" : 0.3, "0" : 0.5}}) evidence = {"v3" : {1 : 1, 0 : 0}} bn.compute_posterior(evidence)
def test6(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [], {"v1_true" : 0.8, "v1_false" : 0.2}) bn.set_pd("v2", ["v1"], {"v2_true" : {"v1_true" : 0.4, "v1_false" : 0.9}, "v2_false" : {"v1_true" : 0.6, "v1_false" : 0.1}}) bn.set_pd("v3", ["v2"], {"v3_true" : {"v2_true" : 0.7, "v2_false" : 0.5}, "v3_false" : {"v2_true" : 0.3, "v2_false" : 0.5}}) evidence = {"v3" : {"v3_true" : 1, "v3_false" : 0}} bn.compute_posterior(evidence)
def test_get_node_order(self): """ Test get_node_order """ dgraph = Digraph() node_list = ['one', 'two', 'three'] for n in node_list: dgraph.add_node(n) if n != 'one': dgraph.add_edge(('one', n)) self.assertEquals(dgraph.get_node_order('one'), 2)
def test_transitivity(self): g = Digraph(edges=[(1, 2), (1, 3), (2, 3), (3, 3)], vertices=[4]) g.add_edge(5, 3) self.assertTrue(g.is_transitive()) g.add_edge(3, 4) self.assertFalse(g.is_transitive()) g.add_edge(5, 4) self.assertFalse(g.is_transitive()) g.add_edge(2, 4) self.assertFalse(g.is_transitive()) g.add_edge(1, 4) self.assertTrue(g.is_transitive())
def test7(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [], {"v1_true" : 1e-300, "v1_false" : 1.0 - 1e-300}) bn.set_pd("v2", ["v1"], {"v2_true" : {"v1_true" : 1e-300, "v1_false" : 1.0 - 1e-300}, "v2_false" : {"v1_true" : 1e-300, "v1_false" : 1.0 - 1e-300}}) bn.set_pd("v3", ["v2"], {"v3_true" : {"v2_true" : 0.7, "v2_false" : 0.5}, "v3_false" : {"v2_true" : 0.3, "v2_false" : 0.5}}) evidence = {"v3" : {"v3_true" : 1, "v3_false" : 0}} post = bn.compute_posterior(evidence) print "Posterior:", post
def test_has_edge(self): """ test has_edge """ dgraph = Digraph() node_list = ['one', 'two', 'three'] for n in node_list: dgraph.add_node(n) if n != 'one': dgraph.add_edge(('one', n)) self.assertTrue(dgraph.has_edge(('one', 'two'))) self.assertTrue(dgraph.has_edge(('one', 'three')))
def save_dot(self, dot_file): g = Digraph(len(self.obj.infos)) for infos in self.obj.infos: n = infos.node if n.pred is not None: g.add_edge(n.pred.idx, n.idx) self.obj.apply(self) for (u, label) in enumerate(self.labels): g.set_vertex_label(u, label) g.save_dot(dot_file)
def test2(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [[0.2, 0.8]]) bn.set_pd("v2", [[0.9, 0.1], [0.6, 0.4]]) bn.set_pd("v3", [[0.5, 0.5], [0.3, 0.7]]) evidence = {"v3" : {0 : 0.0, 1 : 1.0}} bn.compute_posterior(evidence)
def test_del_edge(self): """ Test del_edge """ dgraph = Digraph() node_list = ['one', 'two', 'three'] for n in node_list: dgraph.add_node(n) if n != 'one': dgraph.add_edge(('one', n)) dgraph.del_edge(('one', 'two')) self.assertNotIn('two', dgraph.nodes['one'])
def test_get_neighbors(self): """ test get_neighbors Add a few nodes to a graph, and then add a few neighbors to that node, and check whether get_neighbors returns the expected result """ dgraph = Digraph() node_list = ['one', 'two', 'three'] for n in node_list: dgraph.add_node(n) if n != 'one': dgraph.add_edge(('one', n)) self.assertEquals(dgraph.get_neighbors('one'), ['two', 'three'])
def test3(): dag = Digraph() dag.add_edge("v2", "v1") dag.add_edge("v3", "v1") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", ["v2", "v3"], {0 : {"11" : 0.8, "01" : 0.9, "10" : 0.5, "00" : 0.6}, 0 : {"11" : 0.2, "01" : 0.1, "10" : 0.5, "00" : 0.4}}) bn.set_pd("v2", [], {1 : 0.1, 0 : 0.9}) bn.set_pd("v3", [], {1 : 0.4, 0 : 0.6}) print bn evidence = {} print bn.compute_posterior(evidence)
def test5(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") dag.add_edge("v2", "v4") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [], {0 : 0.5, 1 : 0.5}) bn.set_pd("v2", ["v1"], {0 : {"0" : 0.5, "1" : 0.5}, 1 : {"0" : 0.5, "1" : 0.5}}) bn.set_pd("v3", ["v2"], {0 : {"0" : 0.5, "1" : 0.5}, 1 : {"0" : 0.5, "1" : 0.5}}) bn.set_pd("v4", ["v2"], {0 : {"0" : 0.5, "1" : 0.5}, 1 : {"0" : 0.5, "1" : 0.5}}) print bn evidence = {"v3" : {0 : 0.0, 1 : 1.0}, "v4" : {0 : 0.9, 1 : 0.1}} bn.compute_posterior(evidence)
def test_get_edges(self): """ test get_edges Add a few nodes to a graph, and then add a few edges to the graph. Check whether get_edges returns the expected edges """ dgraph = Digraph() node_list = ['one', 'two', 'three'] for n in node_list: dgraph.add_node(n) if n != 'one': dgraph.add_edge(('one', n)) edges = [('one', 'two'), ('one', 'three')] self.assertEquals(dgraph.get_edges(), edges)
def test3(): dag = Digraph() dag.add_edge("v2", "v1") dag.add_edge("v3", "v1") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", ["v2", "v3"], {0 : {"11" : 0.8, "01" : 0.9, "10" : 0.5, "00" : 0.6}, 0 : {"11" : 0.2, "01" : 0.1, "10" : 0.5, "00" : 0.4}}) bn.set_pd("v2", [], {1 : 0.1, 0 : 0.9}) bn.set_pd("v3", [], {1 : 0.4, 0 : 0.6}) print bn evidence = {} #evidence = {"v1" : {1 : 1, 0 : 0}} bn.compute_posterior(evidence)
def test(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") dag.add_edge("v2", "v4") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [], {0 : 0.6, 1 : 0.4}) bn.set_pd("v2", ["v1"], {0 : {"0" : 0.9, "1" : 0.1}, 1 : {"0" : 0.7, "1" : 0.3}}) bn.set_pd("v3", ["v2"], {0 : {"0" : 0.1, "1" : 0.9}, 1 : {"0" : 0.8, "1" : 0.2}}) bn.set_pd("v4", ["v2"], {0 : {"0" : 0.5, "1" : 0.5}, 1 : {"0" : 0.25, "1" : 0.75}}) print bn evidence = {} bn.compute_posterior(evidence)
def digraph_factory(spec): graph1 = Digraph() graph1.add_vertex('a') graph1.add_vertex('b') graph1.add_vertex('c') graph2 = Digraph() graph2.add_vertex('a') graph2.add_vertex('b') graph2.add_vertex('c') graph2.add_edge('a', 'b') graph2.add_edge('b', 'c') spec_dict = {'no_edge': graph1, 'with_edges': graph2} return spec_dict[spec]
def test(): dag = Digraph() dag.add_edge("v1", "v2") dag.add_edge("v2", "v3") dag.add_edge("v2", "v4") bn = BayesianNetwork() bn.set_dag(dag) bn.set_pd("v1", [], {0 : 0.6, 1 : 0.4}) # bn.set_pd("v1", [], {0 : 0.99, 1 : 0.01}) bn.set_pd("v2", ["v1"], {0 : {"0" : 0.9, "1" : 0.1}, 1 : {"0" : 0.7, "1" : 0.3}}) bn.set_pd("v3", ["v2"], {0 : {"0" : 0.1, "1" : 0.9}, 1 : {"0" : 0.8, "1" : 0.2}}) bn.set_pd("v4", ["v2"], {0 : {"0" : 0.5, "1" : 0.5}, 1 : {"0" : 0.25, "1" : 0.75}}) print bn # evidence = {"v3" : {0 : 0.0, 1 : 1.0}} # evidence = {"v1" : {0 : 0.0, 1 : 1.0}} evidence = {} bn.compute_posterior(evidence)
def build_dag(T, use_tree=True, blast=True, gtg=True): parents, children = findParentsAndChildren(T, ROOT_NODE) dag = Digraph() observed_species = set() ancestors = set() if use_tree: for u in children: ancestors.add(u) for v in children[u]: dag.add_edge(u, v) for u in T: if u not in children: observed_species.add(u) if blast: dag.add_edge(u, get_blast_node_name(u)) if gtg: dag.add_edge(u, get_gtg_node_name(u)) return dag, observed_species, ancestors
def build_dag(T, use_tree = True, blast = True, gtg = True): parents, children = findParentsAndChildren(T, ROOT_NODE) dag = Digraph() observed_species = set() ancestors = set() if use_tree: for u in children: ancestors.add(u) for v in children[u]: dag.add_edge(u, v) for u in T: if u not in children: observed_species.add(u) if blast: dag.add_edge(u, get_blast_node_name(u)) if gtg: dag.add_edge(u, get_gtg_node_name(u)) return dag, observed_species, ancestors
# returns the preorder number of vertex v def pre(self, v): return self._pre[v] # returns the postorder number of vertex v def post(self, v): return self._post[v] # rerurns the vertices in postorder from 0 def postorder(self): return self._postorder # rerurns the vertices in preorder from 0 def preorder(self): return self._preorder # returns reverse postorder from 0 def reverse_postorder(self): return self._postorder[::-1] if __name__ == "__main__": G = Digraph(4) G.add_edge(0, 3) G.add_edge(3, 2) orders = DepthFirstOrder(G) print(orders.postorder()) # [2, 3, 0, 1] print(orders.reverse_postorder()) # [1, 0, 3, 2] print(orders.preorder()) # [0, 3, 2, 1]
def testOverflow(self): d = Digraph(5) d.add_edge(0, 1) self.assertRaises(Exception, d.add_edge, 10, 1)
class Network: session = None engine = None def __init__(self, db): """ Creates a transport network interface between the database and the algorithm. Args: db (str): String describing the database location. """ self.db = db def __enter__(self): """ Startup commands for the context manager. """ engine = create_engine(self.db) Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) self.session = Session() edges = self.session.query(Edge) self._graph = Digraph(len(edges.all())) for edge in edges: if not self._graph.has_edge(edge.stop_from_id, edge.stop_to_id): self._graph.add_edge(DirectedEdge( edge.stop_from_id, edge.stop_to_id, edge.length )) return self def __exit__(self, type, value, traceback): """ Shutdown commands for the context manager. """ if type is not None: pass self.session.commit() self.session.close() @property def stops(self): """ List of stops in the transport network. SQLAlchemy query object. """ return self.session.query(Stop) @property def routes(self): """ List of routes in the transport network. SQLAlchemy query object. """ return self.session.query(Route) @property def graph(self): """ Digraph representing the transport network. """ return self._graph @property def edges(self): """ Edges present in the graph, and routes associated with each edge. SQLAlchemy query object. """ return self.session.query(Edge) @property def route_frequencies(self): """ Frequency tables associated with each route. SQLAlchemy query object. """ return self.session.query(RouteFrequency)
def find_order(word_sorted_list): """ Given a list of words in an alien language in dictionary sorted order, return the alphabetical order of the letters in the alien language. The algorithm is as follows: 1) Find the number of letters in the alphabet, by going 1 pass over the input array. This takes time O(wl). if there are w words and l letters on an avg per word. Lets call the result, alpha 2) Create a digraph with num_vertices = alpha 3) For every pair of consecutive words (word1, word2) in the input list (there are w - 1 pairs in a w-word list), compare letters of word1 & word2 until you find the 1st mismatching character. Add an edge in the digraph from letter in word1 to letter in word2 4) Topologically sort the digraph. This takes time O(V + E) = O(alpha + alpha - 1) Total time = O(wL) + O(1) + O[(w-1)(L)] + O(alpha) = O(wL) where L = avg number of letters per word :param word_sorted_list: :return: """ alphabet = set() for word in word_sorted_list: for letter in word: alphabet.add(letter) num_vertices = len(alphabet) dg = Digraph(num_vertices) # graph takes vertex values as integers, # so using 2 maps for letter -> vertex_id and inverse mapping letter_to_vertex_id_dict = {} vertex_id_to_letter = [] for i in xrange(len(word_sorted_list) - 1): word1 = word_sorted_list[i] word2 = word_sorted_list[i + 1] if len(word1) < len(word2): smaller_word = word_sorted_list[i] else: smaller_word = word_sorted_list[i + 1] for word_index in xrange(len(smaller_word)): if word1[word_index] == word2[word_index]: continue else: letter1 = word1[word_index].lower() letter2 = word2[word_index].lower() vertex1 = _get_vertex_for_letter(letter1, letter_to_vertex_id_dict, vertex_id_to_letter) vertex2 = _get_vertex_for_letter(letter2, letter_to_vertex_id_dict, vertex_id_to_letter) dg.add_edge(vertex1, vertex2) # no need to consider other characters in this word pair, # break out of inner for-loop break # now just do a topological sort of the letters ordered_vertex_ids = topological_sort(dg) lst = [vertex_id_to_letter[vertex] for vertex in ordered_vertex_ids] return ''.join([i for i in lst])
def test_init(self): d = Digraph(13) d.add_edge(2,3) d.add_edge(0,6) d.add_edge(0,1) d.add_edge(2,0) d.add_edge(11,12) d.add_edge(9,12) d.add_edge(9,10) d.add_edge(9,11) d.add_edge(3,5) d.add_edge(8,7) d.add_edge(5,4) d.add_edge(0,5) d.add_edge(6,4) d.add_edge(6,9) d.add_edge(7,6) order = DepthFirstOrder(d) self.assertEquals([0,3,9,10,2,1,4,11,12,5,8,6,7], order.pre) self.assertEquals([0,5,4,1,6,9,11,12,10,2,3,7,8], order.preorder) self.assertEquals([8,2,10,9,0,1,7,11,12,6,5,4,3], order.post) self.assertEquals([4,5,1,12,11,10,9,6,0,3,2,7,8], order.postorder)
def test_remove_vertex_with_edges(self): g = Digraph(edges=[(1, 2), (1, 3), (2, 3), (3, 3)], vertices=[4]) g.add_edge(5, 3) g.remove_vertex(2) self.assertEqual(sorted(g.vertices()), [1, 3, 4, 5]) self.assertEqual(sorted(g.edges()), [(1, 3), (3, 3), (5, 3)])
def test_add_edge(self): g = Digraph(edges=[(1, 2), (1, 3), (2, 3), (3, 3)], vertices=[4]) g.add_edge(5, 3) self.assertEqual(sorted(g.vertices()), [1, 2, 3, 4, 5]) self.assertEqual(sorted(g.edges()), [(1, 2), (1, 3), (2, 3), (3, 3), (5, 3)])
def test_add_edge_to_non_empty(self): d = Digraph(3) d.add_edge(1,2) self.assertEquals(1, len(d.links(1))) self.assertEquals(0, len(d.links(2)))
def has_no_cycle(self): d = Digraph() d.add_edge(2, 3) dc = DirectedCycle(d) self.assertEquals(False, dc.has_cycle())
def find_order(word_sorted_list): """ Given a list of words in an alien language in dictionary sorted order, return the alphabetical order of the letters in the alien language. The algorithm is as follows: 1) Find the number of letters in the alphabet, by going 1 pass over the input array. This takes time O(wl). if there are w words and l letters on an avg per word. Lets call the result, alpha 2) Create a digraph with num_vertices = alpha 3) For every pair of consecutive words (word1, word2) in the input list (there are w - 1 pairs in a w-word list), compare letters of word1 & word2 until you find the 1st mismatching character. Add an edge in the digraph from letter in word1 to letter in word2 4) Topologically sort the digraph. This takes time O(V + E) = O(alpha + alpha - 1) Total time = O(wL) + O(1) + O[(w-1)(L)] + O(alpha) = O(wL) where L = avg number of letters per word :param word_sorted_list: :return: """ alphabet = set() for word in word_sorted_list: for letter in word: alphabet.add(letter) num_vertices = len(alphabet) dg = Digraph(num_vertices) # graph takes vertex values as integers, # so using 2 maps for letter -> vertex_id and inverse mapping letter_to_vertex_id_dict = {} vertex_id_to_letter = [] for i in xrange(len(word_sorted_list) - 1): word1 = word_sorted_list[i] word2 = word_sorted_list[i + 1] if len(word1) < len(word2): smaller_word = word_sorted_list[i] else: smaller_word = word_sorted_list[i + 1] for word_index in xrange(len(smaller_word)): if word1[word_index] == word2[word_index]: continue else: letter1 = word1[word_index].lower() letter2 = word2[word_index].lower() vertex1 = _get_vertex_for_letter(letter1, letter_to_vertex_id_dict, vertex_id_to_letter) vertex2 = _get_vertex_for_letter(letter2, letter_to_vertex_id_dict, vertex_id_to_letter) dg.add_edge(vertex1, vertex2) # no need to consider other characters in this word pair, # break out of inner for-loop break # now just do a topological sort of the letters ordered_vertex_ids = topological_sort(dg) lst = [vertex_id_to_letter[vertex] for vertex in ordered_vertex_ids] return ''.join([i for i in lst])
def testCycle(self): d = Digraph(13) d.add_edge(4,2) d.add_edge(2,3) d.add_edge(3,2) d.add_edge(6,0) d.add_edge(0,1) d.add_edge(2,0) d.add_edge(11,12) d.add_edge(12,9) d.add_edge(9,10) d.add_edge(9,11) d.add_edge(7,9) d.add_edge(10,12) d.add_edge(11,4) d.add_edge(4,3) d.add_edge(3,5) d.add_edge(6,8) d.add_edge(8,6) d.add_edge(5,4) d.add_edge(0,5) d.add_edge(6,4) d.add_edge(6,9) d.add_edge(7,6) self.assertEquals(13, d.count_vertices()) finder = DirectedCycle(d) self.assertEquals([3,4,5,3], finder.cycle)
class Server: def __init__(self): # contents: { vertex_id: ( lat, long ) } # lat and long values are stored in 100,000th of degrees self.vertex_locations = {} # contents: { ( v1, v2 ): name } self.edges = {} self.graph = Digraph() def import_file(self, filename): """ Builds the graph and associated information from specified text file. """ print('Importing {}...'.format(filename)) scale = 100000 count = 0 for line in open(filename, 'r'): count += 1 split_line = line.rstrip().split(',') line_type = split_line[0] if line_type == 'V': v = split_line[1] self.graph.add_vertex(v) self.vertex_locations[v] = (float(split_line[2]) * scale, float(split_line[3]) * scale) if line_type == 'E': t = (split_line[1], split_line[2]) self.graph.add_edge(t) self.edges[t] = split_line[3] print('{} lines processed. Ready for input.'.format(count)) def cost_distance(self, e): """ cost_distance returns the straight-line distance between the two vertices at the endpoints of the edge e. >>> s = Server() >>> s.vertex_locations[29577354] = (400,-400) >>> s.vertex_locations[29770958] = (500,-500) >>> tcompare(100 * math.sqrt(2), s.cost_distance((29577354, 29770958))) True """ #print('cost_distance: e = {}'.format(e)) v1 = self.vertex_locations[e[0]] v2 = self.vertex_locations[e[1]] #print('cost_distance: v1 = {}; v2 = {}'.format(v1, v2)) return euclidean_distance(v1, v2) def closest_vertex(self, lat, long): """ Returns the id of the closest vertex to the specified lat and long >>> s = Server() >>> s.vertex_locations[29577354] = (5343099.6,-11349133.1) >>> s.vertex_locations[29770958] = (5357142.9,-11362729.9) >>> s.closest_vertex(5343099,-11349133) 29577354 """ coords = (lat, long) closest = min(self.vertex_locations.items(), key=lambda x: euclidean_distance(coords, x[1])) return closest[0] def find_shortest_path(self, lat1, long1, lat2, long2): """ Returns a least cost path of coordinates from (lat1, long1) to (lat1, long1) """ v1 = self.closest_vertex(lat1, long1) v2 = self.closest_vertex(lat2, long2) #print('Closest vertices: {} and {}'.format(v1, v2)) vertex_path = least_cost_path(self.graph, v1, v2, self.cost_distance) #print('vertex_path: {}'.format(vertex_path)) path = [] if vertex_path is not None: for v in vertex_path: path.append(self.vertex_locations[v]) return path
def _dfs(self, G, v): self._marked[v] = True self._id[v] = self._count self._size[self._count] = self._size[self._count] + 1 for w in G.adj(v): if not self._marked[w]: self._dfs(G, w) # returns a boolean indicating if v, w are connected def connected(self, v, w): return self._id[v] == self._id[w] # returns the number of connected components def count(self): return self._count # component identifier for v def id(self, v): return self._id[v] if __name__ == "__main__": G = Digraph(4) G.add_edge(0,3) G.add_edge(3,2) G.add_edge(2,0) scc = SCC(G) print(scc.count()) # 2 print(scc.connected(0, 1)) # False print(scc.connected(0, 2)) # True
def readgraph(digraph_file_name): # create logger readgraph_logger = logging.getLogger('MappingServer.readgraph') readgraph_logger.info("Opening graphfile:" + str(digraph_file_name)) digraph_file = open(digraph_file_name, 'r') readgraph_logger.info("Open successful.") V = set() E = set() V_coord = {} E_name = {} G = Digraph() readgraph_logger.info("Parsing file...") # process each line in the file for line in digraph_file: # strip all trailing whitespace line = line.rstrip() fields = line.split(",") type = fields[0] if type == 'V': # got a vertex record (id, lat, long) = fields[1:] # vertex id's should be ints id = int(id) # lat and long are floats lat = float(lat) long = float(long) V.add(id) V_coord[id] = (lat, long) elif type == 'E': # got an edge record (start, stop, name) = fields[1:] # vertices are ints start = int(start) stop = int(stop) e = (start, stop) # get rid of leading and trailing quote " chars around name name = name.strip('"') # consistency check, we don't want auto adding of vertices when # adding an edge. if start not in V or stop not in V: readgraph_logger.error("Edge {} has an endpoint that is not a vertex".format(e)) raise Exception("Edge {} has an endpoint that is not a vertex".format(e)) G.add_edge(e) E_name[e] = name else: # weird input readgraph_logger.error("Error: weird line |{}|".format(line)) raise Exception("Error: weird line |{}|".format(line)) readgraph_logger.info("Parsing finished.") readgraph_logger.debug("Graph has " + str(G.num_vertices()) + " vertices and " + str(G.num_edges()) + " edges") V_Rev = {} for key in V_coord: V_Rev[key] = (int(V_coord[key][0] * 100000), int(V_coord[key][1] * 100000)) V_coord_rev = dict([(v, k) for (k, v) in V_Rev.items()]) names = (V_coord, E_name, V_coord_rev) return (G, names)
class DeadlockSet: def __init__(self): self.box_dl = Digraph() # box node -> deadlocks self._boxes_to_deadlock = defaultdict(list) self._box_to_size_to_nodeA = defaultdict(dict) self._nbox_to_size_to_nodeA = defaultdict(dict) self._last_node = -1 def _get_node(self, d, box, size): node = d[box].get(size, None) if node is not None: return node self._last_node += 1 d[box][size] = self._last_node self.box_dl.add_node_A(self._last_node) return self._last_node def add(self, deadlock): if isinstance(deadlock, SokoState): deadlock = deadlock_from_state(deadlock) self.box_dl.add_node_B(deadlock) self._boxes_to_deadlock[deadlock.boxes].append(deadlock) size = len(deadlock.boxes) for box in deadlock.boxes: node = self._get_node(self._box_to_size_to_nodeA, box, size) self.box_dl.add_edge(node, deadlock) for nbox in deadlock.not_boxes: node = self._get_node(self._nbox_to_size_to_nodeA, nbox, size) self.box_dl.add_edge(node, deadlock) return deadlock def remove(self, deadlock): self._boxes_to_deadlock[deadlock.boxes].remove(deadlock) self.box_dl.remove_node_B(deadlock) def find(self, new_boxes, new_nboxes, ori_boxes, ori_nboxes, storekeeper): size_to_nodes = defaultdict(list) def gen_size_to_node(): for box in new_boxes: size_to_node = self._box_to_size_to_nodeA.get(box, None) if size_to_node != None: yield size_to_node for nbox in new_nboxes: size_to_node = self._nbox_to_size_to_nodeA.get(nbox, None) if size_to_node != None: yield size_to_node for size_to_node in gen_size_to_node(): for size, nodeA in size_to_node.items(): size_to_nodes[size].append(nodeA) if not size_to_nodes: return None boxes_set = set(ori_boxes) boxes_set.update(new_boxes) boxes_set.difference_update(new_nboxes) boxes_sorted = sorted(boxes_set) max_size = len(boxes_sorted) size_to_nodes_items = sorted( filter(lambda item: item[0] <= max_size, size_to_nodes.items())) if ori_nboxes is None: nboxes_set = None else: nboxes_set = set(ori_nboxes) nboxes_set.update(new_nboxes) nboxes_set.difference_update(new_boxes) for size, box_nodes in size_to_nodes_items: candidate_sets = [ self.box_dl.neighbors_A(box_node) for box_node in box_nodes ] if sum(len(candidates) for candidates in candidate_sets) < size * binom( max_size, size): if len(candidate_sets) == 1: candidates = candidate_sets[0] else: candidates = set().union(*candidate_sets) for deadlock in candidates: if deadlock.check_sets(boxes_set, nboxes_set, storekeeper): yield deadlock else: for subboxes in combinations(boxes_sorted, size): for deadlock in self._boxes_to_deadlock[subboxes]: if deadlock.sk_component[storekeeper] \ and deadlock.nboxes_check_sets(boxes_set, nboxes_set): yield deadlock def find_one(self, new_boxes, new_nboxes, ori_boxes, ori_nboxes, storekeeper, condition=None): deadlocks = self.find(new_boxes, new_nboxes, ori_boxes, ori_nboxes, storekeeper) if condition is not None: deadlocks = filter(condition, deadlocks) return maybe_next(deadlocks) def find_by_state(self, state, ori_state=None): sub_boxes = state.sub_boxes if state.sub_full: sup_boxes = sub_boxes else: sup_boxes = state.sup_boxes if ori_state is None: ori_sub_boxes = np.zeros_like(state.available) ori_sup_boxes = state.available else: ori_sub_boxes = ori_state.sub_boxes if ori_state.sub_full: ori_sup_boxes = ori_state.sub_boxes else: ori_sup_boxes = ori_state.sup_boxes ori_boxes = positions_true(sub_boxes) ori_nboxes = positions_true(~sup_boxes & state.available) new_boxes = positions_true(sub_boxes & ~ori_sub_boxes) new_nboxes = positions_true(~sup_boxes & ori_sup_boxes) if state.storekeepers is not None: storekeeper = state.storekeeper else: storekeeper = positions_true(state.storekeepers)[0] if state.multi_component: condition = lambda deadlock: (state.storekeepers <= deadlock. sk_component).all() else: condition = None return self.find_one( new_boxes, new_nboxes, ori_boxes, ori_nboxes, storekeeper, condition=condition, ) def find_for_box_moves(self, state, box_moves): if state.multi_component: for box_src, box_dest, sk_dir in box_moves: sub_boxes = np.array(state.sub_boxes) sup_boxes = np.array(state.sup_boxes) sub_boxes[box_src] = False sup_boxes[box_src] = False sub_boxes[box_dest] = True sup_boxes[box_dest] = True state2 = SokoState( available=state.available, sub_boxes=sub_boxes, sup_boxes=sup_boxes, storages=state.storages, sub_full=state.sub_full, storekeeper=dir_shift(sk_dir, box_dest), storekeeper_goal=state.storekeeper_goal, ) yield self.find_by_state(state2) else: ori_boxes = positions_true(state.sub_boxes) if state.sub_full: ori_nboxes = None else: ori_nboxes = positions_true(state.available & ~state.sup_boxes) for box_src, box_dest, sk_dir in box_moves: storekeeper = dir_shift(sk_dir, box_dest) yield self.find_one([box_dest], [box_src], ori_boxes, ori_nboxes, storekeeper) def find_for_actions(self, state, actions, fw_mode=True): box_moves = [] for y, x, d in actions: box_src = (y + 1, x + 1) box_dest = dir_shift(d, box_src) if fw_mode: sk_dir = op_dir(d) else: sk_dir = d box_moves.append((box_src, box_dest, sk_dir)) return self.find_for_box_moves(state, box_moves)
class SymbolDigraph(object): """Like digraph but operates with strings, you can never remove edges""" def __init__(self,size=0): self.symboltable = {} self.names = [] self.digraph = Digraph(size) def add_vertice(self, edge_from): """Add named vertice""" index_from = self._check_index(edge_from) self._check_digraph_size(index_from) self.names[index_from] = edge_from def add_edge(self, edge_from, edge_to): """Add named edge link""" index_from = self._check_index(edge_from) index_to = self._check_index(edge_to) self._check_digraph_size(max(index_from, index_to)) self.digraph.add_edge(index_from, index_to) def _check_index(self, key): """if exists, returns id, otherwise adds a new one and also returns""" keyname = str(key) #print "_check_index", key, "len(keyname)", len(keyname) if key == None or not(len(keyname)): raise Exception("Edge name cannot be none") if self.index(keyname) == -1: index = len(self.symboltable) self.symboltable[keyname] = index self._check_names_size(index) self.names[index] = key return self.symboltable[keyname] def index(self, key): """returns internal index by key""" if self.symboltable.has_key(key): return self.symboltable[key] return -1 def _check_digraph_size(self, index): """resizes graph accordingly""" i = index - self.digraph.count_vertices() while i >= 0: self.digraph.add_vertice() i -= 1 def _check_names_size(self, index): """resizes graph accordingly""" i = index - len(self.names) while i >= 0: self.names.append(None) i -= 1 def count_vertices(self): """returns number of vertices (nodes)""" return self.digraph.count_vertices() def count_edges(self): """returns number of edges(links)""" return self.digraph.count_edges() def vertices(self): "Named vertices" return self.names def links(self, key): "Links from node" names = [] for linkid in self.digraph.links(self.index(key)): names.append(self.name(linkid)) return names def name(self, index): """Symbol by index""" return self.names[index]
class DeadlockStack: def __init__(self, dl_set=None, fname=None, sample_state=None): self.fname = fname self.dependencies = Digraph() # deadlock -> descendants if dl_set is None: dl_set = DeadlockSet() self.dl_set = dl_set self._last_full_index = -1 self.debug_data = [] self.debug_fname = "bug.log" if fname is not None: assert sample_state is not None if os.path.exists(fname): print("loading deadlocks...") try: blocks = deadlocks_from_file(fname, sample_state) except: blocks = None def backup_fnames_gen(): base_fname = fname + "_backup" yield base_fname i = 0 while True: yield base_fname + str(i) backup_fnames = backup_fnames_gen() while True: backup_fname = next(backup_fnames) if not os.path.exists(backup_fname): break os.rename(fname, backup_fname) print("deadlock file corrupted, renamed to '{}'".format( backup_fname)) if blocks is not None: for dl in chain.from_iterable(blocks): self.debug_data.append( "dummy_deadlocks[{}] = make_dummy_deadlock({})". format(id(dl), dl.full_index)) self.dl_set.add(dl) self._last_full_index = dl.full_index print("loaded {} deadlocks".format(self._last_full_index + 1)) def add(self, deadlock, stack_index): assert stack_index >= 0 if isinstance(deadlock, SokoState): deadlock = deadlock_from_state(deadlock) self.debug_data.append( "dummy_deadlocks[{}] = dl_stack.add(make_dummy_deadlock(), {})". format( id(deadlock), stack_index, )) deadlock.stack_index = stack_index self.dl_set.add(deadlock) self.dependencies.add_node_B(deadlock) return deadlock # supports removing multiple deadlocks at once # discards also deadlocks dependent on it def remove(self, deadlocks): if isinstance(deadlocks, Deadlock): deadlocks = [deadlocks] self.debug_data.append( "dl_stack.remove([dummy_deadlocks[i] for i in {}])".format( [id(dl) for dl in deadlocks])) dependent = self.dependencies.closure_BA(deadlocks) for deadlock in dependent: self.dl_set.remove(deadlock) self.dependencies.remove_node_B(deadlock) if deadlock.descendants is not None: self.dependencies.remove_node_A(deadlock) def make_full(self, deadlock): assert deadlock.full_index == None deadlock.stack_index = -1 self.dependencies.remove_node(deadlock) self._last_full_index += 1 deadlock.full_index = self._last_full_index def set_descendants(self, deadlock, pushes, descendants): self.debug_data.append( "dl_stack.set_descendants(dummy_deadlocks[{}], [None]*{}, [dummy_deadlocks[i] for i in {}])" .format( id(deadlock), len(descendants), [id(dl) for dl in descendants], )) try: assert deadlock.descendants is None assert len(pushes) == len(descendants) deadlock.descendants = dict(zip(pushes, descendants)) # add to dependency graph self.dependencies.add_node_A(deadlock) for descendant in descendants: if descendant.stack_index >= 0: self.dependencies.add_edge(deadlock, descendant) # update stack_index where necessary to_check = self.dependencies.closure_BA([deadlock]) ori_stack_index = deadlock.stack_index assert all(dl.stack_index == ori_stack_index for dl in to_check) # find elements of to_check looking outside new_stack_indices = defaultdict(list) for dl in to_check: new_stack_index = max([ desc.stack_index for desc in self.dependencies.neighbors_A(dl) if desc.stack_index != ori_stack_index ], default=-1) if new_stack_index >= 0: assert (new_stack_index < ori_stack_index), ( new_stack_index, ori_stack_index) new_stack_indices[new_stack_index].append( (dl, new_stack_index)) dfs_stack = list( chain.from_iterable(new_stack_indices[i] for i in sorted(new_stack_indices.keys()))) # propagate the right stack_index backwards to_check_l = [] size_of_index = defaultdict(int) while dfs_stack: dl, i = dfs_stack.pop() if dl not in to_check: continue to_check_l.append(dl) size_of_index[i] += 1 to_check.remove(dl) dl.stack_index = i dfs_stack.extend( (dl2, i) for dl2 in self.dependencies.neighbors_B(dl)) # mark a strongly connected component as a full deadlock scc = list(to_check) if scc: for dl in scc: self.make_full(dl) if self.fname is not None: with open(self.fname, 'a') as f: print(file=f) for dl in scc: dl.print_self(file=f) if len(scc) == 1: print("Saved deadlock {}".format(scc[0].full_index)) else: print("Saved deadlocks {}-{}".format( scc[0].full_index, scc[-1].full_index)) # output for checking on path to_check_l.reverse() return scc, scc + to_check_l, size_of_index except Exception: if self.debug_fname is not None: with open(self.debug_fname, 'w') as f: for l in self.debug_data: print(l, file=f) print("error in DeadlockStack occured, debug data stored in " + self.debug_fname) self.debug_fname = None raise def check_correct(self): for dl in self.dependencies.nodes_A(): assert dl.stack_index == max( [dl2.stack_index for dl2 in dl.descendants.values()], default=-1)
def read_graph(input_file): """ Read in Digraph data from a file, and return it as a tuple containing a Digraph as well as a map of metadata with vertex positions and edge names. Returns: (digraph, { (node id or edge tuple): (position or edge name) }) """ # # graph and metadata to populate # graph = Digraph() # metadata = {} # # set of vertices that we have read in. Used to check that # # we aren't adding verts through |add_edge| that won't have any # # location metadata. # vert_set = set() # # process each line in the file # for line in input_file: # # strip all trailing whitespace # line = line.rstrip() # fields = line.split(",") # type = fields[0] # if type == 'V': # # got a vertex record # (id,lat,long) = fields[1:] # # vertex id's should be ints # id=int(id) # # lat and long are floats # lat=float(lat) # long=float(long) # vert_set.add(id) # graph.add_vertex(id) # metadata[id] = (lat,long) # elif type == 'E': # # got an edge record # (start,stop,name) = fields[1:] # # vertices are ints # start=int(start) # stop=int(stop) # e = (start,stop) # if start not in vert_set: # raise Exception("Vertex %d is an endpoint for an edge but has no metadata" % start) # if stop not in vert_set: # raise Exception("Vertex %d is an endpoint for an edge but has no metadata" % stop) # # get rid of leading and trailing quote " chars around name # name = name.strip('"') # graph.add_edge(e) # metadata[e] = name # else: # # weird input # raise Exception("Error: weird line |{}|".format(line)) vert_map = {} # vert_id => {at = (lat,lon), ine = set(), oute = set()} edge_map = {} # (id,id) => name for line in input_file: # strip all trailing whitespace line = line.rstrip() fields = line.split(",") type = fields[0] if type == "V": # got a vertex record (id, lat, long) = fields[1:] # vertex id's should be ints id = int(id) # lat and long are floats lat = float(lat) long = float(long) # todo vert_map[id] = {"at": (lat, long), "id": id, "ine": set(), "oute": set()} elif type == "E": # got an edge record (start, stop, name) = fields[1:] # vertices are ints start = int(start) stop = int(stop) e = (start, stop) # get rid of leading and trailing quote " chars around name name = name.strip('"') # todo edge_map[(start, stop)] = name else: # weird input raise Exception("Error: weird line |{}|".format(line)) graph = Digraph() cached_aux_verts = {} def get_aux_verts(e): if e not in cached_aux_verts: aux_vert = {} # first assign ine and oute on verts for e in edge_map: vert_map[e[0]]["oute"].add(e) vert_map[e[1]]["ine"].add(e) # metadata metadata = {} # now, make the aux vert set aux_vert_map = {} # {vert_id => {adjacent_id => aux_vert_id}} aux_vert_current_id = 1 for v_id in vert_map: my_aux_verts = {} vdat = vert_map[v_id] for e in vdat["ine"]: my_aux_verts[e[0]] = aux_vert_current_id aux_vert_current_id += 1 for e in vdat["oute"]: my_aux_verts[e[1]] = aux_vert_current_id aux_vert_current_id += 1 for id in my_aux_verts.values(): metadata[id] = vdat["at"] graph.add_vertex(id) aux_vert_map[v_id] = my_aux_verts # aux verts have been created, add the main edges for (a, b) in edge_map: graph.add_edge((aux_vert_map[a][b], aux_vert_map[b][a])) metadata[(aux_vert_map[a][b], aux_vert_map[b][a])] = 0 # and finally, we need to add the junction virtual edges for v_id in vert_map: vdat = vert_map[v_id] # for each incomming edge, join it to each outgoing edge for (a, b) in vdat["ine"]: in_aux_vert_id = aux_vert_map[v_id][a] for (b, c) in vdat["oute"]: out_aux_vert_id = aux_vert_map[v_id][c] # calculate cost cost = 0 if len(vdat["ine"]) == 1 and len(vdat["oute"]) == 1: # ignore turn cost for nodes that just represent curves cost = 0 else: # use the angle at_a = vert_map[a]["at"] at_b = vert_map[b]["at"] at_c = vert_map[c]["at"] dir_1 = (at_b[0] - at_a[0], at_b[1] - at_a[1]) dir_2 = (at_c[0] - at_b[0], at_c[1] - at_b[1]) theta = math.acos( (dir_1[0] * dir_2[0] + dir_1[1] * dir_2[1]) / ((dir_1[0] ** 2 + dir_1[1] ** 2) ** 0.5 * (dir_2[0] ** 2 + dir_2[1] ** 2) ** 0.5) * 0.9999 ) cost = theta * 10 # add graph.add_edge((in_aux_vert_id, out_aux_vert_id)) metadata[(in_aux_vert_id, out_aux_vert_id)] = cost # return the data return (graph, metadata)