Exemplo n.º 1
0
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())
Exemplo n.º 3
0
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())
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
            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)
Exemplo n.º 7
0
    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'])
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
    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())
Exemplo n.º 12
0
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
Exemplo n.º 13
0
    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')))
Exemplo n.º 14
0
            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)
Exemplo n.º 15
0
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)
Exemplo n.º 16
0
    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'])
Exemplo n.º 17
0
    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'])
Exemplo n.º 18
0
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)
Exemplo n.º 19
0
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)
Exemplo n.º 20
0
    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)
Exemplo n.º 21
0
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)
Exemplo n.º 22
0
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)
Exemplo n.º 23
0
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]
Exemplo n.º 24
0
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)
Exemplo n.º 25
0
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
Exemplo n.º 27
0
    # 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]
Exemplo n.º 28
0
 def testOverflow(self):
     d = Digraph(5)
     d.add_edge(0, 1)
     self.assertRaises(Exception, d.add_edge, 10, 1)
Exemplo n.º 29
0
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)
Exemplo n.º 30
0
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)])
Exemplo n.º 34
0
 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())
Exemplo n.º 36
0
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)
Exemplo n.º 38
0
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
Exemplo n.º 39
0
	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
Exemplo n.º 40
0
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)
Exemplo n.º 41
0
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]
Exemplo n.º 43
0
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)
Exemplo n.º 44
0
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)