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())
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 []
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)
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
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
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
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
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
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)
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
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
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
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
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
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
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
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
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
def apply(solver, model, structures): g = structures[0] vertices = solver.get_objects_in_model(model, g, g.internal_graph.vertices()) dims = int(math.log(g.order, 2)) #print(vertices) #print(dims) edges = solver.get_objects_in_model(model, g, g.internal_graph.edges(labels=False)) #print(edges) #create temp graph t = Graph() t.add_vertices(vertices) t.add_edges(edges) for i in range(g.order/2): antipod = g.order - 1 - i #print(i, antipod) if i in vertices and antipod in vertices: path = t.shortest_path(i, antipod) if path: #print(path) return (True, [g, path]) print("COUNTER") return (False, [])
def 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
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
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
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
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
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
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
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
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
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
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
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
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
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()
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
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
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
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
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