def coxeter_graph(self):
        """
        Return the Coxeter graph of ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup(['H',3], implementation="reflection")
            sage: G = W.coxeter_graph(); G
            Graph on 3 vertices
            sage: G.edges()
            [(1, 2, None), (2, 3, 5)]
            sage: CoxeterGroup(G) is W
            True
            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W = CoxeterGroup(G)
            sage: W.coxeter_graph() == G
            True
            sage: CoxeterGroup(W.coxeter_graph()) is W
            True
        """
        G = Graph()
        G.add_vertices(self.index_set())
        for i, row in enumerate(self._matrix.rows()):
            for j, val in enumerate(row[i + 1:]):
                if val == 3:
                    G.add_edge(self._index_set[i], self._index_set[i + 1 + j])
                elif val > 3:
                    G.add_edge(self._index_set[i], self._index_set[i + 1 + j],
                               val)
                elif val == -1:  # FIXME: Hack because there is no ZZ\cup\{\infty\}
                    G.add_edge(self._index_set[i], self._index_set[i + 1 + j],
                               infinity)
        return G
Example #2
0
    def coxeter_diagram(self):
        """
        Return the Coxeter diagram for ``self``.

        EXAMPLES::

            sage: cd = CartanType("A2xB2xF4").coxeter_diagram()
            sage: cd
            Graph on 8 vertices
            sage: cd.edges()
            [(1, 2, 3), (3, 4, 4), (5, 6, 3), (6, 7, 4), (7, 8, 3)]

            sage: CartanType("F4xA2").coxeter_diagram().edges()
            [(1, 2, 3), (2, 3, 4), (3, 4, 3), (5, 6, 3)]

            sage: cd = CartanType("A1xH3").coxeter_diagram(); cd
            Graph on 4 vertices
            sage: cd.edges()
            [(2, 3, 3), (3, 4, 5)]
        """
        from sage.graphs.graph import Graph
        relabelling = self._index_relabelling
        g = Graph(multiedges=False)
        g.add_vertices(self.index_set())
        for i, t in enumerate(self._types):
            for [e1, e2, l] in t.coxeter_diagram().edges():
                g.add_edge(relabelling[i, e1], relabelling[i, e2], label=l)
        return g
Example #3
0
    def coxeter_diagram(self):
        """
        Return the Coxeter diagram for ``self``.

        EXAMPLES::

            sage: cd = CartanType("A2xB2xF4").coxeter_diagram()
            sage: cd
            Graph on 8 vertices
            sage: cd.edges()
            [(1, 2, 3), (3, 4, 4), (5, 6, 3), (6, 7, 4), (7, 8, 3)]

            sage: CartanType("F4xA2").coxeter_diagram().edges()
            [(1, 2, 3), (2, 3, 4), (3, 4, 3), (5, 6, 3)]

            sage: cd = CartanType("A1xH3").coxeter_diagram(); cd
            Graph on 4 vertices
            sage: cd.edges()
            [(2, 3, 3), (3, 4, 5)]
        """
        from sage.graphs.graph import Graph
        relabelling = self._index_relabelling
        g = Graph(multiedges=False)
        g.add_vertices(self.index_set())
        for i,t in enumerate(self._types):
            for [e1, e2, l] in t.coxeter_diagram().edges():
                g.add_edge(relabelling[i,e1], relabelling[i,e2], label=l)
        return g
Example #4
0
    def coxeter_graph(self):
        """
        Return the Coxeter graph of ``self``.

        EXAMPLES::

            sage: C = CoxeterMatrix(['A',3])
            sage: C.coxeter_graph()
            Graph on 3 vertices

            sage: C = CoxeterMatrix([['A',3],['A',1]])
            sage: C.coxeter_graph()
            Graph on 4 vertices
        """
        n = self.rank()
        I = self.index_set()
        val = lambda x: infinity if x == -1 else x
        G = Graph(
            [
                (I[i], I[j], val((self._matrix)[i, j]))
                for i in range(n)
                for j in range(i)
                if self._matrix[i, j] not in [1, 2]
            ]
        )
        G.add_vertices(I)
        return G.copy(immutable=True)
Example #5
0
    def coxeter_graph(self):
        """
        Return the Coxeter graph of ``self``.

        EXAMPLES::

            sage: C = CoxeterMatrix(['A',3])
            sage: C.coxeter_graph()
            Graph on 3 vertices

            sage: C = CoxeterMatrix([['A',3],['A',1]])
            sage: C.coxeter_graph()
            Graph on 4 vertices
        """
        n = self.rank()
        I = self.index_set()

        def val(x):
            return infinity if x == -1 else x

        G = Graph([(I[i], I[j], val((self._matrix)[i, j])) for i in range(n)
                   for j in range(i) if self._matrix[i, j] not in [1, 2]],
                  format='list_of_edges')
        G.add_vertices(I)
        return G.copy(immutable=True)
Example #6
0
    def to_bipartite_graph(self, with_partition=False):
        r"""
        Returns the associated bipartite graph

        INPUT:

        - with_partition -- boolean (default: False)

        OUTPUT:

        - a graph or a pair (graph, partition)

        EXAMPLES::

            sage: H = designs.steiner_triple_system(7).blocks()
            sage: H = Hypergraph(H)
            sage: g = H.to_bipartite_graph(); g
            Graph on 14 vertices
            sage: g.is_regular()
            True
        """
        from sage.graphs.graph import Graph

        G = Graph()
        domain = list(self.domain())
        G.add_vertices(domain)
        for s in self._sets:
            for i in s:
                G.add_edge(s, i)
        if with_partition:
            return (G, [domain, list(self._sets)])
        else:
            return G
Example #7
0
    def __init__(self, args):
        r"""
        The free partially commutative left regular band associated to the
        (undirected) graph ``graph``.

        This is the left regular band generated by the vertices of the graph
        and relations `xy = yx` for every edge `(x,y)` of the graph.

        EXAMPLES::

            sage: from sage_semigroups.monoids.free_partially_commutative_left_regular_band import FreePartiallyCommutativeLeftRegularBand
            sage: G = Graph({0:[],1:[],2:[]})
            sage: S = FreePartiallyCommutativeLeftRegularBand(G); S
            Free partially commutative left regular band on Graph on 3 vertices
            sage: K = graphs.CompleteGraph(4)
            sage: S = FreePartiallyCommutativeLeftRegularBand(K); S
            Free partially commutative left regular band on Graph on 4 vertices
            sage: TestSuite(S).run(skip=["_test_elements", "_test_pickling"])
        """
        (vertices, edges) = args
        graph = Graph()
        graph.add_vertices(vertices)
        graph.add_edges(edges)
        self._graph = graph
        from sage_semigroups.categories.finite_left_regular_bands import FiniteLeftRegularBands
        Parent.__init__(self, category = FiniteLeftRegularBands().FinitelyGenerated())
Example #8
0
    def coxeter_graph(self):
        """
        Return the Coxeter graph of ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup(['H',3], implementation="reflection")
            sage: G = W.coxeter_graph(); G
            Graph on 3 vertices
            sage: G.edges()
            [(1, 2, None), (2, 3, 5)]
            sage: CoxeterGroup(G) is W
            True
            sage: G = Graph([(0, 1, 3), (1, 2, oo)])
            sage: W = CoxeterGroup(G)
            sage: W.coxeter_graph() == G
            True
            sage: CoxeterGroup(W.coxeter_graph()) is W
            True
        """
        G = Graph()
        G.add_vertices(self.index_set())
        for i, row in enumerate(self._matrix.rows()):
            for j, val in enumerate(row[i + 1 :]):
                if val == 3:
                    G.add_edge(self._index_set[i], self._index_set[i + 1 + j])
                elif val > 3:
                    G.add_edge(self._index_set[i], self._index_set[i + 1 + j], val)
                elif val == -1:  # FIXME: Hack because there is no ZZ\cup\{\infty\}
                    G.add_edge(self._index_set[i], self._index_set[i + 1 + j], infinity)
        return G
Example #9
0
    def to_bipartite_graph(self, with_partition=False):
        r"""
        Returns the associated bipartite graph

        INPUT:

        - with_partition -- boolean (default: False)

        OUTPUT:

        - a graph or a pair (graph, partition)

        EXAMPLES::

            sage: H = designs.steiner_triple_system(7).blocks()
            sage: H = Hypergraph(H)
            sage: g = H.to_bipartite_graph(); g
            Graph on 14 vertices
            sage: g.is_regular()
            True
        """
        from sage.graphs.graph import Graph

        G = Graph()
        domain = list(self.domain())
        G.add_vertices(domain)
        for s in self._sets:
            for i in s:
                G.add_edge(s, i)
        if with_partition:
            return (G, [domain, list(self._sets)])
        else:
            return G
Example #10
0
def CircularLadderGraph(n):
    """
    Returns a circular ladder graph with 2\*n nodes.

    A Circular ladder graph is a ladder graph that is connected at the
    ends, i.e.: a ladder bent around so that top meets bottom. Thus it
    can be described as two parallel cycle graphs connected at each
    corresponding node pair.

    This constructor depends on NetworkX numeric labels.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, the circular
    ladder graph is displayed as an inner and outer cycle pair, with
    the first n nodes drawn on the inner circle. The first (0) node is
    drawn at the top of the inner-circle, moving clockwise after that.
    The outer circle is drawn with the (n+1)th node at the top, then
    counterclockwise as well.

    EXAMPLES: Construct and show a circular ladder graph with 26 nodes

    ::

        sage: g = graphs.CircularLadderGraph(13)
        sage: g.show() # long time

    Create several circular ladder graphs in a Sage graphics array

    ::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:    k = graphs.CircularLadderGraph(i+3)
        ....:    g.append(k)
        sage: for i in range(3):
        ....:    n = []
        ....:    for m in range(3):
        ....:        n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
        ....:    j.append(n)
        sage: G = sage.plot.graphics.GraphicsArray(j)
        sage: G.show() # long time
    """
    pos_dict = {}
    for i in range(n):
        x = float(cos((pi/2) + ((2*pi)/n)*i))
        y = float(sin((pi/2) + ((2*pi)/n)*i))
        pos_dict[i] = [x,y]
    for i in range(n,2*n):
        x = float(2*(cos((pi/2) + ((2*pi)/n)*(i-n))))
        y = float(2*(sin((pi/2) + ((2*pi)/n)*(i-n))))
        pos_dict[i] = (x,y)

    G = Graph(pos=pos_dict, name="Circular Ladder graph")
    G.add_vertices( range(2*n) )
    G.add_cycle( range(n) )
    G.add_cycle( range(n,2*n) )
    G.add_edges( (i,i+n) for i in range(n) )
    return G
Example #11
0
def CircularLadderGraph(n):
    """
    Returns a circular ladder graph with 2\*n nodes.

    A Circular ladder graph is a ladder graph that is connected at the
    ends, i.e.: a ladder bent around so that top meets bottom. Thus it
    can be described as two parallel cycle graphs connected at each
    corresponding node pair.

    This constructor depends on NetworkX numeric labels.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, the circular
    ladder graph is displayed as an inner and outer cycle pair, with
    the first n nodes drawn on the inner circle. The first (0) node is
    drawn at the top of the inner-circle, moving clockwise after that.
    The outer circle is drawn with the (n+1)th node at the top, then
    counterclockwise as well.

    EXAMPLES: Construct and show a circular ladder graph with 26 nodes

    ::

        sage: g = graphs.CircularLadderGraph(13)
        sage: g.show() # long time

    Create several circular ladder graphs in a Sage graphics array

    ::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:    k = graphs.CircularLadderGraph(i+3)
        ....:    g.append(k)
        sage: for i in range(3):
        ....:    n = []
        ....:    for m in range(3):
        ....:        n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
        ....:    j.append(n)
        sage: G = sage.plot.graphics.GraphicsArray(j)
        sage: G.show() # long time
    """
    pos_dict = {}
    for i in range(n):
        x = float(cos((pi / 2) + ((2 * pi) / n) * i))
        y = float(sin((pi / 2) + ((2 * pi) / n) * i))
        pos_dict[i] = [x, y]
    for i in range(n, 2 * n):
        x = float(2 * (cos((pi / 2) + ((2 * pi) / n) * (i - n))))
        y = float(2 * (sin((pi / 2) + ((2 * pi) / n) * (i - n))))
        pos_dict[i] = (x, y)

    G = Graph(pos=pos_dict, name="Circular Ladder graph")
    G.add_vertices(range(2 * n))
    G.add_cycle(range(n))
    G.add_cycle(range(n, 2 * n))
    G.add_edges((i, i + n) for i in range(n))
    return G
Example #12
0
 def create_graph_from_model(self, solver, model):
     """
     Given a model from the SAT solver, construct the graph.
     """
     g = Graph()
     on_vertices = solver.get_objects_in_model(model, self, self.internal_graph.vertices())
     on_edges = solver.get_objects_in_model(model, self, self.internal_graph.edges(labels=False))
     g.add_vertices(on_vertices)
     g.add_edges(on_edges)
     return g
Example #13
0
 def create_graph_from_model(self, solver, model):
     '''
     Given a model from the SAT solver, construct the graph.
     '''
     g = Graph()
     on_vertices = solver.get_objects_in_model(
         model, self, self.internal_graph.vertices())
     on_edges = solver.get_objects_in_model(
         model, self, self.internal_graph.edges(labels=False))
     g.add_vertices(on_vertices)
     g.add_edges(on_edges)
     return g
Example #14
0
def IntersectionGraph(S):
    r"""
    Returns the intersection graph of the family `S`

    The intersection graph of a family `S` is a graph `G` with `V(G)=S` such
    that two elements `s_1,s_2\in S` are adjacent in `G` if and only if `s_1\cap
    s_2\neq \emptyset`.

    INPUT:

    - ``S`` -- a list of sets/tuples/iterables

        .. NOTE::

            The elements of `S` must be finite, hashable, and the elements of
            any `s\in S` must be hashable too.

    EXAMPLES::

        sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)])
        Intersection Graph: Graph on 3 vertices

    TESTS::

        sage: graphs.IntersectionGraph([(1,2,[1])])
        Traceback (most recent call last):
        ...
        TypeError: The elements of S must be hashable, and this one is not: (1, 2, [1])
    """
    from itertools import combinations

    for s in S:
        try:
            hash(s)
        except TypeError:
            raise TypeError(
                "The elements of S must be hashable, and this one is not: {}".
                format(s))

    ground_set_to_sets = {}
    for s in S:
        for x in s:
            if x not in ground_set_to_sets:
                ground_set_to_sets[x] = []
            ground_set_to_sets[x].append(s)

    g = Graph(name="Intersection Graph")
    g.add_vertices(S)
    for clique in itervalues(ground_set_to_sets):
        g.add_clique(set(clique))

    return g
Example #15
0
def LadderGraph(n):
    """
    Returns a ladder graph with 2\*n nodes.

    A ladder graph is a basic structure that is typically displayed as
    a ladder, i.e.: two parallel path graphs connected at each
    corresponding node pair.

    This constructor depends on NetworkX numeric labels.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, each ladder
    graph will be displayed horizontally, with the first n nodes
    displayed left to right on the top horizontal line.

    EXAMPLES: Construct and show a ladder graph with 14 nodes

    ::

        sage: g = graphs.LadderGraph(7)
        sage: g.show() # long time

    Create several ladder graphs in a Sage graphics array

    ::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.LadderGraph(i+2)
        ....:     g.append(k)
        sage: for i in range(3):
        ....:     n = []
        ....:     for m in range(3):
        ....:         n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
        ....:     j.append(n)
        sage: G = sage.plot.graphics.GraphicsArray(j)
        sage: G.show() # long time
    """
    pos_dict = {}
    for i in range(n):
        pos_dict[i] = (i,1)
    for i in range(n,2*n):
        x = i - n
        pos_dict[i] = (x,0)
    G = Graph(pos=pos_dict, name="Ladder graph")
    G.add_vertices( range(2*n) )
    G.add_path( range(n) )
    G.add_path( range(n,2*n) )
    G.add_edges( (i,i+n) for i in range(n) )
    return G
Example #16
0
def LadderGraph(n):
    """
    Returns a ladder graph with 2\*n nodes.

    A ladder graph is a basic structure that is typically displayed as
    a ladder, i.e.: two parallel path graphs connected at each
    corresponding node pair.

    This constructor depends on NetworkX numeric labels.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, each ladder
    graph will be displayed horizontally, with the first n nodes
    displayed left to right on the top horizontal line.

    EXAMPLES: Construct and show a ladder graph with 14 nodes

    ::

        sage: g = graphs.LadderGraph(7)
        sage: g.show() # long time

    Create several ladder graphs in a Sage graphics array

    ::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.LadderGraph(i+2)
        ....:     g.append(k)
        sage: for i in range(3):
        ....:     n = []
        ....:     for m in range(3):
        ....:         n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
        ....:     j.append(n)
        sage: G = sage.plot.graphics.GraphicsArray(j)
        sage: G.show() # long time
    """
    pos_dict = {}
    for i in range(n):
        pos_dict[i] = (i, 1)
    for i in range(n, 2 * n):
        x = i - n
        pos_dict[i] = (x, 0)
    G = Graph(pos=pos_dict, name="Ladder graph")
    G.add_vertices(range(2 * n))
    G.add_path(range(n))
    G.add_path(range(n, 2 * n))
    G.add_edges((i, i + n) for i in range(n))
    return G
Example #17
0
def IntersectionGraph(S):
    r"""
    Returns the intersection graph of the family `S`

    The intersection graph of a family `S` is a graph `G` with `V(G)=S` such
    that two elements `s_1,s_2\in S` are adjacent in `G` if and only if `s_1\cap
    s_2\neq \emptyset`.

    INPUT:

    - ``S`` -- a list of sets/tuples/iterables

        .. NOTE::

            The elements of `S` must be finite, hashable, and the elements of
            any `s\in S` must be hashable too.

    EXAMPLE::

        sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)])
        Intersection Graph: Graph on 3 vertices

    TESTS::

        sage: graphs.IntersectionGraph([(1,2,[1])])
        Traceback (most recent call last):
        ...
        TypeError: The elements of S must be hashable, and this one is not: (1, 2, [1])
    """
    from itertools import combinations

    for s in S:
        try:
            hash(s)
        except TypeError:
            raise TypeError("The elements of S must be hashable, and this one is not: {}".format(s))

    ground_set_to_sets = {}
    for s in S:
        for x in s:
            if x not in ground_set_to_sets:
                ground_set_to_sets[x] = []
            ground_set_to_sets[x].append(s)

    g = Graph(name="Intersection Graph")
    g.add_vertices(S)
    for clique in ground_set_to_sets.itervalues():
        g.add_edges((u,v) for u,v in combinations(clique,2))

    return g
Example #18
0
    def from_cells(cls, cells={}):
        r"""
        From a dictionary { coordinates pair : None }
        return a graph with one vertex for every coordinates pair

        TESTS ::

            sage: from sage.graphs.generators.families import AztecDiamondGraph
            sage: from sage_widget_adapters.graphs.graph_grid_view_adapter import GraphGridViewAdapter
            sage: GraphGridViewAdapter.from_cells({(0, 0): None, (0, 1): None, (1, 0): None, (1, 1): None, (2, 0): None, (2, 1): None})
            Graph on 6 vertices
        """
        g = Graph()
        g.add_vertices(list(cells.keys()))
        return cls.objclass(g)
Example #19
0
 def apply(solver, model, structures):
 
     g = structures[0]
     vertices = solver.get_objects_in_model(model, g, g.internal_graph.vertices())
     dims = int(math.log(g.order, 2))
     #print(vertices)
     #print(dims)
     edges = solver.get_objects_in_model(model, g, g.internal_graph.edges(labels=False))
     #print(edges)
     #create temp graph
     t = Graph()
     t.add_vertices(vertices)
     t.add_edges(edges)
     for i in range(g.order/2):
         antipod = g.order - 1 - i
         #print(i, antipod)
         if i in vertices and antipod in vertices:
             path = t.shortest_path(i, antipod)
             if path:
                 #print(path)
                 return (True, [g, path])
     print("COUNTER")
     return (False, [])
    def connection_graph(self):
        """
        Return the graph which has the variables of this system as
        vertices and edges between two variables if they appear in the
        same polynomial.

        EXAMPLE::

            sage: B.<x,y,z> = BooleanPolynomialRing()
            sage: F = Sequence([x*y + y + 1, z + 1])
            sage: F.connection_graph()
            Graph on 3 vertices
        """
        V = sorted(self.variables())
        from sage.graphs.graph import Graph
        g = Graph()
        g.add_vertices(sorted(V))
        for f in self:
            v = f.variables()
            a,tail = v[0],v[1:]
            for b in tail:
                g.add_edge((a,b))
        return g
    def connection_graph(self):
        """
        Return the graph which has the variables of this system as
        vertices and edges between two variables if they appear in the
        same polynomial.

        EXAMPLE::

            sage: B.<x,y,z> = BooleanPolynomialRing()
            sage: F = Sequence([x*y + y + 1, z + 1])
            sage: F.connection_graph()
            Graph on 3 vertices
        """
        V = sorted(self.variables())
        from sage.graphs.graph import Graph
        g = Graph()
        g.add_vertices(sorted(V))
        for f in self:
            v = f.variables()
            a,tail = v[0],v[1:]
            for b in tail:
                g.add_edge((a,b))
        return g
Example #22
0
def decode_fgraph_string(s):
    data = s.split("_")
    n = decode_6bits(data[0])
    f = [decode_6bits(data[1][i]) for i in range(n)]

    G = Graph()
    G.add_vertices(range(n))

    # read in the adjacency matrix
    cur = 0
    val = decode_6bits(data[2][cur])
    mask = 1 << 5  # start with the high bit
    for j in range(
            n):  # adj matrix is bit packed in colex order, as in graph6 format
        for i in range(j):
            if val & mask != 0:  # test whether that bit is nonzero
                G.add_edge(i, j)
            mask >>= 1
            if mask == 0:  # mask has become 0
                cur += 1
                val = decode_6bits(data[2][cur])
                mask = 1 << 5

    return G, f
Example #23
0
def PermutationGraph(second_permutation, first_permutation = None):
    r"""
    Build a permutation graph from one permutation or from two lists.

    Definition:

    If `\sigma` is a permutation of `\{ 1, 2, \ldots, n \}`, then the
    permutation graph of `\sigma` is the graph on vertex set
    `\{ 1, 2, \ldots, n \}` in which two vertices `i` and `j` satisfying
    `i < j` are connected by an edge if and only if
    `\sigma^{-1}(i) > \sigma^{-1}(j)`. A visual way to construct this
    graph is as follows:

      Take two horizontal lines in the euclidean plane, and mark points
      `1, ..., n` from left to right on the first of them. On the second
      one, still from left to right, mark `n` points
      `\sigma(1), \sigma(2), \ldots, \sigma(n)`.
      Now, link by a segment the two points marked with `1`, then link
      together the points marked with `2`, and so on. The permutation
      graph of `\sigma` is the intersection graph of those segments: there
      exists a vertex in this graph for each element from `1` to `n`, two
      vertices `i, j` being adjacent if the segments `i` and `j` cross
      each other.

    The set of edges of the permutation graph can thus be identified with
    the set of inversions of the inverse of the given permutation
    `\sigma`.

    A more general notion of permutation graph can be defined as
    follows: If `S` is a set, and `(a_1, a_2, \ldots, a_n)` and
    `(b_1, b_2, \ldots, b_n)` are two lists of elements of `S`, each of
    which lists contains every element of `S` exactly once, then the
    permutation graph defined by these two lists is the graph on the
    vertex set `S` in which two vertices `i` and `j` are connected by an
    edge if and only if the order in which these vertices appear in the
    list `(a_1, a_2, \ldots, a_n)` is the opposite of the order in which
    they appear in the list `(b_1, b_2, \ldots, b_n)`. When
    `(a_1, a_2, \ldots, a_n) = (1, 2, \ldots, n)`, this graph is the
    permutation graph of the permutation
    `(b_1, b_2, \ldots, b_n) \in S_n`. Notice that `S` does not have to
    be a set of integers here, but can be a set of strings, tuples, or
    anything else. We can still use the above visual description to
    construct the permutation graph, but now we have to mark points
    `a_1, a_2, \ldots, a_n` from left to right on the first horizontal
    line and points `b_1, b_2, \ldots, b_n` from left to right on the
    second horizontal line.

    INPUT:

    - ``second_permutation`` -- the unique permutation/list defining the graph,
      or the second of the two (if the graph is to be built from two
      permutations/lists).

    - ``first_permutation`` (optional) -- the first of the two
      permutations/lists from which the graph should be built, if it is to be
      built from two permutations/lists.

      When ``first_permutation is None`` (default), it is set to be equal to
      ``sorted(second_permutation)``, which yields the expected ordering when
      the elements of the graph are integers.

    .. SEEALSO:

      - Recognition of Permutation graphs in the :mod:`comparability module
        <sage.graphs.comparability>`.

      - Drawings of permutation graphs as intersection graphs of segments is
        possible through the
        :meth:`~sage.combinat.permutation.Permutation.show` method of
        :class:`~sage.combinat.permutation.Permutation` objects.

        The correct argument to use in this case is ``show(representation =
        "braid")``.

      - :meth:`~sage.combinat.permutation.Permutation.inversions`

    EXAMPLES::

        sage: p = Permutations(5).random_element()
        sage: PG = graphs.PermutationGraph(p)
        sage: edges = PG.edges(labels=False)
        sage: set(edges) == set(p.inverse().inversions())
        True

        sage: PG = graphs.PermutationGraph([3,4,5,1,2])
        sage: sorted(PG.edges())
        [(1, 3, None),
         (1, 4, None),
         (1, 5, None),
         (2, 3, None),
         (2, 4, None),
         (2, 5, None)]
        sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3])
        sage: sorted(PG.edges())
        [(1, 3, None),
         (1, 4, None),
         (1, 5, None),
         (2, 3, None),
         (2, 5, None),
         (3, 4, None),
         (3, 5, None)]
        sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2])
        sage: sorted(PG.edges())
        [(1, 3, None),
         (1, 4, None),
         (1, 5, None),
         (2, 3, None),
         (2, 5, None),
         (3, 4, None),
         (3, 5, None)]

        sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3]))
        sage: sorted(PG.edges())
        [(2, 3, None)]

        sage: graphs.PermutationGraph([]).edges()
        []
        sage: graphs.PermutationGraph([], []).edges()
        []

        sage: PG = graphs.PermutationGraph("graph", "phrag")
        sage: sorted(PG.edges())
        [('a', 'g', None),
         ('a', 'h', None),
         ('a', 'p', None),
         ('g', 'h', None),
         ('g', 'p', None),
         ('g', 'r', None),
         ('h', 'r', None),
         ('p', 'r', None)]

    TESTS::

        sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6])
        Traceback (most recent call last):
        ...
        ValueError: The two permutations do not contain the same set of elements ...
    """
    if first_permutation is None:
        first_permutation = sorted(second_permutation)
    else:
        if set(second_permutation) != set(first_permutation):
            raise ValueError("The two permutations do not contain the same "+
                             "set of elements ! It is going to be pretty "+
                             "hard to define a permutation graph from that !")

    vertex_to_index = {}
    for i, v in enumerate(first_permutation):
        vertex_to_index[v] = i+1

    from sage.combinat.permutation import Permutation
    p2 = Permutation([vertex_to_index[x] for x in second_permutation])
    p2 = p2.inverse()

    g = Graph(name="Permutation graph for "+str(second_permutation))
    g.add_vertices(second_permutation)

    for u,v in p2.inversions():
        g.add_edge(first_permutation[u-1], first_permutation[v-1])

    return g
Example #24
0
def Grid2dGraph(p, q, set_positions=True):
    r"""
    Return a `2`-dimensional grid graph with `p \times q` nodes (`p` rows and
    `q` columns).

    A 2d grid graph resembles a `2` dimensional grid. All inner nodes are
    connected to their `4` neighbors. Outer (non-corner) nodes are connected to
    their `3` neighbors. Corner nodes are connected to their 2 neighbors.

    INPUT:

    - ``p`` and ``q`` -- two positive integers

    - ``set_positions`` -- boolean (default: ``True``); whether to set the
      position of the nodes

    PLOTTING: Upon construction, the position dictionary is filled to override
    the spring-layout algorithm. By convention, nodes are labelled in (row,
    column) pairs with `(0, 0)` in the top left corner. Edges will always be
    horizontal and vertical - another advantage of filling the position
    dictionary.

    EXAMPLES:

    Construct and show a grid 2d graph Rows = `5`, Columns = `7`::

        sage: g = graphs.Grid2dGraph(5,7)
        sage: g.show()  # long time

    TESTS:

    Senseless input::

        sage: graphs.Grid2dGraph(5,0)
        Traceback (most recent call last):
        ...
        ValueError: parameters p and q must be positive integers
        sage: graphs.Grid2dGraph(-1,0)
        Traceback (most recent call last):
        ...
        ValueError: parameters p and q must be positive integers

    The graph name contains the dimension::

        sage: g = graphs.Grid2dGraph(5,7)
        sage: g.name()
        '2D Grid Graph for [5, 7]'
    """
    if p <= 0 or q <= 0:
        raise ValueError("parameters p and q must be positive integers")

    pos_dict = {}
    if set_positions:
        for i in range(p):
            y = -i
            for j in range(q):
                x = j
                pos_dict[i, j] = (x, y)

    G = Graph(pos=pos_dict, name="2D Grid Graph for [{}, {}]".format(p, q))
    G.add_vertices((i, j) for i in range(p) for j in range(q))
    G.add_edges(((i, j), (i + 1, j)) for i in range(p - 1) for j in range(q))
    G.add_edges(((i, j), (i, j + 1)) for i in range(p) for j in range(q - 1))
    return G
Example #25
0
File: bibd.py Project: Etn40ff/sage
def _check_pbd(B,v,S):
    r"""
    Checks that ``B`` is a PBD on ``v`` points with given block sizes ``S``.

    The points of the balanced incomplete block design are implicitely assumed
    to be `\{0, ..., v-1\}`.

    INPUT:

    - ``B`` -- a list of blocks

    - ``v`` (integer) -- number of points

    - ``S`` -- list of integers `\geq 2`.

    EXAMPLE::

        sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest
        [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10],
         [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28],
         [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34],
        ...
        sage: from sage.combinat.designs.bibd import _check_pbd
        sage: _check_pbd([[1],[]],1,[1,0])
        Traceback (most recent call last):
        ...
        RuntimeError: All integers of S must be >=2

    TESTS::

        sage: _check_pbd([[1,2]],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The PBD covers a point 2 which is not in {0, 1}
        sage: _check_pbd([[1,2]]*2,2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The pair (1,2) is covered more than once
        sage: _check_pbd([],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The pair (0,1) is not covered
        sage: _check_pbd([[1,2],[1]],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: A block has size 1 while S=[2]
    """
    from itertools import combinations
    from sage.graphs.graph import Graph

    for X in B:
        if len(X) not in S:
            raise RuntimeError("A block has size {} while S={}".format(len(X),S))

    if any(x < 2 for x in S):
        raise RuntimeError("All integers of S must be >=2")

    if v == 0 or v == 1:
        if B:
            raise RuntimeError("A PBD with v<=1 is expected to be empty.")

    g = Graph()
    g.add_vertices(range(v))
    m = 0
    for X in B:
        for i,j in combinations(X,2):
            g.add_edge(i,j)
            m_tmp = g.size()
            if m_tmp != m+1:
                raise RuntimeError("The pair ({},{}) is covered more than once".format(i,j))
            m = m_tmp

    if g.vertices() != range(v):
        from sage.sets.integer_range import IntegerRange
        p = (set(g.vertices())-set(range(v))).pop()
        raise RuntimeError("The PBD covers a point {} which is not in {}".format(p,IntegerRange(v)))

    if not g.is_clique():
        for p1 in g:
            if g.degree(p1) != v-1:
                break
        neighbors = g.neighbors(p1)+[p1]
        p2 = (set(g.vertices())-set(neighbors)).pop()
        raise RuntimeError("The pair ({},{}) is not covered".format(p1,p2))

    return B
Example #26
0
def PermutationGraph(second_permutation, first_permutation=None):
    r"""
    Build a permutation graph from one permutation or from two lists.

    Definition:

    If `\sigma` is a permutation of `\{ 1, 2, \ldots, n \}`, then the
    permutation graph of `\sigma` is the graph on vertex set
    `\{ 1, 2, \ldots, n \}` in which two vertices `i` and `j` satisfying
    `i < j` are connected by an edge if and only if
    `\sigma^{-1}(i) > \sigma^{-1}(j)`. A visual way to construct this
    graph is as follows:

      Take two horizontal lines in the euclidean plane, and mark points
      `1, ..., n` from left to right on the first of them. On the second
      one, still from left to right, mark `n` points
      `\sigma(1), \sigma(2), \ldots, \sigma(n)`.
      Now, link by a segment the two points marked with `1`, then link
      together the points marked with `2`, and so on. The permutation
      graph of `\sigma` is the intersection graph of those segments: there
      exists a vertex in this graph for each element from `1` to `n`, two
      vertices `i, j` being adjacent if the segments `i` and `j` cross
      each other.

    The set of edges of the permutation graph can thus be identified with
    the set of inversions of the inverse of the given permutation
    `\sigma`.

    A more general notion of permutation graph can be defined as
    follows: If `S` is a set, and `(a_1, a_2, \ldots, a_n)` and
    `(b_1, b_2, \ldots, b_n)` are two lists of elements of `S`, each of
    which lists contains every element of `S` exactly once, then the
    permutation graph defined by these two lists is the graph on the
    vertex set `S` in which two vertices `i` and `j` are connected by an
    edge if and only if the order in which these vertices appear in the
    list `(a_1, a_2, \ldots, a_n)` is the opposite of the order in which
    they appear in the list `(b_1, b_2, \ldots, b_n)`. When
    `(a_1, a_2, \ldots, a_n) = (1, 2, \ldots, n)`, this graph is the
    permutation graph of the permutation
    `(b_1, b_2, \ldots, b_n) \in S_n`. Notice that `S` does not have to
    be a set of integers here, but can be a set of strings, tuples, or
    anything else. We can still use the above visual description to
    construct the permutation graph, but now we have to mark points
    `a_1, a_2, \ldots, a_n` from left to right on the first horizontal
    line and points `b_1, b_2, \ldots, b_n` from left to right on the
    second horizontal line.

    INPUT:

    - ``second_permutation`` -- the unique permutation/list defining the graph,
      or the second of the two (if the graph is to be built from two
      permutations/lists).

    - ``first_permutation`` (optional) -- the first of the two
      permutations/lists from which the graph should be built, if it is to be
      built from two permutations/lists.

      When ``first_permutation is None`` (default), it is set to be equal to
      ``sorted(second_permutation)``, which yields the expected ordering when
      the elements of the graph are integers.

    .. SEEALSO::

      - Recognition of Permutation graphs in the :mod:`comparability module
        <sage.graphs.comparability>`.

      - Drawings of permutation graphs as intersection graphs of segments is
        possible through the
        :meth:`~sage.combinat.permutation.Permutation.show` method of
        :class:`~sage.combinat.permutation.Permutation` objects.

        The correct argument to use in this case is ``show(representation =
        "braid")``.

      - :meth:`~sage.combinat.permutation.Permutation.inversions`

    EXAMPLES::

        sage: p = Permutations(5).random_element()
        sage: PG = graphs.PermutationGraph(p)
        sage: edges = PG.edges(labels=False)
        sage: set(edges) == set(p.inverse().inversions())
        True

        sage: PG = graphs.PermutationGraph([3,4,5,1,2])
        sage: sorted(PG.edges())
        [(1, 3, None),
         (1, 4, None),
         (1, 5, None),
         (2, 3, None),
         (2, 4, None),
         (2, 5, None)]
        sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3])
        sage: sorted(PG.edges())
        [(1, 3, None),
         (1, 4, None),
         (1, 5, None),
         (2, 3, None),
         (2, 5, None),
         (3, 4, None),
         (3, 5, None)]
        sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2])
        sage: sorted(PG.edges())
        [(1, 3, None),
         (1, 4, None),
         (1, 5, None),
         (2, 3, None),
         (2, 5, None),
         (3, 4, None),
         (3, 5, None)]

        sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3]))
        sage: sorted(PG.edges())
        [(2, 3, None)]

        sage: graphs.PermutationGraph([]).edges()
        []
        sage: graphs.PermutationGraph([], []).edges()
        []

        sage: PG = graphs.PermutationGraph("graph", "phrag")
        sage: sorted(PG.edges())
        [('a', 'g', None),
         ('a', 'h', None),
         ('a', 'p', None),
         ('g', 'h', None),
         ('g', 'p', None),
         ('g', 'r', None),
         ('h', 'r', None),
         ('p', 'r', None)]

    TESTS::

        sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6])
        Traceback (most recent call last):
        ...
        ValueError: The two permutations do not contain the same set of elements ...
    """
    if first_permutation is None:
        first_permutation = sorted(second_permutation)
    else:
        if set(second_permutation) != set(first_permutation):
            raise ValueError("The two permutations do not contain the same " +
                             "set of elements ! It is going to be pretty " +
                             "hard to define a permutation graph from that !")

    vertex_to_index = {}
    for i, v in enumerate(first_permutation):
        vertex_to_index[v] = i + 1

    from sage.combinat.permutation import Permutation
    p2 = Permutation([vertex_to_index[x] for x in second_permutation])
    p2 = p2.inverse()

    g = Graph(name="Permutation graph for " + str(second_permutation))
    g.add_vertices(second_permutation)

    for u, v in p2.inversions():
        g.add_edge(first_permutation[u - 1], first_permutation[v - 1])

    return g
Example #27
0
def RandomBipartite(n1,n2, p):
    r"""
    Returns a bipartite graph with `n1+n2` vertices
    such that any edge from `[n1]` to `[n2]` exists
    with probability `p`.

    INPUT:

        - ``n1,n2`` : Cardinalities of the two sets
        - ``p``   : Probability for an edge to exist


    EXAMPLE::

        sage: g=graphs.RandomBipartite(5,2,0.5)
        sage: g.vertices()
        [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]

    TESTS::

        sage: g=graphs.RandomBipartite(5,-3,0.5)
        Traceback (most recent call last):
        ...
        ValueError: n1 and n2 should be integers strictly greater than 0
        sage: g=graphs.RandomBipartite(5,3,1.5)
        Traceback (most recent call last):
        ...
        ValueError: Parameter p is a probability, and so should be a real value between 0 and 1

    Trac ticket #12155::

        sage: graphs.RandomBipartite(5,6,.2).complement()
        complement(Random bipartite graph of size 5+6 with edge probability 0.200000000000000): Graph on 11 vertices
    """
    if not (p>=0 and p<=1):
        raise ValueError, "Parameter p is a probability, and so should be a real value between 0 and 1"
    if not (n1>0 and n2>0):
        raise ValueError, "n1 and n2 should be integers strictly greater than 0"

    from numpy.random import uniform

    g=Graph(name="Random bipartite graph of size "+str(n1) +"+"+str(n2)+" with edge probability "+str(p))

    S1=[(0,i) for i in range(n1)]
    S2=[(1,i) for i in range(n2)]
    g.add_vertices(S1)
    g.add_vertices(S2)

    for w in range(n2):
        for v in range(n1):
            if uniform()<=p :
                g.add_edge((0,v),(1,w))

    pos = {}
    for i in range(n1):
        pos[(0,i)] = (0, i/(n1-1.0))
    for i in range(n2):
        pos[(1,i)] = (1, i/(n2-1.0))

    g.set_pos(pos)

    return g
Example #28
0
def EuropeMap(continental=False, year=2018):
    """
    Return European states as a graph of common border.

    "European state" here is defined as an independent
    state having the capital city in Europe. The graph
    has an edge between those countries that have common
    *land* border.

    INPUT:

    - ``continental``, a Boolean -- if set, only return states in
      the continental Europe
    - ``year`` -- reserved for future use

    EXAMPLES::

        sage: Europe = graphs.EuropeMap(); Europe
        Europe Map: Graph on 44 vertices
        sage: Europe.neighbors('Ireland')
        ['United Kingdom']

        sage: cont_Europe = graphs.EuropeMap(continental=True)
        sage: cont_Europe.order()
        40
        sage: 'Iceland' in cont_Europe
        False
    """
    if year != 2018:
        raise ValueError("currently only year 2018 is implemented")

    common_border = {
        'Poland': [
            'Slovakia', 'Czech Republic', 'Lithuania', 'Russia', 'Ukraine',
            'Germany'
        ],
        'Germany': [
            'Czech Republic', 'Netherlands', 'Switzerland', 'Luxembourg',
            'Denmark'
        ],
        'Croatia': [
            'Bosnia and Herzegovina', 'Serbia', 'Hungary', 'Montenegro',
            'Slovenia'
        ],
        'Austria': [
            'Czech Republic', 'Germany', 'Switzerland', 'Slovenia',
            'Liechtenstein'
        ],
        'France':
        ['Germany', 'Italy', 'Switzerland', 'Monaco', 'Luxembourg', 'Andorra'],
        'Hungary':
        ['Slovakia', 'Serbia', 'Romania', 'Ukraine', 'Slovenia', 'Austria'],
        'Italy':
        ['Switzerland', 'Vatican City', 'San Marino', 'Slovenia', 'Austria'],
        'Belarus': ['Poland', 'Latvia', 'Lithuania', 'Russia', 'Ukraine'],
        'Montenegro': ['Bosnia and Herzegovina', 'Serbia', 'Albania'],
        'Belgium': ['Germany', 'Netherlands', 'Luxembourg', 'France'],
        'Russia': ['Finland', 'Lithuania', 'Estonia', 'Ukraine'],
        'Romania': ['Serbia', 'Moldova', 'Bulgaria', 'Ukraine'],
        'Latvia': ['Lithuania', 'Russia', 'Estonia'],
        'Slovakia': ['Czech Republic', 'Ukraine', 'Austria'],
        'Switzerland': ['Liechtenstein'],
        'Spain': ['Portugal', 'Andorra', 'France'],
        'Norway': ['Finland', 'Sweden', 'Russia'],
        'Ireland': ['United Kingdom'],
        'Serbia': ['Bosnia and Herzegovina', 'Bulgaria'],
        'Greece': ['Macedonia', 'Bulgaria', 'Albania'],
        'Ukraine': ['Moldova'],
        'Macedonia': ['Serbia', 'Bulgaria', 'Albania'],
        'Sweden': ['Finland']
    }
    no_land_border = ['Iceland', 'Malta']

    G = Graph(common_border, format='dict_of_lists')

    if continental:
        G = G.subgraph(G.connected_component_containing_vertex('Austria'))
        G.name(new="Continental Europe Map")
    else:
        G.add_vertices(no_land_border)
        G.name(new="Europe Map")

    return G
Example #29
0
def WorldMap():
    """
    Returns the Graph of all the countries, in which two countries are adjacent
    in the graph if they have a common boundary.

    This graph has been built from the data available
    in The CIA World Factbook [CIA]_ (2009-08-21).

    The returned graph ``G`` has a member ``G.gps_coordinates``
    equal to a dictionary containing the GPS coordinates
    of each country's capital city.

    EXAMPLES::

        sage: g = graphs.WorldMap()
        sage: g.has_edge("France", "Italy")
        True
        sage: g.gps_coordinates["Bolivia"]
        [[17, 'S'], [65, 'W']]
        sage: sorted(g.connected_component_containing_vertex('Ireland'))
        ['Ireland', 'United Kingdom']

    TESTS::

        sage: 'Iceland' in graphs.WorldMap()  # Trac 24488
        True

    REFERENCE:

    .. [CIA] CIA Factbook 09 https://www.cia.gov/library/publications/the-world-factbook/
    """
    edges = [
        ('Afghanistan', 'China', None), ('Afghanistan', 'Iran', None),
        ('Afghanistan', 'Uzbekistan', None), ('Albania', 'Greece', None),
        ('Albania', 'Kosovo', None), ('Albania', 'Macedonia', None),
        ('Albania', 'Montenegro', None), ('Algeria', 'Morocco', None),
        ('Algeria', 'Tunisia', None), ('Andorra', 'Spain', None),
        ('Angola', 'Democratic Republic of the Congo', None), ('Angola', 'Namibia', None),
        ('Angola', 'Zambia', None), ('Argentina', 'Bolivia', None),
        ('Argentina', 'Brazil', None), ('Argentina', 'Chile', None),
        ('Argentina', 'Paraguay', None), ('Argentina', 'Uruguay', None),
        ('Armenia', 'Georgia', None), ('Armenia', 'Iran', None),
        ('Austria', 'Germany', None), ('Azerbaijan', 'Armenia', None),
        ('Azerbaijan', 'Georgia', None), ('Azerbaijan', 'Iran', None),
        ('Azerbaijan', 'Russia', None), ('Azerbaijan', 'Turkey', None),
        ('Bangladesh', 'Burma', None), ('Belgium', 'Germany', None),
        ('Belgium', 'Netherlands', None), ('Belize', 'Mexico', None),
        ('Benin', 'Burkina Faso', None), ('Benin', 'Niger', None),
        ('Benin', 'Nigeria', None), ('Benin', 'Togo', None),
        ('Bolivia', 'Brazil', None), ('Bolivia', 'Chile', None),
        ('Bolivia', 'Paraguay', None), ('Bolivia', 'Peru', None),
        ('Bosnia and Herzegovina', 'Croatia', None), ('Bosnia and Herzegovina', 'Montenegro', None),
        ('Bosnia and Herzegovina', 'Serbia', None), ('Brazil', 'Colombia', None),
        ('Brazil', 'Guyana', None), ('Brazil', 'Suriname', None),
        ('Brazil', 'Venezuela', None), ('Bulgaria', 'Greece', None),
        ('Bulgaria', 'Macedonia', None), ('Bulgaria', 'Romania', None),
        ('Bulgaria', 'Serbia', None), ('Burkina Faso', 'Mali', None),
        ('Burkina Faso', 'Niger', None), ('Burkina Faso', 'Togo', None),
        ('Burundi', 'Democratic Republic of the Congo', None), ('Cambodia', 'Laos', None),
        ('Cambodia', 'Thailand', None), ('Cambodia', 'Vietnam', None),
        ('Cameroon', 'Central African Republic', None), ('Cameroon', 'Chad', None),
        ('Cameroon', 'Equatorial Guinea', None), ('Cameroon', 'Nigeria', None),
        ('Cameroon', 'Republic of the Congo', None), ('Canada', 'United States', None),
        ('Central African Republic', 'Chad', None), ('Central African Republic', 'Democratic Republic of the Congo', None),
        ('Central African Republic', 'Sudan', None), ('Chad', 'Niger', None),
        ('Chad', 'Nigeria', None), ('Chad', 'Sudan', None),
        ('China', 'Bhutan', None), ('China', 'Burma', None),
        ('China', 'Hong Kong', None), ('China', 'Kazakhstan', None),
        ('China', 'Kyrgyzstan', None), ('China', 'Mongolia', None),
        ('China', 'Nepal', None), ('China', 'North Korea', None),
        ('China', 'Russia', None), ('China', 'Vietnam', None),
        ('Colombia', 'Venezuela', None), ('Costa Rica', 'Nicaragua', None),
        ("Cote d'Ivoire", 'Burkina Faso', None), ("Cote d'Ivoire", 'Guinea', None),
        ("Cote d'Ivoire", 'Mali', None), ('Cyprus', 'Akrotiri', None),
        ('Cyprus', 'Dhekelia', None), ('Czech Republic', 'Austria', None),
        ('Czech Republic', 'Germany', None), ('Czech Republic', 'Poland', None),
        ('Democratic Republic of the Congo', 'Zambia', None), ('Denmark', 'Germany', None),
        ('Djibouti', 'Eritrea', None), ('Dominican Republic', 'Haiti', None),
        ('Ecuador', 'Colombia', None), ('El Salvador', 'Honduras', None),
        ('Ethiopia', 'Djibouti', None), ('Ethiopia', 'Eritrea', None),
        ('Ethiopia', 'Kenya', None), ('Ethiopia', 'Somalia', None),
        ('Ethiopia', 'Sudan', None), ('Finland', 'Russia', None),
        ('Finland', 'Sweden', None), ('France', 'Andorra', None),
        ('France', 'Belgium', None), ('France', 'Brazil', None),
        ('France', 'Germany', None), ('France', 'Italy', None),
        ('France', 'Luxembourg', None), ('France', 'Spain', None),
        ('France', 'Suriname', None), ('France', 'Switzerland', None),
        ('Gabon', 'Cameroon', None), ('Gabon', 'Equatorial Guinea', None),
        ('Gabon', 'Republic of the Congo', None), ('Gaza Strip', 'Egypt', None),
        ('Gaza Strip', 'Israel', None), ('Ghana', 'Burkina Faso', None),
        ('Ghana', "Cote d'Ivoire", None), ('Ghana', 'Togo', None),
        ('Gibraltar', 'Spain', None), ('Guatemala', 'Belize', None),
        ('Guatemala', 'El Salvador', None), ('Guatemala', 'Honduras', None),
        ('Guatemala', 'Mexico', None), ('Guinea', 'Sierra Leone', None),
        ('Guinea-Bissau', 'Guinea', None), ('Guinea-Bissau', 'Senegal', None),
        ('Honduras', 'Nicaragua', None), ('Hungary', 'Austria', None),
        ('Hungary', 'Croatia', None), ('Hungary', 'Serbia', None),
        ('India', 'Bangladesh', None), ('India', 'Bhutan', None),
        ('India', 'Burma', None), ('India', 'China', None),
        ('India', 'Nepal', None), ('Indonesia', 'Papua New Guinea', None),
        ('Iran', 'Iraq', None), ('Ireland', 'United Kingdom', None),
        ('Israel', 'Egypt', None), ('Italy', 'Austria', None),
        ('Jordan', 'Iraq', None), ('Jordan', 'Israel', None),
        ('Jordan', 'Syria', None), ('Jordan', 'West Bank', None),
        ('Kazakhstan', 'Kyrgyzstan', None), ('Kenya', 'Somalia', None),
        ('Kenya', 'Sudan', None), ('Kenya', 'Uganda', None),
        ('Kosovo', 'Macedonia', None), ('Kosovo', 'Serbia', None),
        ('Kuwait', 'Iraq', None), ('Laos', 'Burma', None),
        ('Laos', 'China', None), ('Laos', 'Thailand', None),
        ('Laos', 'Vietnam', None), ('Latvia', 'Belarus', None),
        ('Latvia', 'Estonia', None), ('Lebanon', 'Israel', None),
        ('Lesotho', 'South Africa', None), ('Liberia', "Cote d'Ivoire", None),
        ('Liberia', 'Guinea', None), ('Liberia', 'Sierra Leone', None),
        ('Libya', 'Algeria', None), ('Libya', 'Chad', None),
        ('Libya', 'Egypt', None), ('Libya', 'Niger', None),
        ('Libya', 'Sudan', None), ('Libya', 'Tunisia', None),
        ('Liechtenstein', 'Austria', None), ('Liechtenstein', 'Switzerland', None),
        ('Lithuania', 'Belarus', None), ('Lithuania', 'Latvia', None),
        ('Lithuania', 'Poland', None), ('Lithuania', 'Russia', None),
        ('Luxembourg', 'Belgium', None), ('Luxembourg', 'Germany', None),
        ('Macau', 'China', None), ('Macedonia', 'Greece', None),
        ('Macedonia', 'Serbia', None), ('Malaysia', 'Brunei', None),
        ('Malaysia', 'Indonesia', None), ('Malaysia', 'Thailand', None),
        ('Mali', 'Algeria', None), ('Mali', 'Guinea', None),
        ('Mali', 'Niger', None), ('Mali', 'Senegal', None),
        ('Mauritania', 'Algeria', None), ('Mauritania', 'Mali', None),
        ('Mauritania', 'Senegal', None), ('Mauritania', 'Western Sahara', None),
        ('Monaco', 'France', None), ('Montenegro', 'Croatia', None),
        ('Montenegro', 'Kosovo', None), ('Montenegro', 'Serbia', None),
        ('Morocco', 'Spain', None), ('Mozambique', 'Malawi', None),
        ('Mozambique', 'Zambia', None), ('Mozambique', 'Zimbabwe', None),
        ('Namibia', 'Botswana', None), ('Namibia', 'Zambia', None),
        ('Netherlands', 'Germany', None), ('Niger', 'Algeria', None),
        ('Niger', 'Nigeria', None), ('Norway', 'Finland', None),
        ('Norway', 'Russia', None), ('Norway', 'Sweden', None),
        ('Oman', 'United Arab Emirates', None), ('Oman', 'Yemen', None),
        ('Pakistan', 'Afghanistan', None), ('Pakistan', 'China', None),
        ('Pakistan', 'India', None), ('Pakistan', 'Iran', None),
        ('Panama', 'Colombia', None), ('Panama', 'Costa Rica', None),
        ('Paraguay', 'Brazil', None), ('Peru', 'Brazil', None),
        ('Peru', 'Chile', None), ('Peru', 'Colombia', None),
        ('Peru', 'Ecuador', None), ('Poland', 'Belarus', None),
        ('Poland', 'Germany', None), ('Portugal', 'Spain', None),
        ('Republic of the Congo', 'Angola', None), ('Republic of the Congo', 'Central African Republic', None),
        ('Republic of the Congo', 'Democratic Republic of the Congo', None), ('Romania', 'Hungary', None),
        ('Romania', 'Moldova', None), ('Romania', 'Serbia', None),
        ('Russia', 'Belarus', None), ('Russia', 'Estonia', None),
        ('Russia', 'Georgia', None), ('Russia', 'Kazakhstan', None),
        ('Russia', 'Latvia', None), ('Russia', 'Mongolia', None),
        ('Russia', 'North Korea', None), ('Russia', 'Poland', None),
        ('Rwanda', 'Burundi', None), ('Rwanda', 'Democratic Republic of the Congo', None),
        ('Rwanda', 'Uganda', None), ('Saint Martin', 'Netherlands Antilles', None),
        ('San Marino', 'Italy', None), ('Saudi Arabia', 'Iraq', None),
        ('Saudi Arabia', 'Jordan', None), ('Saudi Arabia', 'Kuwait', None),
        ('Saudi Arabia', 'Oman', None), ('Saudi Arabia', 'Qatar', None),
        ('Saudi Arabia', 'United Arab Emirates', None), ('Saudi Arabia', 'Yemen', None),
        ('Senegal', 'Guinea', None), ('Serbia', 'Croatia', None),
        ('Slovakia', 'Austria', None), ('Slovakia', 'Czech Republic', None),
        ('Slovakia', 'Hungary', None), ('Slovakia', 'Poland', None),
        ('Slovakia', 'Ukraine', None), ('Slovenia', 'Austria', None),
        ('Slovenia', 'Croatia', None), ('Slovenia', 'Hungary', None),
        ('Slovenia', 'Italy', None), ('Somalia', 'Djibouti', None),
        ('South Africa', 'Botswana', None), ('South Africa', 'Mozambique', None),
        ('South Africa', 'Namibia', None), ('South Africa', 'Zimbabwe', None),
        ('South Korea', 'North Korea', None), ('Sudan', 'Democratic Republic of the Congo', None),
        ('Sudan', 'Egypt', None), ('Sudan', 'Eritrea', None),
        ('Suriname', 'Guyana', None), ('Swaziland', 'Mozambique', None),
        ('Swaziland', 'South Africa', None), ('Switzerland', 'Austria', None),
        ('Switzerland', 'Germany', None), ('Switzerland', 'Italy', None),
        ('Syria', 'Iraq', None), ('Syria', 'Israel', None),
        ('Syria', 'Lebanon', None), ('Tajikistan', 'Afghanistan', None),
        ('Tajikistan', 'China', None), ('Tajikistan', 'Kyrgyzstan', None),
        ('Tajikistan', 'Uzbekistan', None), ('Tanzania', 'Burundi', None),
        ('Tanzania', 'Democratic Republic of the Congo', None), ('Tanzania', 'Kenya', None),
        ('Tanzania', 'Malawi', None), ('Tanzania', 'Mozambique', None),
        ('Tanzania', 'Rwanda', None), ('Tanzania', 'Uganda', None),
        ('Tanzania', 'Zambia', None), ('Thailand', 'Burma', None),
        ('The Gambia', 'Senegal', None), ('Timor-Leste', 'Indonesia', None),
        ('Turkey', 'Armenia', None), ('Turkey', 'Bulgaria', None),
        ('Turkey', 'Georgia', None), ('Turkey', 'Greece', None),
        ('Turkey', 'Iran', None), ('Turkey', 'Iraq', None),
        ('Turkey', 'Syria', None), ('Turkmenistan', 'Afghanistan', None),
        ('Turkmenistan', 'Iran', None), ('Turkmenistan', 'Kazakhstan', None),
        ('Turkmenistan', 'Uzbekistan', None), ('Uganda', 'Democratic Republic of the Congo', None),
        ('Uganda', 'Sudan', None), ('Ukraine', 'Belarus', None),
        ('Ukraine', 'Hungary', None), ('Ukraine', 'Moldova', None),
        ('Ukraine', 'Poland', None), ('Ukraine', 'Romania', None),
        ('Ukraine', 'Russia', None), ('United States', 'Mexico', None),
        ('Uruguay', 'Brazil', None), ('Uzbekistan', 'Kazakhstan', None),
        ('Uzbekistan', 'Kyrgyzstan', None), ('Vatican City', 'Italy', None),
        ('Venezuela', 'Guyana', None), ('West Bank', 'Israel', None),
        ('Western Sahara', 'Algeria', None), ('Western Sahara', 'Morocco', None),
        ('Zambia', 'Malawi', None), ('Zambia', 'Zimbabwe', None),
        ('Zimbabwe', 'Botswana', None)
        ]
    gps_coordinates = {
        'Canada': [[60, 'N'], [95, 'W']],
        'Saint Martin': [[18, 'N'], [63, 'W']],
        'Sao Tome and Principe': [[1, 'N'], [7, 'E']],
        'Turkmenistan': [[40, 'N'], [60, 'E']],
        'Saint Helena': [[15, 'S'], [5, 'W']],
        'Lithuania': [[56, 'N'], [24, 'E']],
        'Cambodia': [[13, 'N'], [105, 'E']],
        'Saint Kitts and Nevis': [[17, 'N'], [62, 'W']],
        'Ethiopia': [[8, 'N'], [38, 'E']],
        'The Gambia': [[13, 'N'], [16, 'W']],
        'Aruba': [[12, 'N'], [69, 'W']],
        'Swaziland': [[26, 'S'], [31, 'E']],
        'Guinea-Bissau': [[12, 'N'], [15, 'W']],
        'Argentina': [[34, 'S'], [64, 'W']],
        'Bolivia': [[17, 'S'], [65, 'W']],
        'Bahamas, The': [[24, 'N'], [76, 'W']],
        'Spratly Islands': [[8, 'N'], [111, 'E']],
        'Ghana': [[8, 'N'], [2, 'W']],
        'Saudi Arabia': [[25, 'N'], [45, 'E']],
        'American Samoa': [[14, 'S'], [170, 'W']],
        'Cocos (Keeling) Islands': [[12, 'S'], [96, 'E']],
        'Slovenia': [[46, 'N'], [14, 'E']],
        'Guatemala': [[15, 'N'], [90, 'W']],
        'Bosnia and Herzegovina': [[44, 'N'], [18, 'E']],
        'Kuwait': [[29, 'N'], [45, 'E']],
        'Jordan': [[31, 'N'], [36, 'E']],
        'Saint Barthelemy': [[17, 'N'], [62, 'W']],
        'Ashmore and Cartier Islands': [[12, 'S'], [123, 'E']],
        'Dominica': [[15, 'N'], [61, 'W']],
        'Liberia': [[6, 'N'], [9, 'W']],
        'Maldives': [[3, 'N'], [73, 'E']],
        'Micronesia, Federated States of': [[6, 'N'], [158, 'E']],
        'Pakistan': [[30, 'N'], [70, 'E']],
        'Oman': [[21, 'N'], [57, 'E']],
        'Tanzania': [[6, 'S'], [35, 'E']],
        'Albania': [[41, 'N'], [20, 'E']],
        'Gabon': [[1, 'S'], [11, 'E']],
        'Niue': [[19, 'S'], [169, 'W']],
        'Monaco': [[43, 'N'], [7, 'E']],
        'Wallis and Futuna': [[13, 'S'], [176, 'W']],
        'New Zealand': [[41, 'S'], [174, 'E']],
        'Yemen': [[15, 'N'], [48, 'E']],
        'Jersey': [[49, 'N'], [2, 'W']],
        'Jamaica': [[18, 'N'], [77, 'W']],
        'Greenland': [[72, 'N'], [40, 'W']],
        'West Bank': [[32, 'N'], [35, 'E']],
        'Macau': [[22, 'N'], [113, 'E']],
        'Jan Mayen': [[71, 'N'], [8, 'W']],
        'United Arab Emirates': [[24, 'N'], [54, 'E']],
        'Guam': [[13, 'N'], [144, 'E']],
        'Uruguay': [[33, 'S'], [56, 'W']],
        'India': [[20, 'N'], [77, 'E']],
        'Azerbaijan': [[40, 'N'], [47, 'E']],
        'Lesotho': [[29, 'S'], [28, 'E']],
        'Saint Vincent and the Grenadines': [[13, 'N'], [61, 'W']],
        'Kenya': [[1, 'N'], [38, 'E']],
        'South Korea': [[37, 'N'], [127, 'E']],
        'Tajikistan': [[39, 'N'], [71, 'E']],
        'Turkey': [[39, 'N'], [35, 'E']],
        'Afghanistan': [[33, 'N'], [65, 'E']],
        'Paraguay': [[23, 'S'], [58, 'W']],
        'Bangladesh': [[24, 'N'], [90, 'E']],
        'Mauritania': [[20, 'N'], [12, 'W']],
        'Solomon Islands': [[8, 'S'], [159, 'E']],
        'Saint Pierre and Miquelon': [[46, 'N'], [56, 'W']],
        'Gaza Strip': [[31, 'N'], [34, 'E']],
        'San Marino': [[43, 'N'], [12, 'E']],
        'French Polynesia': [[15, 'S'], [140, 'W']],
        'France': [[46, 'N'], [2, 'E']],
        'Fiji': [[18, 'S'], [175, 'E']],
        'Rwanda': [[2, 'S'], [30, 'E']],
        'Slovakia': [[48, 'N'], [19, 'E']],
        'Somalia': [[10, 'N'], [49, 'E']],
        'Peru': [[10, 'S'], [76, 'W']],
        'Laos': [[18, 'N'], [105, 'E']],
        'Nauru': [[0, 'S'], [166, 'E']],
        'Seychelles': [[4, 'S'], [55, 'E']],
        'Norway': [[62, 'N'], [10, 'E']],
        "Cote d'Ivoire": [[8, 'N'], [5, 'W']],
        'Cook Islands': [[21, 'S'], [159, 'W']],
        'Benin': [[9, 'N'], [2, 'E']],
        'Western Sahara': [[24, 'N'], [13, 'W']],
        'Cuba': [[21, 'N'], [80, 'W']],
        'Cameroon': [[6, 'N'], [12, 'E']],
        'Montenegro': [[42, 'N'], [19, 'E']],
        'Republic of the Congo': [[1, 'S'], [15, 'E']],
        'Burkina Faso': [[13, 'N'], [2, 'W']],
        'Togo': [[8, 'N'], [1, 'E']],
        'Virgin Islands': [[18, 'N'], [64, 'W']],
        'China': [[35, 'N'], [105, 'E']],
        'Armenia': [[40, 'N'], [45, 'E']],
        'Timor-Leste': [[8, 'S'], [125, 'E']],
        'Dominican Republic': [[19, 'N'], [70, 'W']],
        'Ukraine': [[49, 'N'], [32, 'E']],
        'Bahrain': [[26, 'N'], [50, 'E']],
        'Tonga': [[20, 'S'], [175, 'W']],
        'Finland': [[64, 'N'], [26, 'E']],
        'Libya': [[25, 'N'], [17, 'E']],
        'Cayman Islands': [[19, 'N'], [80, 'W']],
        'Central African Republic': [[7, 'N'], [21, 'E']],
        'New Caledonia': [[21, 'S'], [165, 'E']],
        'Mauritius': [[20, 'S'], [57, 'E']],
        'Liechtenstein': [[47, 'N'], [9, 'E']],
        'Vietnam': [[16, 'N'], [107, 'E']],
        'British Virgin Islands': [[18, 'N'], [64, 'W']],
        'Mali': [[17, 'N'], [4, 'W']],
        'Vatican City': [[41, 'N'], [12, 'E']],
        'Russia': [[60, 'N'], [100, 'E']],
        'Bulgaria': [[43, 'N'], [25, 'E']],
        'United States': [[38, 'N'], [97, 'W']],
        'Romania': [[46, 'N'], [25, 'E']],
        'Angola': [[12, 'S'], [18, 'E']],
        'Chad': [[15, 'N'], [19, 'E']],
        'South Africa': [[29, 'S'], [24, 'E']],
        'Tokelau': [[9, 'S'], [172, 'W']],
        'Turks and Caicos Islands': [[21, 'N'], [71, 'W']],
        'South Georgia and the South Sandwich Islands': [[54, 'S'], [37, 'W']],
        'Sweden': [[62, 'N'], [15, 'E']],
        'Qatar': [[25, 'N'], [51, 'E']],
        'Malaysia': [[2, 'N'], [112, 'E']],
        'Senegal': [[14, 'N'], [14, 'W']],
        'Latvia': [[57, 'N'], [25, 'E']],
        'Clipperton Island': [[10, 'N'], [109, 'W']],
        'Uganda': [[1, 'N'], [32, 'E']],
        'Japan': [[36, 'N'], [138, 'E']],
        'Niger': [[16, 'N'], [8, 'E']],
        'Brazil': [[10, 'S'], [55, 'W']],
        'Faroe Islands': [[62, 'N'], [7, 'W']],
        'Guinea': [[11, 'N'], [10, 'W']],
        'Panama': [[9, 'N'], [80, 'W']],
        'Costa Rica': [[10, 'N'], [84, 'W']],
        'Luxembourg': [[49, 'N'], [6, 'E']],
        'Cape Verde': [[16, 'N'], [24, 'W']],
        'Andorra': [[42, 'N'], [1, 'E']],
        'Gibraltar': [[36, 'N'], [5, 'W']],
        'Ireland': [[53, 'N'], [8, 'W']],
        'Syria': [[35, 'N'], [38, 'E']],
        'Palau': [[7, 'N'], [134, 'E']],
        'Nigeria': [[10, 'N'], [8, 'E']],
        'Ecuador': [[2, 'S'], [77, 'W']],
        'Northern Mariana Islands': [[15, 'N'], [145, 'E']],
        'Brunei': [[4, 'N'], [114, 'E']],
        'Mozambique': [[18, 'S'], [35, 'E']],
        'Australia': [[27, 'S'], [133, 'E']],
        'Iran': [[32, 'N'], [53, 'E']],
        'Algeria': [[28, 'N'], [3, 'E']],
        'Svalbard': [[78, 'N'], [20, 'E']],
        'El Salvador': [[13, 'N'], [88, 'W']],
        'Tuvalu': [[8, 'S'], [178, 'E']],
        'Pitcairn Islands': [[25, 'S'], [130, 'W']],
        'Czech Republic': [[49, 'N'], [15, 'E']],
        'Marshall Islands': [[9, 'N'], [168, 'E']],
        'Chile': [[30, 'S'], [71, 'W']],
        'Puerto Rico': [[18, 'N'], [66, 'W']],
        'Belgium': [[50, 'N'], [4, 'E']],
        'Kiribati': [[1, 'N'], [173, 'E']],
        'Haiti': [[19, 'N'], [72, 'W']],
        'Belize': [[17, 'N'], [88, 'W']],
        'Hong Kong': [[22, 'N'], [114, 'E']],
        'Saint Lucia': [[13, 'N'], [60, 'W']],
        'Georgia': [[42, 'N'], [43, 'E']],
        'Mexico': [[23, 'N'], [102, 'W']],
        'Denmark': [[56, 'N'], [10, 'E']],
        'Poland': [[52, 'N'], [20, 'E']],
        'Moldova': [[47, 'N'], [29, 'E']],
        'Morocco': [[32, 'N'], [5, 'W']],
        'Namibia': [[22, 'S'], [17, 'E']],
        'Mongolia': [[46, 'N'], [105, 'E']],
        'Guernsey': [[49, 'N'], [2, 'W']],
        'Thailand': [[15, 'N'], [100, 'E']],
        'Switzerland': [[47, 'N'], [8, 'E']],
        'Grenada': [[12, 'N'], [61, 'W']],
        'Navassa Island': [[18, 'N'], [75, 'W']],
        'Isle of Man': [[54, 'N'], [4, 'W']],
        'Portugal': [[39, 'N'], [8, 'W']],
        'Estonia': [[59, 'N'], [26, 'E']],
        'Kosovo': [[42, 'N'], [21, 'E']],
        'Norfolk Island': [[29, 'S'], [167, 'E']],
        'Bouvet Island': [[54, 'S'], [3, 'E']],
        'Lebanon': [[33, 'N'], [35, 'E']],
        'Sierra Leone': [[8, 'N'], [11, 'W']],
        'Uzbekistan': [[41, 'N'], [64, 'E']],
        'Tunisia': [[34, 'N'], [9, 'E']],
        'Djibouti': [[11, 'N'], [43, 'E']],
        'Heard Island and McDonald Islands': [[53, 'S'], [72, 'E']],
        'Antigua and Barbuda': [[17, 'N'], [61, 'W']],
        'Spain': [[40, 'N'], [4, 'W']],
        'Colombia': [[4, 'N'], [72, 'W']],
        'Burundi': [[3, 'S'], [30, 'E']],
        'Taiwan': [[23, 'N'], [121, 'E']],
        'Cyprus': [[35, 'N'], [33, 'E']],
        'Barbados': [[13, 'N'], [59, 'W']],
        'Falkland Islands (Islas Malvinas)': [[51, 'S'], [59, 'W']],
        'Madagascar': [[20, 'S'], [47, 'E']],
        'Italy': [[42, 'N'], [12, 'E']],
        'Bhutan': [[27, 'N'], [90, 'E']],
        'Sudan': [[15, 'N'], [30, 'E']],
        'Vanuatu': [[16, 'S'], [167, 'E']],
        'Malta': [[35, 'N'], [14, 'E']],
        'Hungary': [[47, 'N'], [20, 'E']],
        'Democratic Republic of the Congo': [[0, 'N'], [25, 'E']],
        'Netherlands': [[52, 'N'], [5, 'E']],
        'Bermuda': [[32, 'N'], [64, 'W']],
        'Suriname': [[4, 'N'], [56, 'W']],
        'Anguilla': [[18, 'N'], [63, 'W']],
        'Venezuela': [[8, 'N'], [66, 'W']],
        'Netherlands Antilles': [[12, 'N'], [69, 'W']],
        'Israel': [[31, 'N'], [34, 'E']],
        'Paracel Islands': [[16, 'N'], [112, 'E']],
        'Wake Island': [[19, 'N'], [166, 'E']],
        'Indonesia': [[5, 'S'], [120, 'E']],
        'Iceland': [[65, 'N'], [18, 'W']],
        'Zambia': [[15, 'S'], [30, 'E']],
        'Samoa': [[13, 'S'], [172, 'W']],
        'Austria': [[47, 'N'], [13, 'E']],
        'Papua New Guinea': [[6, 'S'], [147, 'E']],
        'Malawi': [[13, 'S'], [34, 'E']],
        'Zimbabwe': [[20, 'S'], [30, 'E']],
        'Germany': [[51, 'N'], [9, 'E']],
        'Dhekelia': [[34, 'N'], [33, 'E']],
        'Kazakhstan': [[48, 'N'], [68, 'E']],
        'Philippines': [[13, 'N'], [122, 'E']],
        'Eritrea': [[15, 'N'], [39, 'E']],
        'Kyrgyzstan': [[41, 'N'], [75, 'E']],
        'Mayotte': [[12, 'S'], [45, 'E']],
        'Iraq': [[33, 'N'], [44, 'E']],
        'Montserrat': [[16, 'N'], [62, 'W']],
        'Coral Sea Islands': [[18, 'S'], [152, 'E']],
        'Macedonia': [[41, 'N'], [22, 'E']],
        'British Indian Ocean Territory': [[6, 'S'], [71, 'E']],
        'North Korea': [[40, 'N'], [127, 'E']],
        'Trinidad and Tobago': [[11, 'N'], [61, 'W']],
        'Akrotiri': [[34, 'N'], [32, 'E']],
        'Guyana': [[5, 'N'], [59, 'W']],
        'Belarus': [[53, 'N'], [28, 'E']],
        'Nepal': [[28, 'N'], [84, 'E']],
        'Burma': [[22, 'N'], [98, 'E']],
        'Honduras': [[15, 'N'], [86, 'W']],
        'Equatorial Guinea': [[2, 'N'], [10, 'E']],
        'Egypt': [[27, 'N'], [30, 'E']],
        'Nicaragua': [[13, 'N'], [85, 'W']],
        'Singapore': [[1, 'N'], [103, 'E']],
        'Serbia': [[44, 'N'], [21, 'E']],
        'Botswana': [[22, 'S'], [24, 'E']],
        'United Kingdom': [[54, 'N'], [2, 'W']],
        'Antarctica': [[90, 'S'], [0, 'E']],
        'Christmas Island': [[10, 'S'], [105, 'E']],
        'Greece': [[39, 'N'], [22, 'E']],
        'Sri Lanka': [[7, 'N'], [81, 'E']],
        'Croatia': [[45, 'N'], [15, 'E']],
        'Comoros': [[12, 'S'], [44, 'E']]
        }
    g = Graph()
    g.add_edges(edges)
    g.add_vertices(gps_coordinates)
    g.gps_coordinates = gps_coordinates
    g.name("World Map")
    return g
Example #30
0
        def dual_equivalence_class(self, index_set=None):
            r"""
            Return the dual equivalence class indexed by ``index_set``
            of ``self``.

            The dual equivalence class of an element `b \in B`
            is the set of all elements of `B` reachable from
            `b` via sequences of `i`-elementary dual equivalence
            relations (i.e., `i`-elementary dual equivalence
            transformations and their inverses) for `i` in the index
            set of `B`.

            For this to be well-defined, the element `b` has to be
            of weight `0` with respect to `I`; that is, we need to have
            `\varepsilon_j(b) = \varphi_j(b)` for all `j \in I`.

            See [Assaf08]_. See also :meth:`dual_equivalence_graph` for
            a definition of `i`-elementary dual equivalence
            transformations.

            INPUT:

            - ``index_set`` -- (optional) the index set `I`
              (default: the whole index set of the crystal); this has
              to be a subset of the index set of the crystal (as a list
              or tuple)

            OUTPUT:

            The dual equivalence class of ``self`` indexed by the
            subset ``index_set``. This class is returned as an
            undirected edge-colored multigraph. The color of an edge
            is the index `i` of the dual equivalence relation it
            encodes.

            .. SEEALSO::

                - :meth:`~sage.categories.regular_crystals.RegularCrystals.ParentMethods.dual_equivalence_graph`
                - :meth:`sage.combinat.partition.Partition.dual_equivalence_graph`

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',3], shape=[2,2])
                sage: G = T(2,1,4,3).dual_equivalence_class()
                sage: sorted(G.edges())
                [([[1, 3], [2, 4]], [[1, 2], [3, 4]], 2),
                 ([[1, 3], [2, 4]], [[1, 2], [3, 4]], 3)]
                sage: T = crystals.Tableaux(['A',4], shape=[3,2])
                sage: G = T(2,1,4,3,5).dual_equivalence_class()
                sage: sorted(G.edges())
                [([[1, 3, 5], [2, 4]], [[1, 3, 4], [2, 5]], 4),
                 ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 2),
                 ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 3),
                 ([[1, 3, 4], [2, 5]], [[1, 2, 4], [3, 5]], 2),
                 ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 3),
                 ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 4)]
            """
            if index_set is None:
                index_set = self.index_set()

            for i in index_set:
                if self.epsilon(i) != self.phi(i):
                    raise ValueError("the element is not weight 0")

            visited = set([])
            todo = set([self])
            edges = []
            while todo:
                x = todo.pop()
                visited.add(x)
                for k, i in enumerate(index_set[1:]):
                    im = index_set[k]
                    if x.epsilon(i) == 1 and x.epsilon(im) == 0:
                        y = x.e(i).e(im).f(i).f(im)
                        if [y, x, i] not in edges:
                            edges.append([x, y, i])
                        if y not in visited:
                            todo.add(y)
                    if x.epsilon(i) == 0 and x.epsilon(im) == 1:
                        y = x.e(im).e(i).f(im).f(i)
                        if [y, x, i] not in edges:
                            edges.append([x, y, i])
                        if y not in visited:
                            todo.add(y)
            from sage.graphs.graph import Graph

            G = Graph(edges, multiedges=True)
            G.add_vertices(visited)
            if have_dot2tex():
                G.set_latex_options(
                    format="dot2tex", edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring
                )
            return G
Example #31
0
def RandomTree(n):
    """
    Returns a random tree on `n` nodes numbered `0` through `n-1`.

    By Cayley's theorem, there are `n^{n-2}` trees with vertex
    set `\{0,1,...,n-1\}`. This constructor chooses one of these uniformly
    at random.

    ALGORITHM:

    The algoritm works by generating an `(n-2)`-long
    random sequence of numbers chosen independently and uniformly
    from `\{0,1,\ldots,n-1\}` and then applies an inverse
    Prufer transformation.

    INPUT:

    -  ``n`` - number of vertices in the tree

    EXAMPLE::

        sage: G = graphs.RandomTree(10)
        sage: G.is_tree()
        True
        sage: G.show() # long

    TESTS:

    Ensuring that we encounter no unexpected surprise ::

        sage: all( graphs.RandomTree(10).is_tree()
        ....:      for i in range(100) )
        True

    """
    from sage.misc.prandom import randint
    g = Graph()

    # create random Prufer code
    code = [randint(0, n - 1) for i in xrange(n - 2)]

    # We count the number of symbols of each type.
    # count[k] is the no. of times k appears in code
    #
    # (count[k] is set to -1 when the corresponding vertex is not
    # available anymore)
    count = [0 for i in xrange(n)]
    for k in code:
        count[k] += 1

    g.add_vertices(range(n))

    for s in code:
        for x in range(n):
            if count[x] == 0:
                break

        count[x] = -1
        g.add_edge(x, s)
        count[s] -= 1

    # Adding as an edge the last two available vertices
    last_edge = [v for v in range(n) if count[v] != -1]
    g.add_edge(last_edge)

    return g
Example #32
0
def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set):
    """
    Return the Coxeter type of ``coxeter_matrix`` if known,
    otherwise return ``None``.

    EXAMPLES:

    Some infinite ones::

        sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]])
        sage: C.is_finite()  # indirect doctest
        False
        sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
        sage: C.is_finite()  # indirect doctest
        False

    Some finite ones::

        sage: m = matrix(CoxeterMatrix(['D', 4]))
        sage: CoxeterMatrix(m).is_finite()  # indirect doctest
        True
        sage: m = matrix(CoxeterMatrix(['H', 4]))
        sage: CoxeterMatrix(m).is_finite()  # indirect doctest
        True

        sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['A', 10]
        sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['B', 10]
        sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['B', 10]
        sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['D', 10]
        sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 6]
        sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 7]
        sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 8]
        sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type()
        Coxeter type of ['F', 4]
        sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type()
        Coxeter type of ['G', 2]
        sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type()
        Coxeter type of ['H', 3]
        sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type()
        Coxeter type of ['H', 4]
        sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type()
        Coxeter type of ['I', 100]

    Some affine graphs::

        sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['A', 1, 1]
        sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['A', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['B', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['C', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['D', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 6, 1]
        sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 7, 1]
        sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 8, 1]
        sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['F', 4, 1]
        sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['G', 2, 1]

    TESTS:

    Check that we detect relabellings::

        sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c'])
        sage: M.coxeter_type()
        Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'}

        sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix
        sage: for C in CoxeterMatrix.samples():
        ....:     relabelling_perm = Permutations(C.index_set()).random_element()
        ....:     relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())}
        ....:     relabeled_matrix = C.relabel(relabelling_dict)._matrix
        ....:     recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm)
        ....:     if C.is_finite() or C.is_affine():
        ....:         assert recognized_type == C.coxeter_type()

    We check the rank 2 cases (:trac:`20419`)::

        sage: for i in range(2, 10):
        ....:     M = matrix([[1,i],[i,1]])
        ....:     CoxeterMatrix(M).coxeter_type()
        Coxeter type of A1xA1 relabelled by {1: 2}
        Coxeter type of ['A', 2]
        Coxeter type of ['B', 2]
        Coxeter type of ['I', 5]
        Coxeter type of ['G', 2]
        Coxeter type of ['I', 7]
        Coxeter type of ['I', 8]
        Coxeter type of ['I', 9]
        sage: CoxeterMatrix(matrix([[1,-1],[-1,1]]), index_set=[0,1]).coxeter_type()
        Coxeter type of ['A', 1, 1]
    """
    # First, we build the Coxeter graph of the group without the edge labels
    n = ZZ(coxeter_matrix.nrows())
    G = Graph([[index_set[i], index_set[j], coxeter_matrix[i, j]]
               for i in range(n) for j in range(i, n)
               if coxeter_matrix[i, j] not in [1, 2]])
    G.add_vertices(index_set)

    types = []
    for S in G.connected_components_subgraphs():
        r = S.num_verts()
        # Handle the special cases first
        if r == 1:
            types.append(CoxeterType(['A', 1]).relabel({1: S.vertices()[0]}))
            continue
        if r == 2:  # Type B2, G2, or I_2(p)
            e = S.edge_labels()[0]
            if e == 3:  # Can't be 2 because it is connected
                ct = CoxeterType(['A', 2])
            elif e == 4:
                ct = CoxeterType(['B', 2])
            elif e == 6:
                ct = CoxeterType(['G', 2])
            elif e > 0 and e < float('inf'):  # Remaining non-affine types
                ct = CoxeterType(['I', e])
            else:  # Otherwise it is infinite dihedral group Z_2 \ast Z_2
                ct = CoxeterType(['A', 1, 1])
            if not ct.is_affine():
                types.append(
                    ct.relabel({
                        1: S.vertices()[0],
                        2: S.vertices()[1]
                    }))
            else:
                types.append(
                    ct.relabel({
                        0: S.vertices()[0],
                        1: S.vertices()[1]
                    }))
            continue

        test = [['A', r], ['B', r], ['A', r - 1, 1]]
        if r >= 3:
            if r == 3:
                test += [['G', 2, 1], ['H', 3]]
            test.append(['C', r - 1, 1])
        if r >= 4:
            if r == 4:
                test += [['F', 4], ['H', 4]]
            test += [['D', r], ['B', r - 1, 1]]
        if r >= 5:
            if r == 5:
                test.append(['F', 4, 1])
            test.append(['D', r - 1, 1])
        if r == 6:
            test.append(['E', 6])
        elif r == 7:
            test += [['E', 7], ['E', 6, 1]]
        elif r == 8:
            test += [['E', 8], ['E', 7, 1]]
        elif r == 9:
            test.append(['E', 8, 1])

        found = False
        for ct in test:
            ct = CoxeterType(ct)
            T = ct.coxeter_graph()
            iso, match = T.is_isomorphic(S, certify=True, edge_labels=True)
            if iso:
                types.append(ct.relabel(match))
                found = True
                break
        if not found:
            return None

    return CoxeterType(types)
Example #33
0
def PermutationGraph(second_permutation, first_permutation=None):
    r"""
    Builds a permutation graph from one (or two) permutations.

    General definition

    A Permutation Graph can be encoded by a permutation `\sigma`
    of `1, ..., n`. It is then built in the following way :

      Take two horizontal lines in the euclidean plane, and mark points `1, ...,
      n` from left to right on the first of them. On the second one, still from
      left to right, mark point in the order in which they appear in `\sigma`.
      Now, link by a segment the two points marked with 1, then link together
      the points marked with 2, and so on. The permutation graph defined by the
      permutation is the intersection graph of those segments : there exists a
      point in this graph for each element from `1` to `n`, two vertices `i, j`
      being adjacent if the segments `i` and `j` cross each other.

    The set of edges of the resulting graph is equal to the set of inversions of
    the inverse of the given permutation.

    INPUT:

    - ``second_permutation`` -- the permutation from which the graph should be
      built. It corresponds to the ordering of the elements on the second line
      (see previous definition)

    - ``first_permutation`` (optional) -- the ordering of the elements on the
      *first* line. This is useful when the elements have no natural ordering,
      for instance when they are strings, or tuples, or anything else.

      When ``first_permutation == None`` (default), it is set to be equal to
      ``sorted(second_permutation)``, which just yields the expected
      ordering when the elements of the graph are integers.

    .. SEEALSO:

      - Recognition of Permutation graphs in the :mod:`comparability module
        <sage.graphs.comparability>`.

      - Drawings of permutation graphs as intersection graphs of segments is
        possible through the
        :meth:`~sage.combinat.permutation.Permutation.show` method of
        :class:`~sage.combinat.permutation.Permutation` objects.

        The correct argument to use in this case is ``show(representation =
        "braid")``.

      - :meth:`~sage.combinat.permutation.Permutation.inversions`

    EXAMPLE::

        sage: p = Permutations(5).random_element()
        sage: edges = graphs.PermutationGraph(p).edges(labels =False)
        sage: set(edges) == set(p.inverse().inversions())
        True

    TESTS::

        sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6])
        Traceback (most recent call last):
        ...
        ValueError: The two permutations do not contain the same set of elements ...
    """
    if first_permutation == None:
        first_permutation = sorted(second_permutation)
    else:
        if set(second_permutation) != set(first_permutation):
            raise ValueError("The two permutations do not contain the same " +
                             "set of elements ! It is going to be pretty " +
                             "hard to define a permutation graph from that !")

    vertex_to_index = {}
    for i, v in enumerate(first_permutation):
        vertex_to_index[v] = i + 1

    from sage.combinat.permutation import Permutation
    p2 = Permutation(map(lambda x: vertex_to_index[x], second_permutation))
    p1 = Permutation(map(lambda x: vertex_to_index[x], first_permutation))
    p2 = p2 * p1.inverse()
    p2 = p2.inverse()

    g = Graph(name="Permutation graph for " + str(second_permutation))
    g.add_vertices(second_permutation)

    for u, v in p2.inversions():
        g.add_edge(first_permutation[u - 1], first_permutation[v - 1])

    return g
Example #34
0
def _check_pbd(B, v, S):
    r"""
    Checks that ``B`` is a PBD on ``v`` points with given block sizes ``S``.

    The points of the balanced incomplete block design are implicitely assumed
    to be `\{0, ..., v-1\}`.

    INPUT:

    - ``B`` -- a list of blocks

    - ``v`` (integer) -- number of points

    - ``S`` -- list of integers `\geq 2`.

    EXAMPLE::

        sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest
        [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10],
         [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28],
         [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34],
        ...
        sage: from sage.combinat.designs.bibd import _check_pbd
        sage: _check_pbd([[1],[]],1,[1,0])
        Traceback (most recent call last):
        ...
        RuntimeError: All integers of S must be >=2

    TESTS::

        sage: _check_pbd([[1,2]],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The PBD covers a point 2 which is not in {0, 1}
        sage: _check_pbd([[1,2]]*2,2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The pair (1,2) is covered more than once
        sage: _check_pbd([],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: The pair (0,1) is not covered
        sage: _check_pbd([[1,2],[1]],2,[2])
        Traceback (most recent call last):
        ...
        RuntimeError: A block has size 1 while S=[2]
    """
    from itertools import combinations
    from sage.graphs.graph import Graph

    for X in B:
        if len(X) not in S:
            raise RuntimeError("A block has size {} while S={}".format(
                len(X), S))

    if any(x < 2 for x in S):
        raise RuntimeError("All integers of S must be >=2")

    if v == 0 or v == 1:
        if B:
            raise RuntimeError("A PBD with v<=1 is expected to be empty.")

    g = Graph()
    g.add_vertices(range(v))
    m = 0
    for X in B:
        for i, j in combinations(X, 2):
            g.add_edge(i, j)
            m_tmp = g.size()
            if m_tmp != m + 1:
                raise RuntimeError(
                    "The pair ({},{}) is covered more than once".format(i, j))
            m = m_tmp

    if g.vertices() != range(v):
        from sage.sets.integer_range import IntegerRange
        p = (set(g.vertices()) - set(range(v))).pop()
        raise RuntimeError(
            "The PBD covers a point {} which is not in {}".format(
                p, IntegerRange(v)))

    if not g.is_clique():
        for p1 in g:
            if g.degree(p1) != v - 1:
                break
        neighbors = g.neighbors(p1) + [p1]
        p2 = (set(g.vertices()) - set(neighbors)).pop()
        raise RuntimeError("The pair ({},{}) is not covered".format(p1, p2))

    return B
Example #35
0
def WorldMap():
    """
    Returns the Graph of all the countries, in which two countries are adjacent
    in the graph if they have a common boundary.

    This graph has been built from the data available
    in The CIA World Factbook [CIA]_ (2009-08-21).

    The returned graph ``G`` has a member ``G.gps_coordinates``
    equal to a dictionary containing the GPS coordinates
    of each country's capital city.

    EXAMPLES::

        sage: g = graphs.WorldMap()
        sage: g.has_edge("France", "Italy")
        True
        sage: g.gps_coordinates["Bolivia"]
        [[17, 'S'], [65, 'W']]
        sage: sorted(g.connected_component_containing_vertex('Ireland'))
        ['Ireland', 'United Kingdom']

    TESTS::

        sage: 'Iceland' in graphs.WorldMap()  # Trac 24488
        True

    REFERENCE:

    .. [CIA] CIA Factbook 09 https://www.cia.gov/library/publications/the-world-factbook/
    """
    edges = [
        ('Afghanistan', 'China', None), ('Afghanistan', 'Iran', None),
        ('Afghanistan', 'Uzbekistan', None), ('Albania', 'Greece', None),
        ('Albania', 'Kosovo', None), ('Albania', 'Macedonia', None),
        ('Albania', 'Montenegro', None), ('Algeria', 'Morocco', None),
        ('Algeria', 'Tunisia', None), ('Andorra', 'Spain', None),
        ('Angola', 'Democratic Republic of the Congo', None),
        ('Angola', 'Namibia', None), ('Angola', 'Zambia', None),
        ('Argentina', 'Bolivia', None), ('Argentina', 'Brazil', None),
        ('Argentina', 'Chile', None), ('Argentina', 'Paraguay', None),
        ('Argentina', 'Uruguay', None), ('Armenia', 'Georgia', None),
        ('Armenia', 'Iran', None), ('Austria', 'Germany', None),
        ('Azerbaijan', 'Armenia', None), ('Azerbaijan', 'Georgia', None),
        ('Azerbaijan', 'Iran', None), ('Azerbaijan', 'Russia', None),
        ('Azerbaijan', 'Turkey', None), ('Bangladesh', 'Burma', None),
        ('Belgium', 'Germany', None), ('Belgium', 'Netherlands', None),
        ('Belize', 'Mexico', None), ('Benin', 'Burkina Faso', None),
        ('Benin', 'Niger', None), ('Benin', 'Nigeria', None),
        ('Benin', 'Togo', None), ('Bolivia', 'Brazil', None),
        ('Bolivia', 'Chile', None), ('Bolivia', 'Paraguay', None),
        ('Bolivia', 'Peru', None), ('Bosnia and Herzegovina', 'Croatia', None),
        ('Bosnia and Herzegovina', 'Montenegro', None),
        ('Bosnia and Herzegovina', 'Serbia', None),
        ('Brazil', 'Colombia', None), ('Brazil', 'Guyana', None),
        ('Brazil', 'Suriname', None), ('Brazil', 'Venezuela', None),
        ('Bulgaria', 'Greece', None), ('Bulgaria', 'Macedonia', None),
        ('Bulgaria', 'Romania', None), ('Bulgaria', 'Serbia', None),
        ('Burkina Faso', 'Mali', None), ('Burkina Faso', 'Niger', None),
        ('Burkina Faso', 'Togo', None),
        ('Burundi', 'Democratic Republic of the Congo', None),
        ('Cambodia', 'Laos', None), ('Cambodia', 'Thailand', None),
        ('Cambodia', 'Vietnam', None),
        ('Cameroon', 'Central African Republic', None),
        ('Cameroon', 'Chad', None), ('Cameroon', 'Equatorial Guinea', None),
        ('Cameroon', 'Nigeria', None),
        ('Cameroon', 'Republic of the Congo', None),
        ('Canada', 'United States', None),
        ('Central African Republic', 'Chad', None),
        ('Central African Republic', 'Democratic Republic of the Congo', None),
        ('Central African Republic', 'Sudan', None), ('Chad', 'Niger', None),
        ('Chad', 'Nigeria', None), ('Chad', 'Sudan', None),
        ('China', 'Bhutan', None), ('China', 'Burma', None),
        ('China', 'Hong Kong', None), ('China', 'Kazakhstan', None),
        ('China', 'Kyrgyzstan', None), ('China', 'Mongolia', None),
        ('China', 'Nepal', None), ('China', 'North Korea', None),
        ('China', 'Russia', None), ('China', 'Vietnam', None),
        ('Colombia', 'Venezuela', None), ('Costa Rica', 'Nicaragua', None),
        ("Cote d'Ivoire", 'Burkina Faso', None),
        ("Cote d'Ivoire", 'Guinea', None), ("Cote d'Ivoire", 'Mali', None),
        ('Cyprus', 'Akrotiri', None), ('Cyprus', 'Dhekelia', None),
        ('Czech Republic', 'Austria', None), ('Czech Republic', 'Germany',
                                              None),
        ('Czech Republic', 'Poland', None),
        ('Democratic Republic of the Congo', 'Zambia', None),
        ('Denmark', 'Germany', None), ('Djibouti', 'Eritrea', None),
        ('Dominican Republic', 'Haiti', None), ('Ecuador', 'Colombia', None),
        ('El Salvador', 'Honduras', None), ('Ethiopia', 'Djibouti', None),
        ('Ethiopia', 'Eritrea', None), ('Ethiopia', 'Kenya', None),
        ('Ethiopia', 'Somalia', None), ('Ethiopia', 'Sudan', None),
        ('Finland', 'Russia', None), ('Finland', 'Sweden', None),
        ('France', 'Andorra', None), ('France', 'Belgium', None),
        ('France', 'Brazil', None), ('France', 'Germany', None),
        ('France', 'Italy', None), ('France', 'Luxembourg', None),
        ('France', 'Spain', None), ('France', 'Suriname', None),
        ('France', 'Switzerland', None), ('Gabon', 'Cameroon', None),
        ('Gabon', 'Equatorial Guinea', None),
        ('Gabon', 'Republic of the Congo', None),
        ('Gaza Strip', 'Egypt', None), ('Gaza Strip', 'Israel', None),
        ('Ghana', 'Burkina Faso', None), ('Ghana', "Cote d'Ivoire", None),
        ('Ghana', 'Togo', None), ('Gibraltar', 'Spain', None),
        ('Guatemala', 'Belize', None), ('Guatemala', 'El Salvador', None),
        ('Guatemala', 'Honduras', None), ('Guatemala', 'Mexico', None),
        ('Guinea', 'Sierra Leone', None), ('Guinea-Bissau', 'Guinea', None),
        ('Guinea-Bissau', 'Senegal', None), ('Honduras', 'Nicaragua', None),
        ('Hungary', 'Austria', None), ('Hungary', 'Croatia', None),
        ('Hungary', 'Serbia', None), ('India', 'Bangladesh', None),
        ('India', 'Bhutan', None), ('India', 'Burma', None),
        ('India', 'China', None), ('India', 'Nepal', None),
        ('Indonesia', 'Papua New Guinea', None), ('Iran', 'Iraq', None),
        ('Ireland', 'United Kingdom', None), ('Israel', 'Egypt', None),
        ('Italy', 'Austria', None), ('Jordan', 'Iraq', None),
        ('Jordan', 'Israel', None), ('Jordan', 'Syria', None),
        ('Jordan', 'West Bank', None), ('Kazakhstan', 'Kyrgyzstan', None),
        ('Kenya', 'Somalia', None), ('Kenya', 'Sudan', None),
        ('Kenya', 'Uganda', None), ('Kosovo', 'Macedonia', None),
        ('Kosovo', 'Serbia', None), ('Kuwait', 'Iraq', None),
        ('Laos', 'Burma', None), ('Laos', 'China', None),
        ('Laos', 'Thailand', None), ('Laos', 'Vietnam', None),
        ('Latvia', 'Belarus', None), ('Latvia', 'Estonia', None),
        ('Lebanon', 'Israel', None), ('Lesotho', 'South Africa', None),
        ('Liberia', "Cote d'Ivoire", None), ('Liberia', 'Guinea', None),
        ('Liberia', 'Sierra Leone', None), ('Libya', 'Algeria', None),
        ('Libya', 'Chad', None), ('Libya', 'Egypt', None),
        ('Libya', 'Niger', None), ('Libya', 'Sudan', None),
        ('Libya', 'Tunisia', None), ('Liechtenstein', 'Austria', None),
        ('Liechtenstein', 'Switzerland', None), ('Lithuania', 'Belarus', None),
        ('Lithuania', 'Latvia', None), ('Lithuania', 'Poland', None),
        ('Lithuania', 'Russia', None), ('Luxembourg', 'Belgium', None),
        ('Luxembourg', 'Germany', None), ('Macau', 'China', None),
        ('Macedonia', 'Greece', None), ('Macedonia', 'Serbia', None),
        ('Malaysia', 'Brunei', None), ('Malaysia', 'Indonesia', None),
        ('Malaysia', 'Thailand', None), ('Mali', 'Algeria', None),
        ('Mali', 'Guinea', None), ('Mali', 'Niger', None),
        ('Mali', 'Senegal', None), ('Mauritania', 'Algeria', None),
        ('Mauritania', 'Mali', None), ('Mauritania', 'Senegal', None),
        ('Mauritania', 'Western Sahara', None), ('Monaco', 'France', None),
        ('Montenegro', 'Croatia', None), ('Montenegro', 'Kosovo', None),
        ('Montenegro', 'Serbia', None), ('Morocco', 'Spain', None),
        ('Mozambique', 'Malawi', None), ('Mozambique', 'Zambia', None),
        ('Mozambique', 'Zimbabwe', None), ('Namibia', 'Botswana', None),
        ('Namibia', 'Zambia', None), ('Netherlands', 'Germany', None),
        ('Niger', 'Algeria', None), ('Niger', 'Nigeria', None),
        ('Norway', 'Finland', None), ('Norway', 'Russia', None),
        ('Norway', 'Sweden', None), ('Oman', 'United Arab Emirates', None),
        ('Oman', 'Yemen', None), ('Pakistan', 'Afghanistan', None),
        ('Pakistan', 'China', None), ('Pakistan', 'India', None),
        ('Pakistan', 'Iran', None), ('Panama', 'Colombia', None),
        ('Panama', 'Costa Rica', None), ('Paraguay', 'Brazil', None),
        ('Peru', 'Brazil', None), ('Peru', 'Chile', None),
        ('Peru', 'Colombia', None), ('Peru', 'Ecuador', None),
        ('Poland', 'Belarus', None), ('Poland', 'Germany', None),
        ('Portugal', 'Spain', None), ('Republic of the Congo', 'Angola', None),
        ('Republic of the Congo', 'Central African Republic', None),
        ('Republic of the Congo', 'Democratic Republic of the Congo', None),
        ('Romania', 'Hungary', None), ('Romania', 'Moldova', None),
        ('Romania', 'Serbia', None), ('Russia', 'Belarus', None),
        ('Russia', 'Estonia', None), ('Russia', 'Georgia', None),
        ('Russia', 'Kazakhstan', None), ('Russia', 'Latvia', None),
        ('Russia', 'Mongolia', None), ('Russia', 'North Korea', None),
        ('Russia', 'Poland', None), ('Rwanda', 'Burundi', None),
        ('Rwanda', 'Democratic Republic of the Congo', None),
        ('Rwanda', 'Uganda', None),
        ('Saint Martin', 'Netherlands Antilles', None),
        ('San Marino', 'Italy', None), ('Saudi Arabia', 'Iraq', None),
        ('Saudi Arabia', 'Jordan', None), ('Saudi Arabia', 'Kuwait', None),
        ('Saudi Arabia', 'Oman', None), ('Saudi Arabia', 'Qatar', None),
        ('Saudi Arabia', 'United Arab Emirates', None),
        ('Saudi Arabia', 'Yemen', None), ('Senegal', 'Guinea', None),
        ('Serbia', 'Croatia', None), ('Slovakia', 'Austria', None),
        ('Slovakia', 'Czech Republic', None), ('Slovakia', 'Hungary', None),
        ('Slovakia', 'Poland', None), ('Slovakia', 'Ukraine', None),
        ('Slovenia', 'Austria', None), ('Slovenia', 'Croatia', None),
        ('Slovenia', 'Hungary', None), ('Slovenia', 'Italy', None),
        ('Somalia', 'Djibouti', None), ('South Africa', 'Botswana', None),
        ('South Africa', 'Mozambique', None),
        ('South Africa', 'Namibia', None), ('South Africa', 'Zimbabwe', None),
        ('South Korea', 'North Korea', None),
        ('Sudan', 'Democratic Republic of the Congo', None),
        ('Sudan', 'Egypt', None), ('Sudan', 'Eritrea', None),
        ('Suriname', 'Guyana', None), ('Swaziland', 'Mozambique', None),
        ('Swaziland', 'South Africa', None), ('Switzerland', 'Austria', None),
        ('Switzerland', 'Germany', None), ('Switzerland', 'Italy', None),
        ('Syria', 'Iraq', None), ('Syria', 'Israel', None),
        ('Syria', 'Lebanon', None), ('Tajikistan', 'Afghanistan', None),
        ('Tajikistan', 'China', None), ('Tajikistan', 'Kyrgyzstan', None),
        ('Tajikistan', 'Uzbekistan', None), ('Tanzania', 'Burundi', None),
        ('Tanzania', 'Democratic Republic of the Congo', None),
        ('Tanzania', 'Kenya', None), ('Tanzania', 'Malawi', None),
        ('Tanzania', 'Mozambique', None), ('Tanzania', 'Rwanda', None),
        ('Tanzania', 'Uganda', None), ('Tanzania', 'Zambia', None),
        ('Thailand', 'Burma', None), ('The Gambia', 'Senegal', None),
        ('Timor-Leste', 'Indonesia', None), ('Turkey', 'Armenia', None),
        ('Turkey', 'Bulgaria', None), ('Turkey', 'Georgia', None),
        ('Turkey', 'Greece', None), ('Turkey', 'Iran', None),
        ('Turkey', 'Iraq', None), ('Turkey', 'Syria', None),
        ('Turkmenistan', 'Afghanistan', None), ('Turkmenistan', 'Iran', None),
        ('Turkmenistan', 'Kazakhstan', None),
        ('Turkmenistan', 'Uzbekistan', None),
        ('Uganda', 'Democratic Republic of the Congo', None),
        ('Uganda', 'Sudan', None), ('Ukraine', 'Belarus', None),
        ('Ukraine', 'Hungary', None), ('Ukraine', 'Moldova', None),
        ('Ukraine', 'Poland', None), ('Ukraine', 'Romania', None),
        ('Ukraine', 'Russia', None), ('United States', 'Mexico', None),
        ('Uruguay', 'Brazil', None), ('Uzbekistan', 'Kazakhstan', None),
        ('Uzbekistan', 'Kyrgyzstan', None), ('Vatican City', 'Italy', None),
        ('Venezuela', 'Guyana', None), ('West Bank', 'Israel', None),
        ('Western Sahara', 'Algeria', None), ('Western Sahara',
                                              'Morocco', None),
        ('Zambia', 'Malawi', None), ('Zambia', 'Zimbabwe', None),
        ('Zimbabwe', 'Botswana', None)
    ]
    gps_coordinates = {
        'Canada': [[60, 'N'], [95, 'W']],
        'Saint Martin': [[18, 'N'], [63, 'W']],
        'Sao Tome and Principe': [[1, 'N'], [7, 'E']],
        'Turkmenistan': [[40, 'N'], [60, 'E']],
        'Saint Helena': [[15, 'S'], [5, 'W']],
        'Lithuania': [[56, 'N'], [24, 'E']],
        'Cambodia': [[13, 'N'], [105, 'E']],
        'Saint Kitts and Nevis': [[17, 'N'], [62, 'W']],
        'Ethiopia': [[8, 'N'], [38, 'E']],
        'The Gambia': [[13, 'N'], [16, 'W']],
        'Aruba': [[12, 'N'], [69, 'W']],
        'Swaziland': [[26, 'S'], [31, 'E']],
        'Guinea-Bissau': [[12, 'N'], [15, 'W']],
        'Argentina': [[34, 'S'], [64, 'W']],
        'Bolivia': [[17, 'S'], [65, 'W']],
        'Bahamas, The': [[24, 'N'], [76, 'W']],
        'Spratly Islands': [[8, 'N'], [111, 'E']],
        'Ghana': [[8, 'N'], [2, 'W']],
        'Saudi Arabia': [[25, 'N'], [45, 'E']],
        'American Samoa': [[14, 'S'], [170, 'W']],
        'Cocos (Keeling) Islands': [[12, 'S'], [96, 'E']],
        'Slovenia': [[46, 'N'], [14, 'E']],
        'Guatemala': [[15, 'N'], [90, 'W']],
        'Bosnia and Herzegovina': [[44, 'N'], [18, 'E']],
        'Kuwait': [[29, 'N'], [45, 'E']],
        'Jordan': [[31, 'N'], [36, 'E']],
        'Saint Barthelemy': [[17, 'N'], [62, 'W']],
        'Ashmore and Cartier Islands': [[12, 'S'], [123, 'E']],
        'Dominica': [[15, 'N'], [61, 'W']],
        'Liberia': [[6, 'N'], [9, 'W']],
        'Maldives': [[3, 'N'], [73, 'E']],
        'Micronesia, Federated States of': [[6, 'N'], [158, 'E']],
        'Pakistan': [[30, 'N'], [70, 'E']],
        'Oman': [[21, 'N'], [57, 'E']],
        'Tanzania': [[6, 'S'], [35, 'E']],
        'Albania': [[41, 'N'], [20, 'E']],
        'Gabon': [[1, 'S'], [11, 'E']],
        'Niue': [[19, 'S'], [169, 'W']],
        'Monaco': [[43, 'N'], [7, 'E']],
        'Wallis and Futuna': [[13, 'S'], [176, 'W']],
        'New Zealand': [[41, 'S'], [174, 'E']],
        'Yemen': [[15, 'N'], [48, 'E']],
        'Jersey': [[49, 'N'], [2, 'W']],
        'Jamaica': [[18, 'N'], [77, 'W']],
        'Greenland': [[72, 'N'], [40, 'W']],
        'West Bank': [[32, 'N'], [35, 'E']],
        'Macau': [[22, 'N'], [113, 'E']],
        'Jan Mayen': [[71, 'N'], [8, 'W']],
        'United Arab Emirates': [[24, 'N'], [54, 'E']],
        'Guam': [[13, 'N'], [144, 'E']],
        'Uruguay': [[33, 'S'], [56, 'W']],
        'India': [[20, 'N'], [77, 'E']],
        'Azerbaijan': [[40, 'N'], [47, 'E']],
        'Lesotho': [[29, 'S'], [28, 'E']],
        'Saint Vincent and the Grenadines': [[13, 'N'], [61, 'W']],
        'Kenya': [[1, 'N'], [38, 'E']],
        'South Korea': [[37, 'N'], [127, 'E']],
        'Tajikistan': [[39, 'N'], [71, 'E']],
        'Turkey': [[39, 'N'], [35, 'E']],
        'Afghanistan': [[33, 'N'], [65, 'E']],
        'Paraguay': [[23, 'S'], [58, 'W']],
        'Bangladesh': [[24, 'N'], [90, 'E']],
        'Mauritania': [[20, 'N'], [12, 'W']],
        'Solomon Islands': [[8, 'S'], [159, 'E']],
        'Saint Pierre and Miquelon': [[46, 'N'], [56, 'W']],
        'Gaza Strip': [[31, 'N'], [34, 'E']],
        'San Marino': [[43, 'N'], [12, 'E']],
        'French Polynesia': [[15, 'S'], [140, 'W']],
        'France': [[46, 'N'], [2, 'E']],
        'Fiji': [[18, 'S'], [175, 'E']],
        'Rwanda': [[2, 'S'], [30, 'E']],
        'Slovakia': [[48, 'N'], [19, 'E']],
        'Somalia': [[10, 'N'], [49, 'E']],
        'Peru': [[10, 'S'], [76, 'W']],
        'Laos': [[18, 'N'], [105, 'E']],
        'Nauru': [[0, 'S'], [166, 'E']],
        'Seychelles': [[4, 'S'], [55, 'E']],
        'Norway': [[62, 'N'], [10, 'E']],
        "Cote d'Ivoire": [[8, 'N'], [5, 'W']],
        'Cook Islands': [[21, 'S'], [159, 'W']],
        'Benin': [[9, 'N'], [2, 'E']],
        'Western Sahara': [[24, 'N'], [13, 'W']],
        'Cuba': [[21, 'N'], [80, 'W']],
        'Cameroon': [[6, 'N'], [12, 'E']],
        'Montenegro': [[42, 'N'], [19, 'E']],
        'Republic of the Congo': [[1, 'S'], [15, 'E']],
        'Burkina Faso': [[13, 'N'], [2, 'W']],
        'Togo': [[8, 'N'], [1, 'E']],
        'Virgin Islands': [[18, 'N'], [64, 'W']],
        'China': [[35, 'N'], [105, 'E']],
        'Armenia': [[40, 'N'], [45, 'E']],
        'Timor-Leste': [[8, 'S'], [125, 'E']],
        'Dominican Republic': [[19, 'N'], [70, 'W']],
        'Ukraine': [[49, 'N'], [32, 'E']],
        'Bahrain': [[26, 'N'], [50, 'E']],
        'Tonga': [[20, 'S'], [175, 'W']],
        'Finland': [[64, 'N'], [26, 'E']],
        'Libya': [[25, 'N'], [17, 'E']],
        'Cayman Islands': [[19, 'N'], [80, 'W']],
        'Central African Republic': [[7, 'N'], [21, 'E']],
        'New Caledonia': [[21, 'S'], [165, 'E']],
        'Mauritius': [[20, 'S'], [57, 'E']],
        'Liechtenstein': [[47, 'N'], [9, 'E']],
        'Vietnam': [[16, 'N'], [107, 'E']],
        'British Virgin Islands': [[18, 'N'], [64, 'W']],
        'Mali': [[17, 'N'], [4, 'W']],
        'Vatican City': [[41, 'N'], [12, 'E']],
        'Russia': [[60, 'N'], [100, 'E']],
        'Bulgaria': [[43, 'N'], [25, 'E']],
        'United States': [[38, 'N'], [97, 'W']],
        'Romania': [[46, 'N'], [25, 'E']],
        'Angola': [[12, 'S'], [18, 'E']],
        'Chad': [[15, 'N'], [19, 'E']],
        'South Africa': [[29, 'S'], [24, 'E']],
        'Tokelau': [[9, 'S'], [172, 'W']],
        'Turks and Caicos Islands': [[21, 'N'], [71, 'W']],
        'South Georgia and the South Sandwich Islands': [[54, 'S'], [37, 'W']],
        'Sweden': [[62, 'N'], [15, 'E']],
        'Qatar': [[25, 'N'], [51, 'E']],
        'Malaysia': [[2, 'N'], [112, 'E']],
        'Senegal': [[14, 'N'], [14, 'W']],
        'Latvia': [[57, 'N'], [25, 'E']],
        'Clipperton Island': [[10, 'N'], [109, 'W']],
        'Uganda': [[1, 'N'], [32, 'E']],
        'Japan': [[36, 'N'], [138, 'E']],
        'Niger': [[16, 'N'], [8, 'E']],
        'Brazil': [[10, 'S'], [55, 'W']],
        'Faroe Islands': [[62, 'N'], [7, 'W']],
        'Guinea': [[11, 'N'], [10, 'W']],
        'Panama': [[9, 'N'], [80, 'W']],
        'Costa Rica': [[10, 'N'], [84, 'W']],
        'Luxembourg': [[49, 'N'], [6, 'E']],
        'Cape Verde': [[16, 'N'], [24, 'W']],
        'Andorra': [[42, 'N'], [1, 'E']],
        'Gibraltar': [[36, 'N'], [5, 'W']],
        'Ireland': [[53, 'N'], [8, 'W']],
        'Syria': [[35, 'N'], [38, 'E']],
        'Palau': [[7, 'N'], [134, 'E']],
        'Nigeria': [[10, 'N'], [8, 'E']],
        'Ecuador': [[2, 'S'], [77, 'W']],
        'Northern Mariana Islands': [[15, 'N'], [145, 'E']],
        'Brunei': [[4, 'N'], [114, 'E']],
        'Mozambique': [[18, 'S'], [35, 'E']],
        'Australia': [[27, 'S'], [133, 'E']],
        'Iran': [[32, 'N'], [53, 'E']],
        'Algeria': [[28, 'N'], [3, 'E']],
        'Svalbard': [[78, 'N'], [20, 'E']],
        'El Salvador': [[13, 'N'], [88, 'W']],
        'Tuvalu': [[8, 'S'], [178, 'E']],
        'Pitcairn Islands': [[25, 'S'], [130, 'W']],
        'Czech Republic': [[49, 'N'], [15, 'E']],
        'Marshall Islands': [[9, 'N'], [168, 'E']],
        'Chile': [[30, 'S'], [71, 'W']],
        'Puerto Rico': [[18, 'N'], [66, 'W']],
        'Belgium': [[50, 'N'], [4, 'E']],
        'Kiribati': [[1, 'N'], [173, 'E']],
        'Haiti': [[19, 'N'], [72, 'W']],
        'Belize': [[17, 'N'], [88, 'W']],
        'Hong Kong': [[22, 'N'], [114, 'E']],
        'Saint Lucia': [[13, 'N'], [60, 'W']],
        'Georgia': [[42, 'N'], [43, 'E']],
        'Mexico': [[23, 'N'], [102, 'W']],
        'Denmark': [[56, 'N'], [10, 'E']],
        'Poland': [[52, 'N'], [20, 'E']],
        'Moldova': [[47, 'N'], [29, 'E']],
        'Morocco': [[32, 'N'], [5, 'W']],
        'Namibia': [[22, 'S'], [17, 'E']],
        'Mongolia': [[46, 'N'], [105, 'E']],
        'Guernsey': [[49, 'N'], [2, 'W']],
        'Thailand': [[15, 'N'], [100, 'E']],
        'Switzerland': [[47, 'N'], [8, 'E']],
        'Grenada': [[12, 'N'], [61, 'W']],
        'Navassa Island': [[18, 'N'], [75, 'W']],
        'Isle of Man': [[54, 'N'], [4, 'W']],
        'Portugal': [[39, 'N'], [8, 'W']],
        'Estonia': [[59, 'N'], [26, 'E']],
        'Kosovo': [[42, 'N'], [21, 'E']],
        'Norfolk Island': [[29, 'S'], [167, 'E']],
        'Bouvet Island': [[54, 'S'], [3, 'E']],
        'Lebanon': [[33, 'N'], [35, 'E']],
        'Sierra Leone': [[8, 'N'], [11, 'W']],
        'Uzbekistan': [[41, 'N'], [64, 'E']],
        'Tunisia': [[34, 'N'], [9, 'E']],
        'Djibouti': [[11, 'N'], [43, 'E']],
        'Heard Island and McDonald Islands': [[53, 'S'], [72, 'E']],
        'Antigua and Barbuda': [[17, 'N'], [61, 'W']],
        'Spain': [[40, 'N'], [4, 'W']],
        'Colombia': [[4, 'N'], [72, 'W']],
        'Burundi': [[3, 'S'], [30, 'E']],
        'Taiwan': [[23, 'N'], [121, 'E']],
        'Cyprus': [[35, 'N'], [33, 'E']],
        'Barbados': [[13, 'N'], [59, 'W']],
        'Falkland Islands (Islas Malvinas)': [[51, 'S'], [59, 'W']],
        'Madagascar': [[20, 'S'], [47, 'E']],
        'Italy': [[42, 'N'], [12, 'E']],
        'Bhutan': [[27, 'N'], [90, 'E']],
        'Sudan': [[15, 'N'], [30, 'E']],
        'Vanuatu': [[16, 'S'], [167, 'E']],
        'Malta': [[35, 'N'], [14, 'E']],
        'Hungary': [[47, 'N'], [20, 'E']],
        'Democratic Republic of the Congo': [[0, 'N'], [25, 'E']],
        'Netherlands': [[52, 'N'], [5, 'E']],
        'Bermuda': [[32, 'N'], [64, 'W']],
        'Suriname': [[4, 'N'], [56, 'W']],
        'Anguilla': [[18, 'N'], [63, 'W']],
        'Venezuela': [[8, 'N'], [66, 'W']],
        'Netherlands Antilles': [[12, 'N'], [69, 'W']],
        'Israel': [[31, 'N'], [34, 'E']],
        'Paracel Islands': [[16, 'N'], [112, 'E']],
        'Wake Island': [[19, 'N'], [166, 'E']],
        'Indonesia': [[5, 'S'], [120, 'E']],
        'Iceland': [[65, 'N'], [18, 'W']],
        'Zambia': [[15, 'S'], [30, 'E']],
        'Samoa': [[13, 'S'], [172, 'W']],
        'Austria': [[47, 'N'], [13, 'E']],
        'Papua New Guinea': [[6, 'S'], [147, 'E']],
        'Malawi': [[13, 'S'], [34, 'E']],
        'Zimbabwe': [[20, 'S'], [30, 'E']],
        'Germany': [[51, 'N'], [9, 'E']],
        'Dhekelia': [[34, 'N'], [33, 'E']],
        'Kazakhstan': [[48, 'N'], [68, 'E']],
        'Philippines': [[13, 'N'], [122, 'E']],
        'Eritrea': [[15, 'N'], [39, 'E']],
        'Kyrgyzstan': [[41, 'N'], [75, 'E']],
        'Mayotte': [[12, 'S'], [45, 'E']],
        'Iraq': [[33, 'N'], [44, 'E']],
        'Montserrat': [[16, 'N'], [62, 'W']],
        'Coral Sea Islands': [[18, 'S'], [152, 'E']],
        'Macedonia': [[41, 'N'], [22, 'E']],
        'British Indian Ocean Territory': [[6, 'S'], [71, 'E']],
        'North Korea': [[40, 'N'], [127, 'E']],
        'Trinidad and Tobago': [[11, 'N'], [61, 'W']],
        'Akrotiri': [[34, 'N'], [32, 'E']],
        'Guyana': [[5, 'N'], [59, 'W']],
        'Belarus': [[53, 'N'], [28, 'E']],
        'Nepal': [[28, 'N'], [84, 'E']],
        'Burma': [[22, 'N'], [98, 'E']],
        'Honduras': [[15, 'N'], [86, 'W']],
        'Equatorial Guinea': [[2, 'N'], [10, 'E']],
        'Egypt': [[27, 'N'], [30, 'E']],
        'Nicaragua': [[13, 'N'], [85, 'W']],
        'Singapore': [[1, 'N'], [103, 'E']],
        'Serbia': [[44, 'N'], [21, 'E']],
        'Botswana': [[22, 'S'], [24, 'E']],
        'United Kingdom': [[54, 'N'], [2, 'W']],
        'Antarctica': [[90, 'S'], [0, 'E']],
        'Christmas Island': [[10, 'S'], [105, 'E']],
        'Greece': [[39, 'N'], [22, 'E']],
        'Sri Lanka': [[7, 'N'], [81, 'E']],
        'Croatia': [[45, 'N'], [15, 'E']],
        'Comoros': [[12, 'S'], [44, 'E']]
    }
    g = Graph()
    g.add_edges(edges)
    g.add_vertices(gps_coordinates)
    g.gps_coordinates = gps_coordinates
    g.name("World Map")
    return g
Example #36
0
def AffineOrthogonalPolarGraph(d,q,sign="+"):
    r"""
    Returns the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`.

    Affine Polar graphs are built from a `d`-dimensional vector space over
    `F_q`, and a quadratic form which is hyperbolic, elliptic or parabolic
    according to the value of ``sign``.

    Note that `VO^+(d,q),VO^-(d,q)` are strongly regular graphs, while `VO(d,q)`
    is not.

    For more information on Affine Polar graphs, see `Affine Polar
    Graphs page of Andries Brouwer's website
    <http://www.win.tue.nl/~aeb/graphs/VO.html>`_.

    INPUT:

    - ``d`` (integer) -- ``d`` must be even if ``sign != None``, and odd
      otherwise.

    - ``q`` (integer) -- a power of a prime number, as `F_q` must exist.

    - ``sign`` -- must be equal to ``"+"``, ``"-"``, or ``None`` to compute
      (respectively) `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. By default
      ``sign="+"``.

    .. NOTE::

        The graph `VO^\epsilon(d,q)` is the graph induced by the
        non-neighbors of a vertex in an :meth:`Orthogonal Polar Graph
        <OrthogonalPolarGraph>` `O^\epsilon(d+2,q)`.

    EXAMPLES:

    The :meth:`Brouwer-Haemers graph <BrouwerHaemersGraph>` is isomorphic to
    `VO^-(4,3)`::

        sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
        sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())
        True

    Some examples from `Brouwer's table or strongly regular graphs
    <http://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`_::

        sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g
        Affine Polar Graph VO^-(6,2): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 27, 10, 12)
        sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g
        Affine Polar Graph VO^+(6,2): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 35, 18, 20)

    When ``sign is None``::

        sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g
        Affine Polar Graph VO^-(5,2): Graph on 32 vertices
        sage: g.is_strongly_regular(parameters=True)
        False
        sage: g.is_regular()
        True
        sage: g.is_vertex_transitive()
        True
    """
    if sign in ["+","-"]:
        s = 1 if sign == "+" else -1
        if d%2 == 1:
            raise ValueError("d must be even when sign!=None")
    else:
        if d%2 == 0:
            raise ValueError("d must be odd when sign==None")
        s = 0

    from sage.interfaces.gap import gap
    from sage.modules.free_module import VectorSpace
    from sage.matrix.constructor import Matrix
    from sage.libs.gap.libgap import libgap
    from itertools import combinations

    M = Matrix(libgap.InvariantQuadraticForm(libgap.GeneralOrthogonalGroup(s,d,q))['matrix'])
    F = libgap.GF(q).sage()
    V = list(VectorSpace(F,d))

    G = Graph()
    G.add_vertices([tuple(_) for _ in V])
    for x,y in combinations(V,2):
        if not (x-y)*M*(x-y):
            G.add_edge(tuple(x),tuple(y))

    G.name("Affine Polar Graph VO^"+str('+' if s == 1 else '-')+"("+str(d)+","+str(q)+")")
    G.relabel()
    return G
Example #37
0
def AfricaMap(continental=False, year=2018):
    """
    Return African states as a graph of common border.

    "African state" here is defined as an independent
    state having the capital city in Africa. The graph
    has an edge between those countries that have common
    *land* border.

    INPUT:

    - ``continental``, a Boolean -- if set, only return states in
      the continental Africa
    - ``year`` -- reserved for future use

    EXAMPLES::

        sage: Africa = graphs.AfricaMap(); Africa
        Africa Map: Graph on 54 vertices
        sage: sorted(Africa.neighbors('Libya'))
        ['Algeria', 'Chad', 'Egypt', 'Niger', 'Sudan', 'Tunisia']

        sage: cont_Africa = graphs.AfricaMap(continental=True)
        sage: cont_Africa.order()
        48
        sage: 'Madagaskar' in cont_Africa
        False
    """
    if year != 2018:
        raise ValueError("currently only year 2018 is implemented")

    common_border = {
        'Algeria':
        ['Libya', 'Mali', 'Mauritania', 'Morocco', 'Niger', 'Tunisia'],
        'Angola': ['Namibia', 'Zambia'],
        'Benin': ['Burkina Faso', 'Niger', 'Nigeria', 'Togo'],
        'Botswana': ['Namibia', 'South Africa', 'Zimbabwe'],
        'Burkina Faso': ['Ghana', 'Ivory Coast', 'Mali', 'Niger', 'Togo'],
        'Cameroon':
        ['Central Africa', 'Chad', 'Equatorial Guinea', 'Gabon', 'Nigeria'],
        'Central Africa': ['Chad', 'South Sudan', 'Sudan'],
        'Chad': ['Libya', 'Niger', 'Nigeria', 'Sudan'],
        'Republic of the Congo': [
            'Gabon', 'Cameroon', 'Central Africa', 'Angola',
            'Democratic Republic of the Congo'
        ],
        'Democratic Republic of the Congo': [
            'Zambia', 'South Sudan', 'Tanzania', 'Burundi', 'Rwanda', 'Uganda',
            'Central Africa', 'Angola'
        ],
        'Djibouti': ['Eritrea', 'Ethiopia', 'Somalia'],
        'Ethiopia': ['Eritrea', 'Kenya', 'Somalia', 'South Sudan', 'Sudan'],
        'Gabon': ['Equatorial Guinea'],
        'Ghana': ['Ivory Coast', 'Togo'],
        'Guinea': ['Guinea-Bissau', 'Ivory Coast', 'Liberia', 'Sierra Leone'],
        'Kenya': ['Somalia', 'South Sudan', 'Tanzania', 'Uganda'],
        'Liberia': ['Ivory Coast', 'Sierra Leone'],
        'Libya': ['Egypt', 'Niger', 'Sudan', 'Tunisia'],
        'Mali': ['Guinea', 'Ivory Coast', 'Mauritania', 'Niger', 'Senegal'],
        'Mozambique': ['Malawi', 'South Africa', 'Swaziland', 'Zimbabwe'],
        'Niger': ['Nigeria'],
        'Rwanda': ['Burundi', 'Tanzania', 'Uganda'],
        'Senegal': ['Guinea', 'Guinea-Bissau', 'Mauritania', 'Gambia'],
        'South Africa': ['Lesotho', 'Namibia', 'Swaziland', 'Zimbabwe'],
        'South Sudan': ['Uganda', 'Sudan', 'Democratic Republic of the Congo'],
        'Sudan': ['Egypt', 'Eritrea'],
        'Tanzania': ['Burundi', 'Malawi', 'Mozambique', 'Uganda', 'Zambia'],
        'Zambia': ['Malawi', 'Mozambique', 'Namibia', 'Zimbabwe']
    }

    no_land_border = [
        'Cape Verde', 'Seychelles', 'Mauritius',
        'S\xc3\xa3o Tom\xc3\xa9 and Pr\xc3\xadncipe', 'Madagascar', 'Comoros'
    ]

    G = Graph(common_border, format='dict_of_lists')

    if continental:
        G = G.subgraph(
            G.connected_component_containing_vertex('Central Africa'))
        G.name(new="Continental Africa Map")
    else:
        G.add_vertices(no_land_border)
        G.name(new="Africa Map")

    return G
Example #38
0
def RandomTree(n):
    """
    Returns a random tree on `n` nodes numbered `0` through `n-1`.

    By Cayley's theorem, there are `n^{n-2}` trees with vertex
    set `\{0,1,...,n-1\}`. This constructor chooses one of these uniformly
    at random.

    ALGORITHM:

    The algoritm works by generating an `(n-2)`-long
    random sequence of numbers chosen independently and uniformly
    from `\{0,1,\ldots,n-1\}` and then applies an inverse
    Prufer transformation.

    INPUT:

    -  ``n`` - number of vertices in the tree

    EXAMPLE::

        sage: G = graphs.RandomTree(10)
        sage: G.is_tree()
        True
        sage: G.show() # long

    TESTS:

    Ensuring that we encounter no unexpected surprise ::

        sage: all( graphs.RandomTree(10).is_tree()
        ....:      for i in range(100) )
        True

    """
    from sage.misc.prandom import randint
    g = Graph()

    # create random Prufer code
    code = [ randint(0,n-1) for i in xrange(n-2) ]

    # We count the number of symbols of each type.
    # count[k] is the no. of times k appears in code
    #
    # (count[k] is set to -1 when the corresponding vertex is not
    # available anymore)
    count = [ 0 for i in xrange(n) ]
    for k in code:
        count[k] += 1

    g.add_vertices(range(n))

    for s in code:
        for x in range(n):
            if count[x] == 0:
                break

        count[x] = -1
        g.add_edge(x,s)
        count[s] -= 1

    # Adding as an edge the last two available vertices
    last_edge = [ v for v in range(n) if count[v] != -1 ]
    g.add_edge(last_edge)

    return g
Example #39
0
def AfricaMap(continental=False, year=2018):
    """
    Return African states as a graph of common border.

    "African state" here is defined as an independent
    state having the capital city in Africa. The graph
    has an edge between those countries that have common
    *land* border.

    INPUT:

    - ``continental``, a Boolean -- if set, only return states in
      the continental Africa
    - ``year`` -- reserved for future use

    EXAMPLES::

        sage: Africa = graphs.AfricaMap(); Africa
        Africa Map: Graph on 54 vertices
        sage: sorted(Africa.neighbors('Libya'))
        ['Algeria', 'Chad', 'Egypt', 'Niger', 'Sudan', 'Tunisia']

        sage: cont_Africa = graphs.AfricaMap(continental=True)
        sage: cont_Africa.order()
        48
        sage: 'Madagaskar' in cont_Africa
        False

    TESTS::

        sage: Africa.plot()
        Graphics object consisting of 159 graphics primitives
    """
    if year != 2018:
        raise ValueError("currently only year 2018 is implemented")

    common_border = {
     'Algeria': ['Libya', 'Mali', 'Mauritania', 'Morocco', 'Niger', 'Tunisia'],
     'Angola': ['Namibia', 'Zambia'],
     'Benin': ['Burkina Faso', 'Niger', 'Nigeria', 'Togo'],
     'Botswana': ['Namibia', 'South Africa', 'Zimbabwe'],
     'Burkina Faso': ['Ghana', 'Ivory Coast', 'Mali', 'Niger', 'Togo'],
     'Cameroon': ['Central Africa', 'Chad', 'Equatorial Guinea', 'Gabon', 'Nigeria'],
     'Central Africa': ['Chad', 'South Sudan', 'Sudan'],
     'Chad': ['Libya', 'Niger', 'Nigeria', 'Sudan'],
     'Republic of the Congo': ['Gabon', 'Cameroon', 'Central Africa', 'Angola',
                               'Democratic Republic of the Congo'],
     'Democratic Republic of the Congo': ['Zambia', 'South Sudan', 'Tanzania', 'Burundi',
                                          'Rwanda', 'Uganda', 'Central Africa', 'Angola'],
     'Djibouti': ['Eritrea', 'Ethiopia', 'Somalia'],
     'Ethiopia': ['Eritrea', 'Kenya', 'Somalia', 'South Sudan', 'Sudan'],
     'Gabon': ['Equatorial Guinea'],
     'Ghana': ['Ivory Coast', 'Togo'],
     'Guinea': ['Guinea-Bissau', 'Ivory Coast', 'Liberia', 'Sierra Leone'],
     'Kenya': ['Somalia', 'South Sudan', 'Tanzania', 'Uganda'],
     'Liberia': ['Ivory Coast', 'Sierra Leone'],
     'Libya': ['Egypt', 'Niger', 'Sudan', 'Tunisia'],
     'Mali': ['Guinea', 'Ivory Coast', 'Mauritania', 'Niger', 'Senegal'],
     'Mozambique': ['Malawi', 'South Africa', 'Swaziland', 'Zimbabwe'],
     'Niger': ['Nigeria'],
     'Rwanda': ['Burundi', 'Tanzania', 'Uganda'],
     'Senegal': ['Guinea', 'Guinea-Bissau', 'Mauritania', 'Gambia'],
     'South Africa': ['Lesotho', 'Namibia', 'Swaziland', 'Zimbabwe'],
     'South Sudan': ['Uganda', 'Sudan', 'Democratic Republic of the Congo'],
     'Sudan': ['Egypt', 'Eritrea'],
     'Tanzania': ['Burundi', 'Malawi', 'Mozambique', 'Uganda', 'Zambia'],
     'Zambia': ['Malawi', 'Mozambique', 'Namibia', 'Zimbabwe']
     }

    no_land_border = ['Cape Verde', 'Seychelles', 'Mauritius', u'São Tomé and Príncipe', 'Madagascar', 'Comoros']

    G = Graph(common_border, format='dict_of_lists')

    if continental:
        G = G.subgraph(G.connected_component_containing_vertex('Central Africa'))
        G.name(new="Continental Africa Map")
    else:
        G.add_vertices(no_land_border)
        G.name(new="Africa Map")

    return G
Example #40
0
def PermutationGraph(second_permutation, first_permutation = None):
    r"""
    Builds a permutation graph from one (or two) permutations.

    General definition

    A Permutation Graph can be encoded by a permutation `\sigma`
    of `1, ..., n`. It is then built in the following way :

      Take two horizontal lines in the euclidean plane, and mark points `1, ...,
      n` from left to right on the first of them. On the second one, still from
      left to right, mark point in the order in which they appear in `\sigma`.
      Now, link by a segment the two points marked with 1, then link together
      the points marked with 2, and so on. The permutation graph defined by the
      permutation is the intersection graph of those segments : there exists a
      point in this graph for each element from `1` to `n`, two vertices `i, j`
      being adjacent if the segments `i` and `j` cross each other.

    The set of edges of the resulting graph is equal to the set of inversions of
    the inverse of the given permutation.

    INPUT:

    - ``second_permutation`` -- the permutation from which the graph should be
      built. It corresponds to the ordering of the elements on the second line
      (see previous definition)

    - ``first_permutation`` (optional) -- the ordering of the elements on the
      *first* line. This is useful when the elements have no natural ordering,
      for instance when they are strings, or tuples, or anything else.

      When ``first_permutation == None`` (default), it is set to be equal to
      ``sorted(second_permutation)``, which just yields the expected
      ordering when the elements of the graph are integers.

    .. SEEALSO:

      - Recognition of Permutation graphs in the :mod:`comparability module
        <sage.graphs.comparability>`.

      - Drawings of permutation graphs as intersection graphs of segments is
        possible through the
        :meth:`~sage.combinat.permutation.Permutation.show` method of
        :class:`~sage.combinat.permutation.Permutation` objects.

        The correct argument to use in this case is ``show(representation =
        "braid")``.

      - :meth:`~sage.combinat.permutation.Permutation.inversions`

    EXAMPLE::

        sage: p = Permutations(5).random_element()
        sage: edges = graphs.PermutationGraph(p).edges(labels =False)
        sage: set(edges) == set(p.inverse().inversions())
        True

    TESTS::

        sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6])
        Traceback (most recent call last):
        ...
        ValueError: The two permutations do not contain the same set of elements ...
    """
    if first_permutation == None:
        first_permutation = sorted(second_permutation)
    else:
        if set(second_permutation) != set(first_permutation):
            raise ValueError("The two permutations do not contain the same "+
                             "set of elements ! It is going to be pretty "+
                             "hard to define a permutation graph from that !")

    vertex_to_index = {}
    for i, v in enumerate(first_permutation):
        vertex_to_index[v] = i+1

    from sage.combinat.permutation import Permutation
    p2 = Permutation(map(lambda x:vertex_to_index[x], second_permutation))
    p1 = Permutation(map(lambda x:vertex_to_index[x], first_permutation))
    p2 = p2 * p1.inverse()
    p2 = p2.inverse()

    g = Graph(name="Permutation graph for "+str(second_permutation))
    g.add_vertices(second_permutation)

    for u,v in p2.inversions():
        g.add_edge(first_permutation[u-1], first_permutation[v-1])

    return g
Example #41
0
def EuropeMap(continental=False, year=2018):
    """
    Return European states as a graph of common border.

    "European state" here is defined as an independent
    state having the capital city in Europe. The graph
    has an edge between those countries that have common
    *land* border.

    INPUT:

    - ``continental``, a Boolean -- if set, only return states in
      the continental Europe
    - ``year`` -- reserved for future use

    EXAMPLES::

        sage: Europe = graphs.EuropeMap(); Europe
        Europe Map: Graph on 44 vertices
        sage: Europe.neighbors('Ireland')
        ['United Kingdom']

        sage: cont_Europe = graphs.EuropeMap(continental=True)
        sage: cont_Europe.order()
        40
        sage: 'Iceland' in cont_Europe
        False
    """
    if year != 2018:
        raise ValueError("currently only year 2018 is implemented")

    common_border = {
     'Poland': ['Slovakia', 'Czech Republic', 'Lithuania', 'Russia', 'Ukraine', 'Germany'],
     'Germany': ['Czech Republic', 'Netherlands', 'Switzerland', 'Luxembourg', 'Denmark'],
     'Croatia': ['Bosnia and Herzegovina', 'Serbia', 'Hungary', 'Montenegro', 'Slovenia'],
     'Austria': ['Czech Republic', 'Germany', 'Switzerland', 'Slovenia', 'Liechtenstein'],
     'France': ['Germany', 'Italy', 'Switzerland', 'Monaco', 'Luxembourg', 'Andorra'],
     'Hungary': ['Slovakia', 'Serbia', 'Romania', 'Ukraine', 'Slovenia', 'Austria'],
     'Italy': ['Switzerland', 'Vatican City', 'San Marino', 'Slovenia', 'Austria'],
     'Belarus': ['Poland', 'Latvia', 'Lithuania', 'Russia', 'Ukraine'],
     'Montenegro': ['Bosnia and Herzegovina', 'Serbia', 'Albania'],
     'Belgium': ['Germany', 'Netherlands', 'Luxembourg', 'France'],
     'Russia': ['Finland', 'Lithuania', 'Estonia', 'Ukraine'],
     'Romania': ['Serbia', 'Moldova', 'Bulgaria', 'Ukraine'],
     'Latvia': ['Lithuania', 'Russia', 'Estonia'],
     'Slovakia': ['Czech Republic', 'Ukraine', 'Austria'], 'Switzerland': ['Liechtenstein'],
     'Spain': ['Portugal', 'Andorra', 'France'], 'Norway': ['Finland', 'Sweden', 'Russia'],
     'Ireland': ['United Kingdom'], 'Serbia': ['Bosnia and Herzegovina', 'Bulgaria'],
     'Greece': ['Macedonia', 'Bulgaria', 'Albania'], 'Ukraine': ['Moldova'],
     'Macedonia': ['Serbia', 'Bulgaria', 'Albania'], 'Sweden': ['Finland']
    }
    no_land_border = ['Iceland', 'Malta']

    G = Graph(common_border, format='dict_of_lists')

    if continental:
        G = G.subgraph(G.connected_component_containing_vertex('Austria'))
        G.name(new="Continental Europe Map")
    else:
        G.add_vertices(no_land_border)
        G.name(new="Europe Map")

    return G
Example #42
0
def AffineOrthogonalPolarGraph(d, q, sign="+"):
    r"""
    Returns the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`.

    Affine Polar graphs are built from a `d`-dimensional vector space over
    `F_q`, and a quadratic form which is hyperbolic, elliptic or parabolic
    according to the value of ``sign``.

    Note that `VO^+(d,q),VO^-(d,q)` are strongly regular graphs, while `VO(d,q)`
    is not.

    For more information on Affine Polar graphs, see `Affine Polar
    Graphs page of Andries Brouwer's website
    <http://www.win.tue.nl/~aeb/graphs/VO.html>`_.

    INPUT:

    - ``d`` (integer) -- ``d`` must be even if ``sign != None``, and odd
      otherwise.

    - ``q`` (integer) -- a power of a prime number, as `F_q` must exist.

    - ``sign`` -- must be equal to ``"+"``, ``"-"``, or ``None`` to compute
      (respectively) `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. By default
      ``sign="+"``.

    .. NOTE::

        The graph `VO^\epsilon(d,q)` is the graph induced by the
        non-neighbors of a vertex in an :meth:`Orthogonal Polar Graph
        <OrthogonalPolarGraph>` `O^\epsilon(d+2,q)`.

    EXAMPLES:

    The :meth:`Brouwer-Haemers graph <BrouwerHaemersGraph>` is isomorphic to
    `VO^-(4,3)`::

        sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-")
        sage: g.is_isomorphic(graphs.BrouwerHaemersGraph())
        True

    Some examples from `Brouwer's table or strongly regular graphs
    <http://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`_::

        sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g
        Affine Polar Graph VO^-(6,2): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 27, 10, 12)
        sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g
        Affine Polar Graph VO^+(6,2): Graph on 64 vertices
        sage: g.is_strongly_regular(parameters=True)
        (64, 35, 18, 20)

    When ``sign is None``::

        sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g
        Affine Polar Graph VO^-(5,2): Graph on 32 vertices
        sage: g.is_strongly_regular(parameters=True)
        False
        sage: g.is_regular()
        True
        sage: g.is_vertex_transitive()
        True
    """
    if sign in ["+", "-"]:
        s = 1 if sign == "+" else -1
        if d % 2 == 1:
            raise ValueError("d must be even when sign!=None")
    else:
        if d % 2 == 0:
            raise ValueError("d must be odd when sign==None")
        s = 0

    from sage.interfaces.gap import gap
    from sage.rings.finite_rings.constructor import FiniteField
    from sage.modules.free_module import VectorSpace
    from sage.matrix.constructor import Matrix
    from sage.libs.gap.libgap import libgap
    from itertools import combinations

    M = Matrix(
        libgap.InvariantQuadraticForm(libgap.GeneralOrthogonalGroup(
            s, d, q))['matrix'])
    F = libgap.GF(q).sage()
    V = list(VectorSpace(F, d))

    G = Graph()
    G.add_vertices([tuple(_) for _ in V])
    for x, y in combinations(V, 2):
        if not (x - y) * M * (x - y):
            G.add_edge(tuple(x), tuple(y))

    G.name("Affine Polar Graph VO^" + str('+' if s == 1 else '-') + "(" +
           str(d) + "," + str(q) + ")")
    G.relabel()
    return G
Example #43
0
def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set):
    """
    Return the Coxeter type of ``coxeter_matrix`` if known,
    otherwise return ``None``.

    EXAMPLES:

    Some infinite ones::

        sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]])
        sage: C.is_finite()  # indirect doctest
        False
        sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
        sage: C.is_finite()  # indirect doctest
        False

    Some finite ones::

        sage: m = matrix(CoxeterMatrix(['D', 4]))
        sage: CoxeterMatrix(m).is_finite()  # indirect doctest
        True
        sage: m = matrix(CoxeterMatrix(['H', 4]))
        sage: CoxeterMatrix(m).is_finite()  # indirect doctest
        True

        sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['A', 10]
        sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['B', 10]
        sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['B', 10]
        sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type()
        Coxeter type of ['D', 10]
        sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 6]
        sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 7]
        sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 8]
        sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type()
        Coxeter type of ['F', 4]
        sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type()
        Coxeter type of ['G', 2]
        sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type()
        Coxeter type of ['H', 3]
        sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type()
        Coxeter type of ['H', 4]
        sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type()
        Coxeter type of ['I', 100]

    Some affine graphs::

        sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['A', 1, 1]
        sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['A', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['B', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['C', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['D', 10, 1]
        sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 6, 1]
        sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 7, 1]
        sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['E', 8, 1]
        sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['F', 4, 1]
        sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type()
        Coxeter type of ['G', 2, 1]

    TESTS:

    Check that we detect relabellings::

        sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c'])
        sage: M.coxeter_type()
        Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'}

        sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix
        sage: for C in CoxeterMatrix.samples():
        ....:     relabelling_perm = Permutations(C.index_set()).random_element()
        ....:     relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())}
        ....:     relabeled_matrix = C.relabel(relabelling_dict)._matrix
        ....:     recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm)
        ....:     if C.is_finite() or C.is_affine():
        ....:         assert recognized_type == C.coxeter_type()

    We check the rank 2 cases (:trac:`20419`)::

        sage: for i in range(2, 10):
        ....:     M = matrix([[1,i],[i,1]])
        ....:     CoxeterMatrix(M).coxeter_type()
        Coxeter type of A1xA1 relabelled by {1: 2}
        Coxeter type of ['A', 2]
        Coxeter type of ['B', 2]
        Coxeter type of ['I', 5]
        Coxeter type of ['G', 2]
        Coxeter type of ['I', 7]
        Coxeter type of ['I', 8]
        Coxeter type of ['I', 9]
        sage: CoxeterMatrix(matrix([[1,-1],[-1,1]]), index_set=[0,1]).coxeter_type()
        Coxeter type of ['A', 1, 1]
    """
    # First, we build the Coxeter graph of the group without the edge labels
    n = ZZ(coxeter_matrix.nrows())
    G = Graph(
        [
            [index_set[i], index_set[j], coxeter_matrix[i, j]]
            for i in range(n)
            for j in range(i, n)
            if coxeter_matrix[i, j] not in [1, 2]
        ]
    )
    G.add_vertices(index_set)

    types = []
    for S in G.connected_components_subgraphs():
        r = S.num_verts()
        # Handle the special cases first
        if r == 1:
            types.append(CoxeterType(["A", 1]).relabel({1: S.vertices()[0]}))
            continue
        if r == 2:  # Type B2, G2, or I_2(p)
            e = S.edge_labels()[0]
            if e == 3:  # Can't be 2 because it is connected
                ct = CoxeterType(["A", 2])
            elif e == 4:
                ct = CoxeterType(["B", 2])
            elif e == 6:
                ct = CoxeterType(["G", 2])
            elif e > 0 and e < float("inf"):  # Remaining non-affine types
                ct = CoxeterType(["I", e])
            else:  # Otherwise it is infinite dihedral group Z_2 \ast Z_2
                ct = CoxeterType(["A", 1, 1])
            if not ct.is_affine():
                types.append(ct.relabel({1: S.vertices()[0], 2: S.vertices()[1]}))
            else:
                types.append(ct.relabel({0: S.vertices()[0], 1: S.vertices()[1]}))
            continue

        test = [["A", r], ["B", r], ["A", r - 1, 1]]
        if r >= 3:
            if r == 3:
                test += [["G", 2, 1], ["H", 3]]
            test.append(["C", r - 1, 1])
        if r >= 4:
            if r == 4:
                test += [["F", 4], ["H", 4]]
            test += [["D", r], ["B", r - 1, 1]]
        if r >= 5:
            if r == 5:
                test.append(["F", 4, 1])
            test.append(["D", r - 1, 1])
        if r == 6:
            test.append(["E", 6])
        elif r == 7:
            test += [["E", 7], ["E", 6, 1]]
        elif r == 8:
            test += [["E", 8], ["E", 7, 1]]
        elif r == 9:
            test.append(["E", 8, 1])

        found = False
        for ct in test:
            ct = CoxeterType(ct)
            T = ct.coxeter_graph()
            iso, match = T.is_isomorphic(S, certify=True, edge_labels=True)
            if iso:
                types.append(ct.relabel(match))
                found = True
                break
        if not found:
            return None

    return CoxeterType(types)
Example #44
0
def RandomBipartite(n1, n2, p):
    r"""
    Returns a bipartite graph with `n1+n2` vertices
    such that any edge from `[n1]` to `[n2]` exists
    with probability `p`.

    INPUT:

        - ``n1,n2`` : Cardinalities of the two sets
        - ``p``   : Probability for an edge to exist


    EXAMPLE::

        sage: g=graphs.RandomBipartite(5,2,0.5)
        sage: g.vertices()
        [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)]

    TESTS::

        sage: g=graphs.RandomBipartite(5,-3,0.5)
        Traceback (most recent call last):
        ...
        ValueError: n1 and n2 should be integers strictly greater than 0
        sage: g=graphs.RandomBipartite(5,3,1.5)
        Traceback (most recent call last):
        ...
        ValueError: Parameter p is a probability, and so should be a real value between 0 and 1

    Trac ticket #12155::

        sage: graphs.RandomBipartite(5,6,.2).complement()
        complement(Random bipartite graph of size 5+6 with edge probability 0.200000000000000): Graph on 11 vertices
    """
    if not (p >= 0 and p <= 1):
        raise ValueError, "Parameter p is a probability, and so should be a real value between 0 and 1"
    if not (n1 > 0 and n2 > 0):
        raise ValueError, "n1 and n2 should be integers strictly greater than 0"

    from numpy.random import uniform
    from sage.graphs.all import Graph

    g = Graph(name="Random bipartite graph of size " + str(n1) + "+" +
              str(n2) + " with edge probability " + str(p))

    S1 = [(0, i) for i in range(n1)]
    S2 = [(1, i) for i in range(n2)]
    g.add_vertices(S1)
    g.add_vertices(S2)

    for w in range(n2):
        for v in range(n1):
            if uniform() <= p:
                g.add_edge((0, v), (1, w))

    pos = {}
    for i in range(n1):
        pos[(0, i)] = (0, i / (n1 - 1.0))
    for i in range(n2):
        pos[(1, i)] = (1, i / (n2 - 1.0))

    g.set_pos(pos)

    return g
Example #45
0
        def dual_equivalence_class(self, index_set=None):
            r"""
            Return the dual equivalence class indexed by ``index_set``
            of ``self``.

            The dual equivalence class of an element `b \in B`
            is the set of all elements of `B` reachable from
            `b` via sequences of `i`-elementary dual equivalence
            relations (i.e., `i`-elementary dual equivalence
            transformations and their inverses) for `i` in the index
            set of `B`.

            For this to be well-defined, the element `b` has to be
            of weight `0` with respect to `I`; that is, we need to have
            `\varepsilon_j(b) = \varphi_j(b)` for all `j \in I`.

            See [Assaf08]_. See also :meth:`dual_equivalence_graph` for
            a definition of `i`-elementary dual equivalence
            transformations.

            INPUT:

            - ``index_set`` -- (optional) the index set `I`
              (default: the whole index set of the crystal); this has
              to be a subset of the index set of the crystal (as a list
              or tuple)

            OUTPUT:

            The dual equivalence class of ``self`` indexed by the
            subset ``index_set``. This class is returned as an
            undirected edge-colored multigraph. The color of an edge
            is the index `i` of the dual equivalence relation it
            encodes.

            .. SEEALSO::

                - :meth:`~sage.categories.regular_crystals.RegularCrystals.ParentMethods.dual_equivalence_graph`
                - :meth:`sage.combinat.partition.Partition.dual_equivalence_graph`

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',3], shape=[2,2])
                sage: G = T(2,1,4,3).dual_equivalence_class()
                sage: sorted(G.edges())
                [([[1, 3], [2, 4]], [[1, 2], [3, 4]], 2),
                 ([[1, 3], [2, 4]], [[1, 2], [3, 4]], 3)]
                sage: T = crystals.Tableaux(['A',4], shape=[3,2])
                sage: G = T(2,1,4,3,5).dual_equivalence_class()
                sage: sorted(G.edges())
                [([[1, 3, 5], [2, 4]], [[1, 3, 4], [2, 5]], 4),
                 ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 2),
                 ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 3),
                 ([[1, 3, 4], [2, 5]], [[1, 2, 4], [3, 5]], 2),
                 ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 3),
                 ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 4)]
            """
            if index_set is None:
                index_set = self.index_set()

            for i in index_set:
                if self.epsilon(i) != self.phi(i):
                    raise ValueError("the element is not weight 0")

            visited = set([])
            todo = set([self])
            edges = []
            while todo:
                x = todo.pop()
                visited.add(x)
                for k, i in enumerate(index_set[1:]):
                    im = index_set[k]
                    if x.epsilon(i) == 1 and x.epsilon(im) == 0:
                        y = x.e(i).e(im).f(i).f(im)
                        if [y, x, i] not in edges:
                            edges.append([x, y, i])
                        if y not in visited:
                            todo.add(y)
                    if x.epsilon(i) == 0 and x.epsilon(im) == 1:
                        y = x.e(im).e(i).f(im).f(i)
                        if [y, x, i] not in edges:
                            edges.append([x, y, i])
                        if y not in visited:
                            todo.add(y)
            from sage.graphs.graph import Graph
            G = Graph(edges, multiedges=True)
            G.add_vertices(visited)
            if have_dot2tex():
                G.set_latex_options(
                    format="dot2tex",
                    edge_labels=True,
                    color_by_label=self.cartan_type()._index_set_coloring)
            return G