Example #1
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 #2
0
    def cluster_in_box(self, m, pt=None):
        r"""
        Return the cluster (as a list) in the primal box [-m,m]^d
        containing the point pt.

        INPUT:

        - ``m`` - integer
        - ``pt`` - tuple, point in Z^d. If None, pt=zero is considered.

        EXAMPLES::

            sage: from slabbe import BondPercolationSample
            sage: S = BondPercolationSample(0.3,2)
            sage: S.cluster_in_box(2)         # random
            [(-2, -2), (-2, -1), (-1, -2), (-1, -1), (-1, 0), (0, 0)]
        """
        G = Graph()
        G.add_edges(self.edges_in_box(m))
        if pt is None:
            pt = self.zero()
        if pt in G:
            return G.connected_component_containing_vertex(pt)
        else:
            return []
Example #3
0
    def cluster_in_box(self, m, pt=None):
        r"""
        Return the cluster (as a list) in the primal box [-m,m]^d
        containing the point pt.

        INPUT:

        - ``m`` - integer
        - ``pt`` - tuple, point in Z^d. If None, pt=zero is considered.

        EXAMPLES::

            sage: from slabbe import BondPercolationSample
            sage: S = BondPercolationSample(0.3,2)
            sage: S.cluster_in_box(2)         # random
            [(-2, -2), (-2, -1), (-1, -2), (-1, -1), (-1, 0), (0, 0)]
        """
        G = Graph()
        G.add_edges(self.edges_in_box(m))
        if pt is None:
            pt = self.zero()
        if pt in G:
            return G.connected_component_containing_vertex(pt)
        else:
            return []
Example #4
0
def _polar_graph(m, q, g, intersection_size=None):
    r"""
    The helper function to build graphs `(D)U(m,q)` and `(D)Sp(m,q)`

    Building a graph on an orbit of a group `g` of `m\times m` matrices over `GF(q)` on
    the points (or subspaces of dimension ``m//2``) isotropic w.r.t. the form `F`
    left invariant by the group `g`.

    The only constraint is that the first ``m//2`` elements of the standard
    basis must generate a totally isotropic w.r.t. `F` subspace; this is the case with
    these groups coming from GAP; namely, `F` has the anti-diagonal all-1 matrix.

    INPUT:

    - ``m`` -- the dimension of the underlying vector space

    - ``q`` -- the size of the field

    - ``g`` -- the group acting

    - ``intersection_size`` -- if ``None``, build the graph on the isotropic points, with
      adjacency being orthogonality w.r.t. `F`. Otherwise, build the graph on the maximal
      totally isotropic subspaces, with adjacency specified by ``intersection_size`` being
      as given.

    TESTS::

        sage: from sage.graphs.generators.classical_geometries import _polar_graph
        sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2))
        Graph on 45 vertices
        sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1)
        Graph on 27 vertices
    """
    from sage.libs.gap.libgap import libgap
    from itertools import combinations
    W = libgap.FullRowSpace(libgap.GF(q), m)  # F_q^m
    B = libgap.Elements(libgap.Basis(W))  # the standard basis of W
    V = libgap.Orbit(g, B[0], libgap.OnLines)  # orbit on isotropic points
    gp = libgap.Action(g, V, libgap.OnLines)  # make a permutation group
    s = libgap.Subspace(
        W, [B[i] for i in range(m // 2)])  # a totally isotropic subspace
    # and the points there
    sp = [
        libgap.Elements(libgap.Basis(x))[0]
        for x in libgap.Elements(s.Subspaces(1))
    ]
    h = libgap.Set(map(lambda x: libgap.Position(V, x),
                       sp))  # indices of the points in s
    L = libgap.Orbit(gp, h, libgap.OnSets)  # orbit on these subspaces
    if intersection_size == None:
        G = Graph()
        for x in L:  # every pair of points in the subspace is adjacent to each other in G
            G.add_edges(combinations(x, 2))
        return G
    else:
        return Graph([
            L, lambda i, j: libgap.Size(libgap.Intersection(i, j)) ==
            intersection_size
        ],
                     loops=False)
Example #5
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 #6
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 #7
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 #8
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 #9
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 #10
0
def _polar_graph(m, q, g, intersection_size=None):
    r"""
    The helper function to build graphs `(D)U(m,q)` and `(D)Sp(m,q)`

    Building a graph on an orbit of a group `g` of `m\times m` matrices over `GF(q)` on
    the points (or subspaces of dimension ``m//2``) isotropic w.r.t. the form `F`
    left invariant by the group `g`.

    The only constraint is that the first ``m//2`` elements of the standard
    basis must generate a totally isotropic w.r.t. `F` subspace; this is the case with
    these groups coming from GAP; namely, `F` has the anti-diagonal all-1 matrix.

    INPUT:

    - ``m`` -- the dimension of the underlying vector space

    - ``q`` -- the size of the field

    - ``g`` -- the group acting

    - ``intersection_size`` -- if ``None``, build the graph on the isotropic points, with
      adjacency being orthogonality w.r.t. `F`. Otherwise, build the graph on the maximal
      totally isotropic subspaces, with adjacency specified by ``intersection_size`` being
      as given.

    TESTS::

        sage: from sage.graphs.generators.classical_geometries import _polar_graph
        sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2))
        Graph on 45 vertices
        sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1)
        Graph on 27 vertices
    """
    from sage.libs.gap.libgap import libgap
    from itertools import combinations
    W=libgap.FullRowSpace(libgap.GF(q), m)  # F_q^m
    B=libgap.Elements(libgap.Basis(W))      # the standard basis of W
    V = libgap.Orbit(g,B[0],libgap.OnLines) # orbit on isotropic points
    gp = libgap.Action(g,V,libgap.OnLines)  # make a permutation group
    s = libgap.Subspace(W,[B[i] for i in range(m//2)]) # a totally isotropic subspace
    # and the points there
    sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))]
    h = libgap.Set(map(lambda x: libgap.Position(V, x), sp)) # indices of the points in s
    L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces
    if intersection_size == None:
        G = Graph()
        for x in L: # every pair of points in the subspace is adjacent to each other in G
            G.add_edges(combinations(x, 2))
        return G
    else:
        return Graph([L, lambda i,j: libgap.Size(libgap.Intersection(i,j))==intersection_size],
                        loops=False)
Example #11
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 #12
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 #13
0
def CircularLadderGraph(n):
    r"""
    Return 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.

    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.
    When `n == 2`, we rotate the outer circle by an angle of `\pi/8` to ensure
    that all edges are visible (otherwise the 4 vertices of the graph would be
    placed on a single line).

    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 = graphics_array(j)
        sage: G.show() # long time
    """
    G = Graph(2 * n, name="Circular Ladder graph")
    G._circle_embedding(list(range(n)), radius=1, angle=pi/2)
    if n == 2:
        G._circle_embedding(list(range(4)), radius=1, angle=pi/2 + pi/8)
    else:
        G._circle_embedding(list(range(n, 2*n)), radius=2, angle=pi/2)
    G.add_cycle(list(range(n)))
    G.add_cycle(list(range(n, 2 * n)))
    G.add_edges((i, i + n) for i in range(n))
    return G
Example #14
0
def CircularLadderGraph(n):
    r"""
    Return 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.

    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.
    When `n == 2`, we rotate the outer circle by an angle of `\pi/8` to ensure
    that all edges are visible (otherwise the 4 vertices of the graph would be
    placed on a single line).

    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
    """
    G = Graph(2 * n, name="Circular Ladder graph")
    G._circle_embedding(list(range(n)), radius=1, angle=pi/2)
    if n == 2:
        G._circle_embedding(list(range(4)), radius=1, angle=pi/2 + pi/8)
    else:
        G._circle_embedding(list(range(n, 2*n)), radius=2, angle=pi/2)
    G.add_cycle(list(range(n)))
    G.add_cycle(list(range(n, 2 * n)))
    G.add_edges( (i,i+n) for i in range(n) )
    return G
Example #15
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 #16
0
def read_mtx(f):
    contents = f.readlines()
    edges = []
    first = 0
    for i in range(len(contents)):
        words = contents[i].split()
        if words[0][0] != '%':
            if first == 0:
                first = 1
            else:
                if(len(words) == 3):
                    edges.append((int(words[0]), int(words[1]), float(words[2])))
                else:
                    edges.append((int(words[0]), int(words[1]), None))

    g = Graph()
    g.add_edges(edges)
    return g
Example #17
0
def read_mtx(f):
    contents = f.readlines()
    edges = []
    first = 0
    for i in range(len(contents)):
        words = contents[i].split()
        if words[0][0] != '%':
            if first == 0:
                first = 1
            else:
                if (len(words) == 3):
                    edges.append(
                        (int(words[0]), int(words[1]), float(words[2])))
                else:
                    edges.append((int(words[0]), int(words[1]), None))

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

    INPUT:

    - ``bibd`` -- a list of blocks

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

    - ``S`` -- list of integers

    EXAMPLE::

        sage: designs.BalancedIncompleteBlockDesign(40,4).blocks() # indirect doctest
        [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 11], [0, 5, 7, 10],
         [0, 13, 26, 39], [0, 14, 28, 38], [0, 15, 25, 27],
         [0, 16, 32, 35], [0, 17, 34, 37], [0, 18, 33, 36],
        ...
    """
    from itertools import combinations
    from sage.graphs.graph import Graph

    if not all(len(X) in S for X in B):
        raise RuntimeError(
            "This is not a nice honest PBD from the good old days !")

    g = Graph()
    m = 0
    for X in B:
        g.add_edges(list(combinations(X, 2)))
        if g.size() != m + binomial(len(X), 2):
            raise RuntimeError(
                "This is not a nice honest PBD from the good old days !")
        m = g.size()

    if not (g.is_clique() and g.vertices() == range(v)):
        raise RuntimeError(
            "This is not a nice honest PBD from the good old days !")

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

    INPUT:

    - ``bibd`` -- a list of blocks

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

    - ``S`` -- list of integers

    EXAMPLE::

        sage: designs.BalancedIncompleteBlockDesign(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],
        ...
    """
    from itertools import combinations
    from sage.graphs.graph import Graph

    if not all(len(X) in S for X in B):
        raise RuntimeError("This is not a nice honest PBD from the good old days !")

    g = Graph()
    m = 0
    for X in B:
        g.add_edges(list(combinations(X,2)))
        if g.size() != m+binomial(len(X),2):
            raise RuntimeError("This is not a nice honest PBD from the good old days !")
        m = g.size()

    if not (g.is_clique() and g.vertices() == range(v)):
        raise RuntimeError("This is not a nice honest PBD from the good old days !")

    return B
Example #20
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, [])
Example #21
0
def CompleteBipartiteGraph(n1, n2, set_position=True):
    r"""
    Return a Complete Bipartite Graph on `n1 + n2` vertices.

    A Complete Bipartite Graph is a graph with its vertices partitioned into two
    groups, `V_1 = \{0,...,n1-1\}` and `V_2 = \{n1,...,n1+n2-1\}`. Each `u \in
    V_1` is connected to every `v \in V_2`.

    INPUT:

    - ``n1, n2`` -- number of vertices in each side

    - ``set_position`` -- boolean (default ``True``); if set to ``True``, we
      assign positions to the vertices so that the set of cardinality `n1` is
      on the line `y=1` and the set of cardinality `n2` is on the line `y=0`.

    PLOTTING: Upon construction, the position dictionary is filled to override
    the spring-layout algorithm. By convention, each complete bipartite graph
    will be displayed with the first `n1` nodes on the top row (at `y=1`) from
    left to right. The remaining `n2` nodes appear at `y=0`, also from left to
    right. The shorter row (partition with fewer nodes) is stretched to the same
    length as the longer row, unless the shorter row has 1 node; in which case
    it is centered. The `x` values in the plot are in domain `[0, \max(n1,
    n2)]`.

    In the Complete Bipartite graph, there is a visual difference in using the
    spring-layout algorithm vs. the position dictionary used in this
    constructor. The position dictionary flattens the graph and separates the
    partitioned nodes, making it clear which nodes an edge is connected to. The
    Complete Bipartite graph plotted with the spring-layout algorithm tends to
    center the nodes in n1 (see spring_med in examples below), thus overlapping
    its nodes and edges, making it typically hard to decipher.

    Filling the position dictionary in advance adds `O(n)` to the constructor.
    Feel free to race the constructors below in the examples section. The much
    larger difference is the time added by the spring-layout algorithm when
    plotting. (Also shown in the example below). The spring model is typically
    described as `O(n^3)`, as appears to be the case in the NetworkX source
    code.

    EXAMPLES:

    Two ways of constructing the complete bipartite graph, using different
    layout algorithms::

        sage: import networkx
        sage: n = networkx.complete_bipartite_graph(389, 157); spring_big = Graph(n)   # long time
        sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157)                    # long time

    Compare the plotting::

        sage: n = networkx.complete_bipartite_graph(11, 17)
        sage: spring_med = Graph(n)
        sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)

    Notice here how the spring-layout tends to center the nodes of `n1`::

        sage: spring_med.show() # long time
        sage: posdict_med.show() # long time

    View many complete bipartite graphs with a Sage Graphics Array, with this
    constructor (i.e., the position dictionary filled)::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.CompleteBipartiteGraph(i+1,4)
        ....:     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

    We compare to plotting with the spring-layout algorithm::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     spr = networkx.complete_bipartite_graph(i+1,4)
        ....:     k = Graph(spr)
        ....:     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

    :trac:`12155`::

        sage: graphs.CompleteBipartiteGraph(5,6).complement()
        complement(Complete bipartite graph of order 5+6): Graph on 11 vertices

    TESTS:

    Prevent negative dimensions (:trac:`18530`)::

        sage: graphs.CompleteBipartiteGraph(-1,1)
        Traceback (most recent call last):
        ...
        ValueError: the arguments n1(=-1) and n2(=1) must be positive integers
        sage: graphs.CompleteBipartiteGraph(1,-1)
        Traceback (most recent call last):
        ...
        ValueError: the arguments n1(=1) and n2(=-1) must be positive integers
    """
    if n1<0 or n2<0:
        raise ValueError('the arguments n1(={}) and n2(={}) must be positive integers'.format(n1,n2))

    G = Graph(n1+n2, name="Complete bipartite graph of order {}+{}".format(n1, n2))
    G.add_edges((i,j) for i in range(n1) for j in range(n1,n1+n2))

    # We now assign positions to vertices:
    # - vertices 0,..,n1-1 are placed on the line (0, 1) to (max(n1, n2), 1)
    # - vertices n1,..,n1+n2-1 are placed on the line (0, 0) to (max(n1, n2), 0)
    # If n1 (or n2) is 1, the vertex is centered in the line.
    if set_position:
        nmax = max(n1, n2)
        G._line_embedding(list(range(n1)), first=(0, 1), last=(nmax, 1))
        G._line_embedding(list(range(n1, n1+n2)), first=(0, 0), last=(nmax, 0))

    return G
Example #22
0
def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None):
    r"""
    Returns the Graph `NO^{\epsilon,\perp}_{m}(q)`

    Let the vectorspace of dimension `m` over `F_q` be
    endowed with a nondegenerate quadratic form `F`, of type ``sign`` for `m` even.

    * `m` even: assume further that `q=2` or `3`. Returns the graph of the
      points (in the underlying projective space) `x` satisfying `F(x)=1`, with adjacency
      given by orthogonality w.r.t. `F`. Parameter ``perp`` is ignored.

    * `m` odd: if ``perp`` is not ``None``, then we assume that `q=5` and
      return the graph of the points `x` satisfying `F(x)=\pm 1` if ``sign="+"``,
      respectively `F(x) \in \{2,3\}` if ``sign="-"``, with adjacency
      given by orthogonality w.r.t. `F` (cf. Sect 7.D of [BvL84]_).
      Otherwise return the graph
      of nongenerate hyperplanes of type ``sign``, adjacent whenever the intersection
      is degenerate (cf. Sect. 7.C of [BvL84]_).
      Note that for `q=2` one will get a complete graph.

    For more information, see Sect. 9.9 of [BH12]_ and [BvL84]_. Note that the `page of
    Andries Brouwer's website <http://www.win.tue.nl/~aeb/graphs/srghub.html>`_
    uses different notation.

    INPUT:

    - ``m``  - integer,  half the dimension of the underlying vectorspace

    - ``q``  - a power of a prime number, the size of the underlying field

    - ``sign`` -- ``"+"`` (default) or ``"-"``.

    EXAMPLES:

    `NO^-(4,2)` is isomorphic to Petersen graph::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g
        NO^-(4, 2): Graph on 10 vertices
        sage: g.is_strongly_regular(parameters=True)
        (10, 3, 0, 1)

    `NO^-(6,2)` and `NO^+(6,2)`::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'-')
        sage: g.is_strongly_regular(parameters=True)
        (36, 15, 6, 6)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g
        NO^+(6, 2): Graph on 28 vertices
        sage: g.is_strongly_regular(parameters=True)
        (28, 15, 6, 10)

    `NO^+(8,2)`::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(8,2,'+')
        sage: g.is_strongly_regular(parameters=True)
        (120, 63, 30, 36)

    Wilbrink's graphs for `q=5`::

        sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time
        (325, 60, 15, 10)
        sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time
        (300, 65, 10, 15)

    Wilbrink's graphs::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'+')
        sage: g.is_strongly_regular(parameters=True)
        (136, 75, 42, 40)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-')
        sage: g.is_strongly_regular(parameters=True)
        (120, 51, 18, 24)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time)
        NO^+(7, 4): Graph on 2080 vertices
        sage: g.is_strongly_regular(parameters=True) # not tested (long time)
        (2080, 1071, 558, 544)

    TESTS::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2); g
        NO^+(4, 2): Graph on 6 vertices
        sage: graphs.NonisotropicOrthogonalPolarGraph(4,3,'-').is_strongly_regular(parameters=True)
        (15, 6, 1, 3)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g
        NO^-,perp(3, 5): Graph on 10 vertices
        sage: g.is_strongly_regular(parameters=True)
        (10, 3, 0, 1)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'+')   # long time
        sage: g.is_strongly_regular(parameters=True)               # long time
        (117, 36, 15, 9)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time
        NO^-(6, 3): Graph on 126 vertices
        sage: g.is_strongly_regular(parameters=True)                # long time
        (126, 45, 12, 18)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,5,'-')    # long time
        sage: g.is_strongly_regular(parameters=True)                # long time
        (300, 104, 28, 40)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,5,'+')    # long time
        sage: g.is_strongly_regular(parameters=True)                # long time
        (325, 144, 68, 60)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,4,'+')
        Traceback (most recent call last):
        ...
        ValueError: for m even q must be 2 or 3

    """
    from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph
    p, k = is_prime_power(q,get_data=True)
    if k==0:
        raise ValueError('q must be a prime power')
    dec = ''
    if m % 2 == 0:
        if q in [2,3]:
            G = _orthogonal_polar_graph(m, q, sign=sign, point_type=[1])
        else:
            raise ValueError("for m even q must be 2 or 3")
    elif not perp is None:
        if q == 5:
            G = _orthogonal_polar_graph(m, q, point_type=\
                [-1,1] if sign=='+' else [2,3] if sign=='-' else [])
            dec = ",perp"
        else:
            raise ValueError("for perp not None q must be 5")
    else:
        if not sign in ['+','-']:
            raise ValueError("sign must be '+' or '-'")
        from sage.libs.gap.libgap import libgap
        g0 = libgap.GeneralOrthogonalGroup(m,q)
        g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(),libgap.TransposedMat))
        F=libgap.GF(q)  # F_q
        W=libgap.FullRowSpace(F, m)  # F_q^m
        e = 1 if sign=='+' else -1
        n = (m-1)/2
        # we build (q^n(q^n+e)/2, (q^n-e)(q^(n-1)+e), 2(q^(2n-2)-1)+eq^(n-1)(q-1),
        #                                          2q^(n-1)(q^(n-1)+e))-srg
        # **use** v and k to select appropriate orbit and orbital
        nvert = (q**n)*(q**n+e)/2     # v
        deg = (q**n-e)*(q**(n-1)+e)   # k
        S=map(lambda x: libgap.Elements(libgap.Basis(x))[0], \
            libgap.Elements(libgap.Subspaces(W,1)))
        V = filter(lambda x: len(x)==nvert, libgap.Orbits(g,S,libgap.OnLines))
        assert len(V)==1
        V = V[0]
        gp = libgap.Action(g,V,libgap.OnLines)  # make a permutation group
        h = libgap.Stabilizer(gp,1)
        Vh = filter(lambda x: len(x)==deg, libgap.Orbits(h,libgap.Orbit(gp,1)))
        assert len(Vh)==1
        Vh = Vh[0][0]
        L = libgap.Orbit(gp, [1, Vh], libgap.OnSets)
        G = Graph()
        G.add_edges(L)
    G.name("NO^" + sign + dec + str((m, q)))
    return G
Example #23
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 #24
0
def OrthogonalArrayBlockGraph(k,n,OA=None):
    r"""
    Returns the graph of an `OA(k,n)`.

    The intersection graph of the blocks of a transversal design with parameters
    `(k,n)`, or `TD(k,n)` for short, is a strongly regular graph (unless it is a
    complete graph). Its parameters `(v,k',\lambda,\mu)` are determined by the
    parameters `k,n` via:

    .. MATH::

        v=n^2, k'=k(n-1), \lambda=(k-1)(k-2)+n-2, \mu=k(k-1)

    As transversal designs and orthogonal arrays (OA for short) are equivalent
    objects, this graph can also be built from the blocks of an `OA(k,n)`, two
    of them being adjacent if one of their coordinates match.

    For more information on these graphs, see `Andries Brouwer's page
    on Orthogonal Array graphs <www.win.tue.nl/~aeb/graphs/OA.html>`_.

    .. WARNING::

        - Brouwer's website uses the notation `OA(n,k)` instead of `OA(k,n)`

        - For given parameters `k` and `n` there can be many `OA(k,n)` : the
          graphs returned are not uniquely defined by their parameters (see the
          examples below).

        - If the function is called only with the parameter ``k`` and ``n`` the
          results might be different with two versions of Sage, or even worse :
          some could not be available anymore.

    .. SEEALSO::

        :mod:`sage.combinat.designs.orthogonal_arrays`

    INPUT:

    - ``k,n`` (integers)

    - ``OA`` -- An orthogonal array. If set to ``None`` (default) then
      :func:`~sage.combinat.designs.orthogonal_arrays.orthogonal_array` is
      called to compute an `OA(k,n)`.

    EXAMPLES::

        sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G
        OA(5,5): Graph on 25 vertices
        sage: G.is_strongly_regular(parameters=True)
        (25, 20, 15, 20)
        sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G
        OA(4,10): Graph on 100 vertices
        sage: G.is_strongly_regular(parameters=True)
        (100, 36, 14, 12)

    Two graphs built from different orthogonal arrays are also different::

        sage: k=4;n=10
        sage: OAa = designs.orthogonal_arrays.build(k,n)
        sage: OAb = [[(x+1)%n for x in R] for R in OAa]
        sage: set(map(tuple,OAa)) == set(map(tuple,OAb))
        False
        sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa)
        sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb)
        sage: Ga == Gb
        False

    As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are
    isomorphic::

        sage: Ga.is_isomorphic(Gb)
        True

    But there are examples of `OA(k,n)` for which the resulting graphs are not
    isomorphic::

        sage: oa0 = [[0, 0, 1], [0, 1, 3], [0, 2, 0], [0, 3, 2],
        ....:        [1, 0, 3], [1, 1, 1], [1, 2, 2], [1, 3, 0],
        ....:        [2, 0, 0], [2, 1, 2], [2, 2, 1], [2, 3, 3],
        ....:        [3, 0, 2], [3, 1, 0], [3, 2, 3], [3, 3, 1]]
        sage: oa1 = [[0, 0, 1], [0, 1, 0], [0, 2, 3], [0, 3, 2],
        ....:        [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1],
        ....:        [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3],
        ....:        [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]]
        sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0)
        sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1)
        sage: g0.is_isomorphic(g1)
        False

    But nevertheless isospectral::

        sage: g0.spectrum()
        [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
        sage: g1.spectrum()
        [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]

    Note that the graph ``g0`` is actually isomorphic to the affine polar graph
    `VO^+(4,2)`::

        sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0)
        True

    TESTS::

        sage: G = graphs.OrthogonalArrayBlockGraph(4,6)
        Traceback (most recent call last):
        ...
        NotImplementedError: I don't know how to build an OA(4,6)!
        sage: G = graphs.OrthogonalArrayBlockGraph(8,2)
        Traceback (most recent call last):
        ...
        ValueError: There is no OA(8,2). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) !
    """
    if n>1 and k>=n+2:
        raise ValueError("There is no OA({},{}). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) !".format(k,n))

    from itertools import combinations

    if OA is None:
        from sage.combinat.designs.orthogonal_arrays import orthogonal_array
        OA = orthogonal_array(k,n)
    else:
        assert len(OA) == n**2
        assert n == 0 or k == len(OA[0])

    OA = map(tuple,OA)

    d = [[[] for j in range(n)] for i in range(k)]
    for R in OA:
        for i,x in enumerate(R):
            d[i][x].append(R)

    g = Graph()
    for l in d:
        for ll in l:
            g.add_edges(combinations(ll,2))

    g.name("OA({},{})".format(k,n))

    return g
Example #25
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.

    EXAMPLE::

        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']

    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.gps_coordinates = gps_coordinates
    g.name("World Map")
    return g
Example #26
0
def CompleteBipartiteGraph(p, q, set_position=True):
    r"""
    Return a Complete Bipartite Graph on `p + q` vertices.

    A Complete Bipartite Graph is a graph with its vertices partitioned into two
    groups, `V_1 = \{0,...,p-1\}` and `V_2 = \{p,...,p+q-1\}`. Each `u \in
    V_1` is connected to every `v \in V_2`.

    INPUT:

    - ``p,q`` -- number of vertices in each side

    - ``set_position`` -- boolean (default ``True``); if set to ``True``, we
      assign positions to the vertices so that the set of cardinality `p` is
      on the line `y=1` and the set of cardinality `q` is on the line `y=0`.

    PLOTTING: Upon construction, the position dictionary is filled to override
    the spring-layout algorithm. By convention, each complete bipartite graph
    will be displayed with the first `p` nodes on the top row (at `y=1`) from
    left to right. The remaining `q` nodes appear at `y=0`, also from left to
    right. The shorter row (partition with fewer nodes) is stretched to the same
    length as the longer row, unless the shorter row has 1 node; in which case
    it is centered. The `x` values in the plot are in domain `[0, \max(p, q)]`.

    In the Complete Bipartite graph, there is a visual difference in using the
    spring-layout algorithm vs. the position dictionary used in this
    constructor. The position dictionary flattens the graph and separates the
    partitioned nodes, making it clear which nodes an edge is connected to. The
    Complete Bipartite graph plotted with the spring-layout algorithm tends to
    center the nodes in `p` (see ``spring_med`` in examples below), thus
    overlapping its nodes and edges, making it typically hard to decipher.

    Filling the position dictionary in advance adds `O(n)` to the constructor.
    Feel free to race the constructors below in the examples section. The much
    larger difference is the time added by the spring-layout algorithm when
    plotting. (Also shown in the example below). The spring model is typically
    described as `O(n^3)`, as appears to be the case in the NetworkX source
    code.

    EXAMPLES:

    Two ways of constructing the complete bipartite graph, using different
    layout algorithms::

        sage: import networkx
        sage: n = networkx.complete_bipartite_graph(389, 157); spring_big = Graph(n)   # long time
        sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157)                    # long time

    Compare the plotting::

        sage: n = networkx.complete_bipartite_graph(11, 17)
        sage: spring_med = Graph(n)
        sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)

    Notice here how the spring-layout tends to center the nodes of `n1`::

        sage: spring_med.show()  # long time
        sage: posdict_med.show()  # long time

    View many complete bipartite graphs with a Sage Graphics Array, with this
    constructor (i.e., the position dictionary filled)::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.CompleteBipartiteGraph(i+1,4)
        ....:     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 = graphics_array(j)
        sage: G.show()  # long time

    We compare to plotting with the spring-layout algorithm::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     spr = networkx.complete_bipartite_graph(i+1,4)
        ....:     k = Graph(spr)
        ....:     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 = graphics_array(j)
        sage: G.show()  # long time

    :trac:`12155`::

        sage: graphs.CompleteBipartiteGraph(5,6).complement()
        complement(Complete bipartite graph of order 5+6): Graph on 11 vertices

    TESTS:

    Prevent negative dimensions (:trac:`18530`)::

        sage: graphs.CompleteBipartiteGraph(-1,1)
        Traceback (most recent call last):
        ...
        ValueError: the arguments p(=-1) and q(=1) must be positive integers
        sage: graphs.CompleteBipartiteGraph(1,-1)
        Traceback (most recent call last):
        ...
        ValueError: the arguments p(=1) and q(=-1) must be positive integers
    """
    if p < 0 or q < 0:
        raise ValueError('the arguments p(={}) and q(={}) must be positive integers'.format(p, q))

    G = Graph(p + q, name="Complete bipartite graph of order {}+{}".format(p, q))
    G.add_edges((i, j) for i in range(p) for j in range(p, p + q))

    # We now assign positions to vertices:
    # - vertices 0,..,p-1 are placed on the line (0, 1) to (max(p, q), 1)
    # - vertices p,..,p+q-1 are placed on the line (0, 0) to (max(p, q), 0)
    # If p (or q) is 1, the vertex is centered in the line.
    if set_position:
        nmax = max(p, q)
        G._line_embedding(list(range(p)), first=(0, 1), last=(nmax, 1))
        G._line_embedding(list(range(p, p + q)), first=(0, 0), last=(nmax, 0))

    return G
Example #27
0
def PathGraph(n, pos=None):
    r"""
    Return a path graph with `n` nodes.

    A path graph is a graph where all inner nodes are connected to their two
    neighbors and the two end-nodes are connected to their one inner neighbors
    (i.e.: a cycle graph without the first and last node connected).

    INPUT:

    - ``n`` -- number of nodes of the path graph

    - ``pos`` -- string (default: ``None``); indicates the embedding to use
      between 'circle', 'line' or the default algorithm. See the plotting
      section below for more detail.

    PLOTTING: Upon construction, the position dictionary is filled to override
    the spring-layout algorithm. By convention, the graph may be drawn in one of
    two ways: The 'line' argument will draw the graph in a horizontal line (left
    to right) if there are less than 11 nodes. Otherwise the 'line' argument
    will append horizontal lines of length 10 nodes below, alternating left to
    right and right to left. The 'circle' argument will cause the graph to be
    drawn in a cycle-shape, with the first node at the top and then about the
    circle in a clockwise manner. By default (without an appropriate string
    argument) the graph will be drawn as a 'circle' if `10 < n < 41` and as a
    'line' for all other `n`.

    EXAMPLES: Show default drawing by size: 'line': `n \leq 10`

    ::

        sage: p = graphs.PathGraph(10)
        sage: p.show()  # long time

    'circle': `10 < n < 41`

    ::

        sage: q = graphs.PathGraph(25)
        sage: q.show()  # long time

    'line': `n \geq 41`

    ::

        sage: r = graphs.PathGraph(55)
        sage: r.show()  # long time

    Override the default drawing::

        sage: s = graphs.PathGraph(5,'circle')
        sage: s.show()  # long time
    """
    G = Graph(n, name="Path graph")

    pos_dict = {}

    # Choose appropriate drawing pattern
    circle = False
    if pos == "circle":
        circle = True
    elif pos == "line":
        circle = False
    # Otherwise use default by size of n
    elif 10 < n < 41:
        circle = True

    # Draw 'circle'
    if circle:
        if n == 1:
            G.set_pos({0: (0, 0)})
        else:
            G._circle_embedding(list(range(n)), angle=pi/2)
    # Draw 'line'
    else:
        counter = 0  # node index
        rem = n % 10  # remainder to appear on last row
        rows = n // 10  # number of rows (not counting last row)
        lr = True  # left to right

        for i in range(rows):  # note that rows doesn't include last row
            y = -i
            for j in range(10):
                if lr:
                    x = j
                else:
                    x = 9 - j
                pos_dict[counter] = (x, y)
                counter += 1
            if lr:
                lr = False
            else:
                lr = True
        y = -rows
        for j in range(rem):  # last row
            if lr:
                x = j
            else:
                x = 9 - j
            pos_dict[counter] = (x, y)
            counter += 1
        G.set_pos(pos_dict)

    G.add_edges((i, i + 1) for i in range(n - 1))
    return G
Example #28
0
def CompleteBipartiteGraph(n1, n2):
    """
    Returns a Complete Bipartite Graph sized n1+n2, with each of the
    nodes [0,(n1-1)] connected to each of the nodes [n1,(n2-1)] and
    vice versa.

    A Complete Bipartite Graph is a graph with its vertices partitioned
    into two groups, V1 and V2. Each v in V1 is connected to every v in
    V2, and vice versa.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, each complete
    bipartite graph will be displayed with the first n1 nodes on the
    top row (at y=1) from left to right. The remaining n2 nodes appear
    at y=0, also from left to right. The shorter row (partition with
    fewer nodes) is stretched to the same length as the longer row,
    unless the shorter row has 1 node; in which case it is centered.
    The x values in the plot are in domain [0,maxn1,n2].

    In the Complete Bipartite graph, there is a visual difference in
    using the spring-layout algorithm vs. the position dictionary used
    in this constructor. The position dictionary flattens the graph and
    separates the partitioned nodes, making it clear which nodes an
    edge is connected to. The Complete Bipartite graph plotted with the
    spring-layout algorithm tends to center the nodes in n1 (see
    spring_med in examples below), thus overlapping its nodes and
    edges, making it typically hard to decipher.

    Filling the position dictionary in advance adds O(n) to the
    constructor. Feel free to race the constructors below in the
    examples section. The much larger difference is the time added by
    the spring-layout algorithm when plotting. (Also shown in the
    example below). The spring model is typically described as
    `O(n^3)`, as appears to be the case in the NetworkX source
    code.

    EXAMPLES: Two ways of constructing the complete bipartite graph,
    using different layout algorithms::

        sage: import networkx
        sage: n = networkx.complete_bipartite_graph(389,157); spring_big = Graph(n)   # long time
        sage: posdict_big = graphs.CompleteBipartiteGraph(389,157)                    # long time

    Compare the plotting::

        sage: n = networkx.complete_bipartite_graph(11,17)
        sage: spring_med = Graph(n)
        sage: posdict_med = graphs.CompleteBipartiteGraph(11,17)

    Notice here how the spring-layout tends to center the nodes of n1

    ::

        sage: spring_med.show() # long time
        sage: posdict_med.show() # long time

    View many complete bipartite graphs with a Sage Graphics Array,
    with this constructor (i.e., the position dictionary filled)::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.CompleteBipartiteGraph(i+1,4)
        ....:     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

    We compare to plotting with the spring-layout algorithm::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     spr = networkx.complete_bipartite_graph(i+1,4)
        ....:     k = Graph(spr)
        ....:     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

    :trac:`12155`::

        sage: graphs.CompleteBipartiteGraph(5,6).complement()
        complement(Complete bipartite graph): Graph on 11 vertices

    TESTS:

    Prevent negative dimensions (:trac:`18530`)::

        sage: graphs.CompleteBipartiteGraph(-1,1)
        Traceback (most recent call last):
        ...
        ValueError: The arguments n1(=-1) and n2(=1) must be positive integers.
        sage: graphs.CompleteBipartiteGraph(1,-1)
        Traceback (most recent call last):
        ...
        ValueError: The arguments n1(=1) and n2(=-1) must be positive integers.
    """
    if n1<0 or n2<0:
        raise ValueError('The arguments n1(={}) and n2(={}) must be positive integers.'.format(n1,n2))

    pos_dict = {}
    c1 = 1 # scaling factor for top row
    c2 = 1 # scaling factor for bottom row
    c3 = 0 # pad to center if top row has 1 node
    c4 = 0 # pad to center if bottom row has 1 node
    if n1 > n2:
        if n2 == 1:
            c4 = (n1-1)/2
        else:
            c2 = ((n1-1)/(n2-1))
    elif n2 > n1:
        if n1 == 1:
            c3 = (n2-1)/2
        else:
            c1 = ((n2-1)/(n1-1))
    for i in range(n1):
        x = c1*i + c3
        y = 1
        pos_dict[i] = (x, y)
    for i in range(n1,n1+n2):
        x = c2*(i-n1) + c4
        y = 0
        pos_dict[i] = (x, y)

    G = Graph(n1+n2, pos=pos_dict, name="Complete bipartite graph")
    G.add_edges((i,j) for i in range(n1) for j in range(n1,n1+n2))
    return G
Example #29
0
def CompleteBipartiteGraph(n1, n2):
    """
    Returns a Complete Bipartite Graph sized n1+n2, with each of the
    nodes [0,(n1-1)] connected to each of the nodes [n1,(n2-1)] and
    vice versa.

    A Complete Bipartite Graph is a graph with its vertices partitioned
    into two groups, V1 and V2. Each v in V1 is connected to every v in
    V2, and vice versa.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, each complete
    bipartite graph will be displayed with the first n1 nodes on the
    top row (at y=1) from left to right. The remaining n2 nodes appear
    at y=0, also from left to right. The shorter row (partition with
    fewer nodes) is stretched to the same length as the longer row,
    unless the shorter row has 1 node; in which case it is centered.
    The x values in the plot are in domain [0,maxn1,n2].

    In the Complete Bipartite graph, there is a visual difference in
    using the spring-layout algorithm vs. the position dictionary used
    in this constructor. The position dictionary flattens the graph and
    separates the partitioned nodes, making it clear which nodes an
    edge is connected to. The Complete Bipartite graph plotted with the
    spring-layout algorithm tends to center the nodes in n1 (see
    spring_med in examples below), thus overlapping its nodes and
    edges, making it typically hard to decipher.

    Filling the position dictionary in advance adds O(n) to the
    constructor. Feel free to race the constructors below in the
    examples section. The much larger difference is the time added by
    the spring-layout algorithm when plotting. (Also shown in the
    example below). The spring model is typically described as
    `O(n^3)`, as appears to be the case in the NetworkX source
    code.

    EXAMPLES: Two ways of constructing the complete bipartite graph,
    using different layout algorithms::

        sage: import networkx
        sage: n = networkx.complete_bipartite_graph(389,157); spring_big = Graph(n)   # long time
        sage: posdict_big = graphs.CompleteBipartiteGraph(389,157)                    # long time

    Compare the plotting::

        sage: n = networkx.complete_bipartite_graph(11,17)
        sage: spring_med = Graph(n)
        sage: posdict_med = graphs.CompleteBipartiteGraph(11,17)

    Notice here how the spring-layout tends to center the nodes of n1

    ::

        sage: spring_med.show() # long time
        sage: posdict_med.show() # long time

    View many complete bipartite graphs with a Sage Graphics Array,
    with this constructor (i.e., the position dictionary filled)::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.CompleteBipartiteGraph(i+1,4)
        ....:     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

    We compare to plotting with the spring-layout algorithm::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     spr = networkx.complete_bipartite_graph(i+1,4)
        ....:     k = Graph(spr)
        ....:     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

    Trac ticket #12155::

        sage: graphs.CompleteBipartiteGraph(5,6).complement()
        complement(Complete bipartite graph): Graph on 11 vertices

    TESTS:

    Prevent negative dimensions (:trac:`18530`)::

        sage: graphs.CompleteBipartiteGraph(-1,1)
        Traceback (most recent call last):
        ...
        ValueError: The arguments n1(=-1) and n2(=1) must be positive integers.
        sage: graphs.CompleteBipartiteGraph(1,-1)
        Traceback (most recent call last):
        ...
        ValueError: The arguments n1(=1) and n2(=-1) must be positive integers.
    """
    if n1<0 or n2<0:
        raise ValueError('The arguments n1(={}) and n2(={}) must be positive integers.'.format(n1,n2))

    pos_dict = {}
    c1 = 1 # scaling factor for top row
    c2 = 1 # scaling factor for bottom row
    c3 = 0 # pad to center if top row has 1 node
    c4 = 0 # pad to center if bottom row has 1 node
    if n1 > n2:
        if n2 == 1:
            c4 = (n1-1)/2
        else:
            c2 = ((n1-1)/(n2-1))
    elif n2 > n1:
        if n1 == 1:
            c3 = (n2-1)/2
        else:
            c1 = ((n2-1)/(n1-1))
    for i in range(n1):
        x = c1*i + c3
        y = 1
        pos_dict[i] = (x,y)
    for i in range(n1+n2)[n1:]:
        x = c2*(i-n1) + c4
        y = 0
        pos_dict[i] = (x,y)

    G = Graph(n1+n2, pos=pos_dict, name="Complete bipartite graph")
    G.add_edges((i,j) for i in range(n1) for j in range(n1,n1+n2))
    return G
Example #30
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']

    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.gps_coordinates = gps_coordinates
    g.name("World Map")
    return g
Example #31
0
def root_graph(g, verbose=False):
    r"""
    Computes the root graph corresponding to the given graph

    See the documentation of :mod:`sage.graphs.line_graph` to know how it works.

    INPUT:

    - ``g`` -- a graph

    - ``verbose`` (boolean) -- display some information about what is happening
      inside of the algorithm.

    .. NOTE::

        It is best to use this code through
        :meth:`~sage.graphs.graph.Graph.is_line_graph`, which first checks that
        the graph is indeed a line graph, and deals with the disconnected
        case. But if you are sure of yourself, dig in !

    .. WARNING::

        * This code assumes that the graph is connected.

        * If the graph is *not* a line graph, this implementation will take a
          loooooong time to run. Its first step is to enumerate all maximal
          cliques, and that can take a while for general graphs. As soon as
          there is a way to iterate over maximal cliques without first building
          the (long) list of them this implementation can be updated, and will
          deal reasonably with non-line graphs too !

    TESTS:

    All connected graphs on 6 vertices::

        sage: from sage.graphs.line_graph import root_graph
        sage: def test(g):
        ...      gl = g.line_graph(labels = False)
        ...      d=root_graph(gl)
        sage: for i,g in enumerate(graphs(6)): # long time
        ...     if not g.is_connected():       # long time
        ...       continue                     # long time
        ...     test(g)                        # long time

    Non line-graphs::

        sage: root_graph(graphs.PetersenGraph())
        Traceback (most recent call last):
        ...
        ValueError: This graph is not a line graph !

    Small corner-cases::

        sage: from sage.graphs.line_graph import root_graph
        sage: root_graph(graphs.CompleteGraph(3))
        (Complete bipartite graph: Graph on 4 vertices, {0: (0, 1), 1: (0, 2), 2: (0, 3)})
        sage: root_graph(graphs.OctahedralGraph())
        (Complete graph: Graph on 4 vertices, {0: (0, 1), 1: (0, 2), 2: (0, 3), 3: (1, 2), 4: (1, 3), 5: (2, 3)})
        sage: root_graph(graphs.DiamondGraph())
        (Graph on 4 vertices, {0: (0, 3), 1: (0, 1), 2: (0, 2), 3: (1, 2)})
        sage: root_graph(graphs.WheelGraph(5))
        (Diamond Graph: Graph on 4 vertices, {0: (1, 2), 1: (0, 1), 2: (0, 2), 3: (2, 3), 4: (1, 3)})
    """
    from sage.graphs.digraph import DiGraph

    if isinstance(g, DiGraph):
        raise ValueError("g cannot be a DiGraph !")
    if g.has_multiple_edges():
        raise ValueError("g cannot have multiple edges !")
    if not g.is_connected():
        raise ValueError("g is not connected !")

    # Complete Graph ?
    if g.is_clique():
        from sage.graphs.generators.basic import CompleteBipartiteGraph
        return (CompleteBipartiteGraph(1, g.order()),
                {v: (0, 1 + i)
                 for i, v in enumerate(g)})

    # Diamond Graph ?
    elif g.order() == 4 and g.size() == 5:
        from sage.graphs.graph import Graph
        root = Graph([(0, 1), (1, 2), (2, 0), (0, 3)])
        return (root,
                g.is_isomorphic(root.line_graph(labels=False),
                                certify=True)[1])

    # Wheel on 5 vertices ?
    elif g.order() == 5 and g.size() == 8 and min(g.degree()) == 3:
        from sage.graphs.generators.basic import DiamondGraph
        root = DiamondGraph()
        return (root,
                g.is_isomorphic(root.line_graph(labels=False),
                                certify=True)[1])

    # Octahedron ?
    elif g.order() == 6 and g.size() == 12 and g.is_regular(k=4):
        from sage.graphs.generators.platonic_solids import OctahedralGraph
        if g.is_isomorphic(OctahedralGraph()):
            from sage.graphs.generators.basic import CompleteGraph
            root = CompleteGraph(4)
            return (root,
                    g.is_isomorphic(root.line_graph(labels=False),
                                    certify=True)[1])

    # From now on we can assume (thanks to Beineke) that no edge belongs to two
    # even triangles at once.

    error_message = ("It looks like there is a problem somewhere. You"
                     "found a bug here ! Please report it on sage-devel,"
                     "our google group !")

    # Better to work on integers... Everything takes more time
    # otherwise.
    G = g.relabel(inplace=False)

    # Dictionary of (pairs of) cliques, i.e. the two cliques
    # associated with each vertex.
    v_cliques = {v: [] for v in G}

    # All the even triangles we meet
    even_triangles = []

    # Here is THE "problem" of this implementation. Listing all maximal cliques
    # takes an exponential time on general graphs (while it is obviously
    # polynomial on line graphs). The problem is that this implementation cannot
    # be used to *recognise* line graphs for as long as cliques_maximal returns
    # a list and does not ITERATE on the maximal cliques : if there are too many
    # cliques in the graph, this implementation will notice it and answer that
    # the graph is not a line graph. If, on the other hand, the first thing it
    # does is enumerate ALL maximal cliques, then there is no way to say early
    # that the graph is not a line graph.
    #
    # If this cliques_maximal thing is replaced by an iterator that does not
    # build the list of all cliques before returning them, then this method is a
    # good recognition algorithm.

    for S in G.cliques_maximal():

        # Triangles... even or odd ?
        if len(S) == 3:

            # If a vertex of G has an odd number of neighbors among the vertices
            # of S, then the triangle is odd. We compute the list of such
            # vertices by taking the symmetric difference of the neighborhood of
            # our three vertices.
            #
            # Note that the elements of S do not appear in this set as they are
            # all seen exactly twice.

            odd_neighbors = set(G.neighbors(S[0]))
            odd_neighbors.symmetric_difference_update(G.neighbors(S[1]))
            odd_neighbors.symmetric_difference_update(G.neighbors(S[2]))

            # Even triangles
            if not odd_neighbors:
                even_triangles.append(tuple(S))
                continue

            # We manage odd triangles the same way we manage other cliques ...

        # We now associate the clique to all the vertices it contains.
        for v in S:
            if len(v_cliques[v]) == 2:
                raise ValueError("This graph is not a line graph !")
            v_cliques[v].append(tuple(S))

        if verbose:
            print("Added clique", S)

    # Deal with even triangles
    for u, v, w in even_triangles:

        # According to Beineke, we must go through all even triangles, and for
        # each triangle uvw consider its three pairs of adjacent verties uv, vw,
        # wu. For all pairs xy among those such that xy do not appear together
        # in any clique we have found so far, we add xy to the list of cliques
        # describing our covering.

        for x, y in [(u, v), (v, w), (w, u)]:

            # If edge xy does not appear in any of the cliques associated with y
            if all([not x in C for C in v_cliques[y]]):
                if len(v_cliques[y]) >= 2 or len(v_cliques[x]) >= 2:
                    raise ValueError("This graph is not a line graph !")

                v_cliques[x].append((x, y))
                v_cliques[y].append((x, y))

                if verbose:
                    print("Adding pair", (x, y),
                          "appearing in the even triangle", (u, v, w))

    # Deal with vertices contained in only one clique. All edges must be defined
    # by TWO endpoints, so we add a fake clique.
    for x, clique_list in v_cliques.iteritems():
        if len(clique_list) == 1:
            clique_list.append((x, ))

    # We now have all our cliques. Let's build the root graph to check that it
    # all fits !
    from sage.graphs.graph import Graph
    R = Graph()

    # Associates an integer to each clique
    relabel = {}

    # Associates to each vertex of G its pair of coordinates in R
    vertex_to_map = {}

    for v, L in v_cliques.iteritems():

        # Add cliques to relabel dictionary
        for S in L:
            if not S in relabel:
                relabel[S] = len(relabel)

        # The coordinates of edge v
        vertex_to_map[v] = relabel[L[0]], relabel[L[1]]

    if verbose:
        print("Final associations :")
        for v, L in v_cliques.iteritems():
            print(v, L)

    # We now build R
    R.add_edges(vertex_to_map.values())

    # Even if whatever is written above is complete nonsense, here we
    # make sure that we do not return gibberish. Is the line graph of
    # R isomorphic to the input ? If so, we return R, and the
    # isomorphism. Else, we panic and scream.
    #
    # It's actually "just to make sure twice". This can be removed later if it
    # turns out to be too costly.
    is_isom, isom = g.is_isomorphic(R.line_graph(labels=False), certify=True)

    if not is_isom:
        raise Exception(error_message)

    return R, isom
Example #32
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 #33
0
def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None):
    r"""
    Returns the Graph `NO^{\epsilon,\perp}_{m}(q)`

    Let the vectorspace of dimension `m` over `F_q` be
    endowed with a nondegenerate quadratic form `F`, of type ``sign`` for `m` even.

    * `m` even: assume further that `q=2` or `3`. Returns the graph of the
      points (in the underlying projective space) `x` satisfying `F(x)=1`, with adjacency
      given by orthogonality w.r.t. `F`. Parameter ``perp`` is ignored.

    * `m` odd: if ``perp`` is not ``None``, then we assume that `q=5` and
      return the graph of the points `x` satisfying `F(x)=\pm 1` if ``sign="+"``,
      respectively `F(x) \in \{2,3\}` if ``sign="-"``, with adjacency
      given by orthogonality w.r.t. `F` (cf. Sect 7.D of [BvL84]_).
      Otherwise return the graph
      of nongenerate hyperplanes of type ``sign``, adjacent whenever the intersection
      is degenerate (cf. Sect. 7.C of [BvL84]_).
      Note that for `q=2` one will get a complete graph.

    For more information, see Sect. 9.9 of [BH12]_ and [BvL84]_. Note that the `page of
    Andries Brouwer's website <http://www.win.tue.nl/~aeb/graphs/srghub.html>`_
    uses different notation.

    INPUT:

    - ``m``  - integer,  half the dimension of the underlying vectorspace

    - ``q``  - a power of a prime number, the size of the underlying field

    - ``sign`` -- ``"+"`` (default) or ``"-"``.

    EXAMPLES:

    `NO^-(4,2)` is isomorphic to Petersen graph::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g
        NO^-(4, 2): Graph on 10 vertices
        sage: g.is_strongly_regular(parameters=True)
        (10, 3, 0, 1)

    `NO^-(6,2)` and `NO^+(6,2)`::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'-')
        sage: g.is_strongly_regular(parameters=True)
        (36, 15, 6, 6)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g
        NO^+(6, 2): Graph on 28 vertices
        sage: g.is_strongly_regular(parameters=True)
        (28, 15, 6, 10)

    `NO^+(8,2)`::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(8,2,'+')
        sage: g.is_strongly_regular(parameters=True)
        (120, 63, 30, 36)

    Wilbrink's graphs for `q=5`::

        sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time
        (325, 60, 15, 10)
        sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time
        (300, 65, 10, 15)

    Wilbrink's graphs::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'+')
        sage: g.is_strongly_regular(parameters=True)
        (136, 75, 42, 40)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') 
        sage: g.is_strongly_regular(parameters=True)
        (120, 51, 18, 24)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time)
        NO^+(7, 4): Graph on 2080 vertices
        sage: g.is_strongly_regular(parameters=True) # not tested (long time)
        (2080, 1071, 558, 544)

    TESTS::

        sage: g=graphs.NonisotropicOrthogonalPolarGraph(4,2); g
        NO^+(4, 2): Graph on 6 vertices
        sage: graphs.NonisotropicOrthogonalPolarGraph(4,3,'-').is_strongly_regular(parameters=True)
        (15, 6, 1, 3)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g
        NO^-,perp(3, 5): Graph on 10 vertices
        sage: g.is_strongly_regular(parameters=True)
        (10, 3, 0, 1)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'+')   # long time
        sage: g.is_strongly_regular(parameters=True)               # long time
        (117, 36, 15, 9)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time
        NO^-(6, 3): Graph on 126 vertices
        sage: g.is_strongly_regular(parameters=True)                # long time
        (126, 45, 12, 18)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,5,'-')    # long time
        sage: g.is_strongly_regular(parameters=True)                # long time
        (300, 104, 28, 40)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,5,'+')    # long time
        sage: g.is_strongly_regular(parameters=True)                # long time
        (325, 144, 68, 60)
        sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,4,'+')
        Traceback (most recent call last):
        ...
        ValueError: for m even q must be 2 or 3 

    """
    from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph
    from sage.rings.arith import is_prime_power
    p, k = is_prime_power(q, get_data=True)
    if k == 0:
        raise ValueError('q must be a prime power')
    dec = ''
    if m % 2 == 0:
        if q in [2, 3]:
            G = _orthogonal_polar_graph(m, q, sign=sign, point_type=[1])
        else:
            raise ValueError("for m even q must be 2 or 3")
    elif not perp is None:
        if q == 5:
            G = _orthogonal_polar_graph(m, q, point_type=\
                [-1,1] if sign=='+' else [2,3] if sign=='-' else [])
            dec = ",perp"
        else:
            raise ValueError("for perp not None q must be 5")
    else:
        if not sign in ['+', '-']:
            raise ValueError("sign must be '+' or '-'")
        from sage.libs.gap.libgap import libgap
        g0 = libgap.GeneralOrthogonalGroup(m, q)
        g = libgap.Group(
            libgap.List(g0.GeneratorsOfGroup(), libgap.TransposedMat))
        F = libgap.GF(q)  # F_q
        W = libgap.FullRowSpace(F, m)  # F_q^m
        e = 1 if sign == '+' else -1
        n = (m - 1) / 2
        # we build (q^n(q^n+e)/2, (q^n-e)(q^(n-1)+e), 2(q^(2n-2)-1)+eq^(n-1)(q-1),
        #                                          2q^(n-1)(q^(n-1)+e))-srg
        # **use** v and k to select appropriate orbit and orbital
        nvert = (q**n) * (q**n + e) / 2  # v
        deg = (q**n - e) * (q**(n - 1) + e)  # k
        S=map(lambda x: libgap.Elements(libgap.Basis(x))[0], \
            libgap.Elements(libgap.Subspaces(W,1)))
        V = filter(lambda x: len(x) == nvert,
                   libgap.Orbits(g, S, libgap.OnLines))
        assert len(V) == 1
        V = V[0]
        gp = libgap.Action(g, V, libgap.OnLines)  # make a permutation group
        h = libgap.Stabilizer(gp, 1)
        Vh = filter(lambda x: len(x) == deg,
                    libgap.Orbits(h, libgap.Orbit(gp, 1)))
        assert len(Vh) == 1
        Vh = Vh[0][0]
        L = libgap.Orbit(gp, [1, Vh], libgap.OnSets)
        G = Graph()
        G.add_edges(L)
    G.name("NO^" + sign + dec + str((m, q)))
    return G
Example #34
0
    return G, isosig_to_link_dict


mutation_graph = Graph()
isosig_dict = {}
i = 0
for link in links:
    print('%d / %d' % (i, len(links)))
    i += 1
    try:
        isosig = link.isometry_signature(of_link=True)
    except:
        print('isosig failed')
        continue
    if isosig in mutation_graph:
        continue
    G, d = mutant_neighborhood_graph(link.link())
    print(len(G.edges()))
    mutation_graph.add_edges(G.edges())
    for iso in d:
        isosig_dict[iso] = d[iso]

f = open('mutation_graph_knots12.txt', 'w')
f.write(str(mutation_graph.edges()))
f.close()

g = open('isosig_to_PD_dict12.txt', 'w')
g.write(str(isosig_dict))
g.close()
Example #35
0
def root_graph(g, verbose = False):
    r"""
    Computes the root graph corresponding to the given graph

    See the documentation of :mod:`sage.graphs.line_graph` to know how it works.

    INPUT:

    - ``g`` -- a graph

    - ``verbose`` (boolean) -- display some information about what is happening
      inside of the algorithm.

    .. NOTE::

        It is best to use this code through
        :meth:`~sage.graphs.graph.Graph.is_line_graph`, which first checks that
        the graph is indeed a line graph, and deals with the disconnected
        case. But if you are sure of yourself, dig in !

    .. WARNING::

        * This code assumes that the graph is connected.

        * If the graph is *not* a line graph, this implementation will take a
          loooooong time to run. Its first step is to enumerate all maximal
          cliques, and that can take a while for general graphs. As soon as
          there is a way to iterate over maximal cliques without first building
          the (long) list of them this implementation can be updated, and will
          deal reasonably with non-line graphs too !

    TESTS:

    All connected graphs on 6 vertices::

        sage: from sage.graphs.line_graph import root_graph
        sage: def test(g):
        ....:    gl = g.line_graph(labels = False)
        ....:    d=root_graph(gl)
        sage: for i,g in enumerate(graphs(6)): # long time
        ....:   if not g.is_connected():       # long time
        ....:     continue                     # long time
        ....:   test(g)                        # long time

    Non line-graphs::

        sage: root_graph(graphs.PetersenGraph())
        Traceback (most recent call last):
        ...
        ValueError: This graph is not a line graph !

    Small corner-cases::

        sage: from sage.graphs.line_graph import root_graph
        sage: root_graph(graphs.CompleteGraph(3))
        (Complete bipartite graph: Graph on 4 vertices, {0: (0, 1), 1: (0, 2), 2: (0, 3)})
        sage: root_graph(graphs.OctahedralGraph())
        (Complete graph: Graph on 4 vertices, {0: (0, 1), 1: (0, 2), 2: (0, 3), 3: (1, 2), 4: (1, 3), 5: (2, 3)})
        sage: root_graph(graphs.DiamondGraph())
        (Graph on 4 vertices, {0: (0, 3), 1: (0, 1), 2: (0, 2), 3: (1, 2)})
        sage: root_graph(graphs.WheelGraph(5))
        (Diamond Graph: Graph on 4 vertices, {0: (1, 2), 1: (0, 1), 2: (0, 2), 3: (2, 3), 4: (1, 3)})
    """
    from sage.graphs.digraph import DiGraph

    if isinstance(g, DiGraph):
        raise ValueError("g cannot be a DiGraph !")
    if g.has_multiple_edges():
        raise ValueError("g cannot have multiple edges !")
    if not g.is_connected():
        raise ValueError("g is not connected !")

    # Complete Graph ?
    if g.is_clique():
        from sage.graphs.generators.basic import CompleteBipartiteGraph
        return (CompleteBipartiteGraph(1,g.order()),
                {v : (0,1+i) for i,v in enumerate(g)})

    # Diamond Graph ?
    elif g.order() == 4 and g.size() == 5:
        from sage.graphs.graph import Graph
        root = Graph([(0,1),(1,2),(2,0),(0,3)])
        return (root,
                g.is_isomorphic(root.line_graph(labels = False), certificate = True)[1])

    # Wheel on 5 vertices ?
    elif g.order() == 5 and g.size() == 8 and min(g.degree()) == 3:
        from sage.graphs.generators.basic import DiamondGraph
        root = DiamondGraph()
        return (root,
                g.is_isomorphic(root.line_graph(labels = False), certificate = True)[1])

    # Octahedron ?
    elif g.order() == 6 and g.size() == 12 and g.is_regular(k=4):
        from sage.graphs.generators.platonic_solids import OctahedralGraph
        if g.is_isomorphic(OctahedralGraph()):
            from sage.graphs.generators.basic import CompleteGraph
            root = CompleteGraph(4)
            return (root,
                    g.is_isomorphic(root.line_graph(labels = False), certificate = True)[1])

    # From now on we can assume (thanks to Beineke) that no edge belongs to two
    # even triangles at once.

    error_message = ("It looks like there is a problem somewhere. You"
                     "found a bug here ! Please report it on sage-devel,"
                     "our google group !")

    # Better to work on integers... Everything takes more time
    # otherwise.
    G = g.relabel(inplace = False)

    # Dictionary of (pairs of) cliques, i.e. the two cliques
    # associated with each vertex.
    v_cliques = {v:[] for v in G}

    # All the even triangles we meet
    even_triangles = []


    # Here is THE "problem" of this implementation. Listing all maximal cliques
    # takes an exponential time on general graphs (while it is obviously
    # polynomial on line graphs). The problem is that this implementation cannot
    # be used to *recognise* line graphs for as long as cliques_maximal returns
    # a list and does not ITERATE on the maximal cliques : if there are too many
    # cliques in the graph, this implementation will notice it and answer that
    # the graph is not a line graph. If, on the other hand, the first thing it
    # does is enumerate ALL maximal cliques, then there is no way to say early
    # that the graph is not a line graph.
    #
    # If this cliques_maximal thing is replaced by an iterator that does not
    # build the list of all cliques before returning them, then this method is a
    # good recognition algorithm.

    for S in G.cliques_maximal():

        # Triangles... even or odd ?
        if len(S) == 3:

            # If a vertex of G has an odd number of neighbors among the vertices
            # of S, then the triangle is odd. We compute the list of such
            # vertices by taking the symmetric difference of the neighborhood of
            # our three vertices.
            #
            # Note that the elements of S do not appear in this set as they are
            # all seen exactly twice.

            odd_neighbors = set(G.neighbors(S[0]))
            odd_neighbors.symmetric_difference_update(G.neighbors(S[1]))
            odd_neighbors.symmetric_difference_update(G.neighbors(S[2]))

            # Even triangles
            if not odd_neighbors:
                even_triangles.append(tuple(S))
                continue

            # We manage odd triangles the same way we manage other cliques ...

        # We now associate the clique to all the vertices it contains.
        for v in S:
            if len(v_cliques[v]) == 2:
                raise ValueError("This graph is not a line graph !")
            v_cliques[v].append(tuple(S))

        if verbose:
            print("Added clique", S)

    # Deal with even triangles
    for u,v,w in even_triangles:

        # According to Beineke, we must go through all even triangles, and for
        # each triangle uvw consider its three pairs of adjacent verties uv, vw,
        # wu. For all pairs xy among those such that xy do not appear together
        # in any clique we have found so far, we add xy to the list of cliques
        # describing our covering.

        for x,y in [(u,v), (v,w), (w,u)]:

            # If edge xy does not appear in any of the cliques associated with y
            if all([not x in C for C in v_cliques[y]]):
                if len(v_cliques[y]) >= 2 or len(v_cliques[x]) >= 2:
                    raise ValueError("This graph is not a line graph !")

                v_cliques[x].append((x,y))
                v_cliques[y].append((x,y))

                if verbose:
                    print("Adding pair", (x, y),
                          "appearing in the even triangle", (u, v, w))

    # Deal with vertices contained in only one clique. All edges must be defined
    # by TWO endpoints, so we add a fake clique.
    for x, clique_list in iteritems(v_cliques):
        if len(clique_list) == 1:
            clique_list.append((x,))

    # We now have all our cliques. Let's build the root graph to check that it
    # all fits !
    from sage.graphs.graph import Graph
    R = Graph()

    # Associates an integer to each clique
    relabel = {}

    # Associates to each vertex of G its pair of coordinates in R
    vertex_to_map = {}

    for v, L in iteritems(v_cliques):

        # Add cliques to relabel dictionary
        for S in L:
            if not S in relabel:
                relabel[S] = len(relabel)

        # The coordinates of edge v
        vertex_to_map[v] = relabel[L[0]], relabel[L[1]]

    if verbose:
        print("Final associations :")
        for v, L in iteritems(v_cliques):
            print(v, L)

    # We now build R
    R.add_edges(vertex_to_map.values())

    # Even if whatever is written above is complete nonsense, here we
    # make sure that we do not return gibberish. Is the line graph of
    # R isomorphic to the input ? If so, we return R, and the
    # isomorphism. Else, we panic and scream.
    #
    # It's actually "just to make sure twice". This can be removed later if it
    # turns out to be too costly.
    is_isom, isom = g.is_isomorphic(R.line_graph(labels = False), certificate = True)

    if not is_isom:
        raise Exception(error_message)

    return R, isom
Example #36
0
def NonisotropicUnitaryPolarGraph(m, q):
    r"""
    Returns the Graph `NU(m,q)`.

    Returns the graph on nonisotropic, with respect to a nondegenerate
    Hermitean form, points of the `(m-1)`-dimensional projective space over `F_q`,
    with points adjacent whenever they lie on a tangent (to the set of isotropic points)
    line.
    For more information, see Sect. 9.9 of [BH12]_ and series C14 in [Hu75]_.

    INPUT:

    - ``m,q`` (integers) -- `q` must be a prime power.

    EXAMPLES::

        sage: g=graphs.NonisotropicUnitaryPolarGraph(5,2); g
        NU(5, 2): Graph on 176 vertices
        sage: g.is_strongly_regular(parameters=True)
        (176, 135, 102, 108)

    TESTS::

        sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True)
        (40, 27, 18, 18)
        sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time
        (540, 224, 88, 96)
        sage: graphs.NonisotropicUnitaryPolarGraph(6,6)
        Traceback (most recent call last):
        ...
        ValueError: q must be a prime power

    REFERENCE:

    .. [Hu75] \X. L. Hubaut.
      Strongly regular graphs.
      Disc. Math. 13(1975), pp 357--381.
      http://dx.doi.org/10.1016/0012-365X(75)90057-6
    """
    p, k = is_prime_power(q,get_data=True)
    if k==0:
       raise ValueError('q must be a prime power')
    from sage.libs.gap.libgap import libgap
    from itertools import combinations
    F=libgap.GF(q**2)  # F_{q^2}
    W=libgap.FullRowSpace(F, m)  # F_{q^2}^m
    B=libgap.Elements(libgap.Basis(W))      # the standard basis of W
    if m % 2 != 0:
        point = B[(m-1)/2]
    else:
        if p==2:
            point = B[m/2] + F.PrimitiveRoot()*B[(m-2)/2]
        else:
            point = B[(m-2)/2] + B[m/2]
    g = libgap.GeneralUnitaryGroup(m,q)
    V = libgap.Orbit(g,point,libgap.OnLines) # orbit on nonisotropic points
    gp = libgap.Action(g,V,libgap.OnLines)  # make a permutation group

    s = libgap.Subspace(W,[point, point+B[0]]) # a tangent line on point

    # and the points there
    sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))]
    h = libgap.Set(map(lambda x: libgap.Position(V, x), libgap.Intersection(V,sp))) # indices
    L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines
    G = Graph()
    for x in L: # every pair of points in the subspace is adjacent to each other in G
        G.add_edges(combinations(x, 2))
    G.relabel()
    G.name("NU" + str((m, q)))
    return G
Example #37
0
def CompleteGraph(n):
    r"""
    Return a complete graph on `n` nodes.

    A Complete Graph is a graph in which all nodes are connected to all
    other nodes.

    PLOTTING: Upon construction, the position dictionary is filled to
    override the spring-layout algorithm. By convention, each complete
    graph will be displayed with the first (0) node at the top, with
    the rest following in a counterclockwise manner.

    In the complete graph, there is a big difference visually in using
    the spring-layout algorithm vs. the position dictionary used in
    this constructor. The position dictionary flattens the graph,
    making it clear which nodes an edge is connected to. But the
    complete graph offers a good example of how the spring-layout
    works. The edges push outward (everything is connected), causing
    the graph to appear as a 3-dimensional pointy ball. (See examples
    below).

    EXAMPLES:

    We view many Complete graphs with a Sage Graphics Array, first with this
    constructor (i.e., the position dictionary filled)::

        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     k = graphs.CompleteGraph(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 = graphics_array(j)
        sage: G.show()  # long time

    We compare to plotting with the spring-layout algorithm::

        sage: import networkx
        sage: g = []
        sage: j = []
        sage: for i in range(9):
        ....:     spr = networkx.complete_graph(i+3)
        ....:     k = Graph(spr)
        ....:     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 = graphics_array(j)
        sage: G.show()  # long time

    Compare the constructors (results will vary)::

        sage: import networkx
        sage: t = cputime()
        sage: n = networkx.complete_graph(389); spring389 = Graph(n)
        sage: cputime(t)  # random
        0.59203700000000126
        sage: t = cputime()
        sage: posdict389 = graphs.CompleteGraph(389)
        sage: cputime(t)  # random
        0.6680419999999998

    We compare plotting::

        sage: import networkx
        sage: n = networkx.complete_graph(23)
        sage: spring23 = Graph(n)
        sage: posdict23 = graphs.CompleteGraph(23)
        sage: spring23.show()  # long time
        sage: posdict23.show()  # long time
    """
    G = Graph(n, name="Complete graph")
    if n == 1:
        G.set_pos({0: (0, 0)})
    else:
        G._circle_embedding(list(range(n)), angle=pi/2)
    G.add_edges(((i,j) for i in range(n) for j in range(i+1,n)))
    return G
Example #38
0
def OrthogonalArrayBlockGraph(k, n, OA=None):
    r"""
    Return the graph of an `OA(k,n)`.

    The intersection graph of the blocks of a transversal design with parameters
    `(k,n)`, or `TD(k,n)` for short, is a strongly regular graph (unless it is a
    complete graph). Its parameters `(v,k',\lambda,\mu)` are determined by the
    parameters `k,n` via:

    .. MATH::

        v=n^2, k'=k(n-1), \lambda=(k-1)(k-2)+n-2, \mu=k(k-1)

    As transversal designs and orthogonal arrays (OA for short) are equivalent
    objects, this graph can also be built from the blocks of an `OA(k,n)`, two
    of them being adjacent if one of their coordinates match.

    For more information on these graphs, see `Andries Brouwer's page
    on Orthogonal Array graphs <https://www.win.tue.nl/~aeb/graphs/OA.html>`_.

    .. WARNING::

        - Brouwer's website uses the notation `OA(n,k)` instead of `OA(k,n)`

        - For given parameters `k` and `n` there can be many `OA(k,n)` : the
          graphs returned are not uniquely defined by their parameters (see the
          examples below).

        - If the function is called only with the parameter ``k`` and ``n`` the
          results might be different with two versions of Sage, or even worse :
          some could not be available anymore.

    .. SEEALSO::

        :mod:`sage.combinat.designs.orthogonal_arrays`

    INPUT:

    - ``k,n`` (integers)

    - ``OA`` -- An orthogonal array. If set to ``None`` (default) then
      :func:`~sage.combinat.designs.orthogonal_arrays.orthogonal_array` is
      called to compute an `OA(k,n)`.

    EXAMPLES::

        sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G
        OA(5,5): Graph on 25 vertices
        sage: G.is_strongly_regular(parameters=True)
        (25, 20, 15, 20)
        sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G
        OA(4,10): Graph on 100 vertices
        sage: G.is_strongly_regular(parameters=True)
        (100, 36, 14, 12)

    Two graphs built from different orthogonal arrays are also different::

        sage: k=4;n=10
        sage: OAa = designs.orthogonal_arrays.build(k,n)
        sage: OAb = [[(x+1)%n for x in R] for R in OAa]
        sage: set(map(tuple,OAa)) == set(map(tuple,OAb))
        False
        sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa)
        sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb)
        sage: Ga == Gb
        False

    As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are
    isomorphic::

        sage: Ga.is_isomorphic(Gb)
        True

    But there are examples of `OA(k,n)` for which the resulting graphs are not
    isomorphic::

        sage: oa0 = [[0, 0, 1], [0, 1, 3], [0, 2, 0], [0, 3, 2],
        ....:        [1, 0, 3], [1, 1, 1], [1, 2, 2], [1, 3, 0],
        ....:        [2, 0, 0], [2, 1, 2], [2, 2, 1], [2, 3, 3],
        ....:        [3, 0, 2], [3, 1, 0], [3, 2, 3], [3, 3, 1]]
        sage: oa1 = [[0, 0, 1], [0, 1, 0], [0, 2, 3], [0, 3, 2],
        ....:        [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1],
        ....:        [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3],
        ....:        [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]]
        sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0)
        sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1)
        sage: g0.is_isomorphic(g1)
        False

    But nevertheless isospectral::

        sage: g0.spectrum()
        [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]
        sage: g1.spectrum()
        [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3]

    Note that the graph ``g0`` is actually isomorphic to the affine polar graph
    `VO^+(4,2)`::

        sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0)
        True

    TESTS::

        sage: G = graphs.OrthogonalArrayBlockGraph(4,6)
        Traceback (most recent call last):
        ...
        NotImplementedError: I don't know how to build an OA(4,6)!
        sage: G = graphs.OrthogonalArrayBlockGraph(8,2)
        Traceback (most recent call last):
        ...
        ValueError: There is no OA(8,2). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) !
    """
    if n > 1 and k >= n + 2:
        raise ValueError(
            "There is no OA({},{}). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) !"
            .format(k, n))

    from itertools import combinations

    if OA is None:
        from sage.combinat.designs.orthogonal_arrays import orthogonal_array
        OA = orthogonal_array(k, n)
    else:
        assert len(OA) == n**2
        assert n == 0 or k == len(OA[0])

    OA = map(tuple, OA)

    d = [[[] for j in range(n)] for i in range(k)]
    for R in OA:
        for i, x in enumerate(R):
            d[i][x].append(R)

    g = Graph()
    for l in d:
        for ll in l:
            g.add_edges(combinations(ll, 2))

    g.name("OA({},{})".format(k, n))

    return g
Example #39
0
def NonisotropicUnitaryPolarGraph(m, q):
    r"""
    Returns the Graph `NU(m,q)`.

    Returns the graph on nonisotropic, with respect to a nondegenerate
    Hermitean form, points of the `(m-1)`-dimensional projective space over `F_q`,
    with points adjacent whenever they lie on a tangent (to the set of isotropic points)
    line.
    For more information, see Sect. 9.9 of [BH12]_ and series C14 in [Hu75]_.

    INPUT:

    - ``m,q`` (integers) -- `q` must be a prime power.

    EXAMPLES::

        sage: g=graphs.NonisotropicUnitaryPolarGraph(5,2); g
        NU(5, 2): Graph on 176 vertices
        sage: g.is_strongly_regular(parameters=True)
        (176, 135, 102, 108)

    TESTS::

        sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True)
        (40, 27, 18, 18)
        sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time
        (540, 224, 88, 96)
        sage: graphs.NonisotropicUnitaryPolarGraph(6,6)
        Traceback (most recent call last):
        ...
        ValueError: q must be a prime power

    REFERENCE:

    .. [Hu75] X. L. Hubaut.
      Strongly regular graphs.
      Disc. Math. 13(1975), pp 357--381.
      http://dx.doi.org/10.1016/0012-365X(75)90057-6
    """
    from sage.rings.arith import is_prime_power
    p, k = is_prime_power(q, get_data=True)
    if k == 0:
        raise ValueError('q must be a prime power')
    from sage.libs.gap.libgap import libgap
    from itertools import combinations
    F = libgap.GF(q**2)  # F_{q^2}
    W = libgap.FullRowSpace(F, m)  # F_{q^2}^m
    B = libgap.Elements(libgap.Basis(W))  # the standard basis of W
    if m % 2 != 0:
        point = B[(m - 1) / 2]
    else:
        if p == 2:
            point = B[m / 2] + F.PrimitiveRoot() * B[(m - 2) / 2]
        else:
            point = B[(m - 2) / 2] + B[m / 2]
    g = libgap.GeneralUnitaryGroup(m, q)
    V = libgap.Orbit(g, point, libgap.OnLines)  # orbit on nonisotropic points
    gp = libgap.Action(g, V, libgap.OnLines)  # make a permutation group

    s = libgap.Subspace(W, [point, point + B[0]])  # a tangent line on point

    # and the points there
    sp = [
        libgap.Elements(libgap.Basis(x))[0]
        for x in libgap.Elements(s.Subspaces(1))
    ]
    h = libgap.Set(
        map(lambda x: libgap.Position(V, x),
            libgap.Intersection(V, sp)))  # indices
    L = libgap.Orbit(gp, h, libgap.OnSets)  # orbit on the tangent lines
    G = Graph()
    for x in L:  # every pair of points in the subspace is adjacent to each other in G
        G.add_edges(combinations(x, 2))
    G.relabel()
    G.name("NU" + str((m, q)))
    return G