def coxeter_graph(self): """ Return the Coxeter graph of ``self``. EXAMPLES:: sage: W = CoxeterGroup(['H',3], implementation="reflection") sage: G = W.coxeter_graph(); G Graph on 3 vertices sage: G.edges() [(1, 2, None), (2, 3, 5)] sage: CoxeterGroup(G) is W True sage: G = Graph([(0, 1, 3), (1, 2, oo)]) sage: W = CoxeterGroup(G) sage: W.coxeter_graph() == G True sage: CoxeterGroup(W.coxeter_graph()) is W True """ G = Graph() G.add_vertices(self.index_set()) for i, row in enumerate(self._matrix.rows()): for j, val in enumerate(row[i + 1:]): if val == 3: G.add_edge(self._index_set[i], self._index_set[i + 1 + j]) elif val > 3: G.add_edge(self._index_set[i], self._index_set[i + 1 + j], val) elif val == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} G.add_edge(self._index_set[i], self._index_set[i + 1 + j], infinity) return G
def coxeter_diagram(self): """ Return the Coxeter diagram for ``self``. EXAMPLES:: sage: cd = CartanType("A2xB2xF4").coxeter_diagram() sage: cd Graph on 8 vertices sage: cd.edges() [(1, 2, 3), (3, 4, 4), (5, 6, 3), (6, 7, 4), (7, 8, 3)] sage: CartanType("F4xA2").coxeter_diagram().edges() [(1, 2, 3), (2, 3, 4), (3, 4, 3), (5, 6, 3)] sage: cd = CartanType("A1xH3").coxeter_diagram(); cd Graph on 4 vertices sage: cd.edges() [(2, 3, 3), (3, 4, 5)] """ from sage.graphs.graph import Graph relabelling = self._index_relabelling g = Graph(multiedges=False) g.add_vertices(self.index_set()) for i, t in enumerate(self._types): for [e1, e2, l] in t.coxeter_diagram().edges(): g.add_edge(relabelling[i, e1], relabelling[i, e2], label=l) return g
def coxeter_diagram(self): """ Return the Coxeter diagram for ``self``. EXAMPLES:: sage: cd = CartanType("A2xB2xF4").coxeter_diagram() sage: cd Graph on 8 vertices sage: cd.edges() [(1, 2, 3), (3, 4, 4), (5, 6, 3), (6, 7, 4), (7, 8, 3)] sage: CartanType("F4xA2").coxeter_diagram().edges() [(1, 2, 3), (2, 3, 4), (3, 4, 3), (5, 6, 3)] sage: cd = CartanType("A1xH3").coxeter_diagram(); cd Graph on 4 vertices sage: cd.edges() [(2, 3, 3), (3, 4, 5)] """ from sage.graphs.graph import Graph relabelling = self._index_relabelling g = Graph(multiedges=False) g.add_vertices(self.index_set()) for i,t in enumerate(self._types): for [e1, e2, l] in t.coxeter_diagram().edges(): g.add_edge(relabelling[i,e1], relabelling[i,e2], label=l) return g
def coxeter_graph(self): """ Return the Coxeter graph of ``self``. EXAMPLES:: sage: C = CoxeterMatrix(['A',3]) sage: C.coxeter_graph() Graph on 3 vertices sage: C = CoxeterMatrix([['A',3],['A',1]]) sage: C.coxeter_graph() Graph on 4 vertices """ n = self.rank() I = self.index_set() val = lambda x: infinity if x == -1 else x G = Graph( [ (I[i], I[j], val((self._matrix)[i, j])) for i in range(n) for j in range(i) if self._matrix[i, j] not in [1, 2] ] ) G.add_vertices(I) return G.copy(immutable=True)
def coxeter_graph(self): """ Return the Coxeter graph of ``self``. EXAMPLES:: sage: C = CoxeterMatrix(['A',3]) sage: C.coxeter_graph() Graph on 3 vertices sage: C = CoxeterMatrix([['A',3],['A',1]]) sage: C.coxeter_graph() Graph on 4 vertices """ n = self.rank() I = self.index_set() def val(x): return infinity if x == -1 else x G = Graph([(I[i], I[j], val((self._matrix)[i, j])) for i in range(n) for j in range(i) if self._matrix[i, j] not in [1, 2]], format='list_of_edges') G.add_vertices(I) return G.copy(immutable=True)
def to_bipartite_graph(self, with_partition=False): r""" Returns the associated bipartite graph INPUT: - with_partition -- boolean (default: False) OUTPUT: - a graph or a pair (graph, partition) EXAMPLES:: sage: H = designs.steiner_triple_system(7).blocks() sage: H = Hypergraph(H) sage: g = H.to_bipartite_graph(); g Graph on 14 vertices sage: g.is_regular() True """ from sage.graphs.graph import Graph G = Graph() domain = list(self.domain()) G.add_vertices(domain) for s in self._sets: for i in s: G.add_edge(s, i) if with_partition: return (G, [domain, list(self._sets)]) else: return G
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 coxeter_graph(self): """ Return the Coxeter graph of ``self``. EXAMPLES:: sage: W = CoxeterGroup(['H',3], implementation="reflection") sage: G = W.coxeter_graph(); G Graph on 3 vertices sage: G.edges() [(1, 2, None), (2, 3, 5)] sage: CoxeterGroup(G) is W True sage: G = Graph([(0, 1, 3), (1, 2, oo)]) sage: W = CoxeterGroup(G) sage: W.coxeter_graph() == G True sage: CoxeterGroup(W.coxeter_graph()) is W True """ G = Graph() G.add_vertices(self.index_set()) for i, row in enumerate(self._matrix.rows()): for j, val in enumerate(row[i + 1 :]): if val == 3: G.add_edge(self._index_set[i], self._index_set[i + 1 + j]) elif val > 3: G.add_edge(self._index_set[i], self._index_set[i + 1 + j], val) elif val == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} G.add_edge(self._index_set[i], self._index_set[i + 1 + j], infinity) return G
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. EXAMPLES:: sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)]) Intersection Graph: Graph on 3 vertices TESTS:: sage: graphs.IntersectionGraph([(1,2,[1])]) Traceback (most recent call last): ... TypeError: The elements of S must be hashable, and this one is not: (1, 2, [1]) """ from itertools import combinations for s in S: try: hash(s) except TypeError: raise TypeError( "The elements of S must be hashable, and this one is not: {}". format(s)) ground_set_to_sets = {} for s in S: for x in s: if x not in ground_set_to_sets: ground_set_to_sets[x] = [] ground_set_to_sets[x].append(s) g = Graph(name="Intersection Graph") g.add_vertices(S) for clique in itervalues(ground_set_to_sets): g.add_clique(set(clique)) return g
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 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 from_cells(cls, cells={}): r""" From a dictionary { coordinates pair : None } return a graph with one vertex for every coordinates pair TESTS :: sage: from sage.graphs.generators.families import AztecDiamondGraph sage: from sage_widget_adapters.graphs.graph_grid_view_adapter import GraphGridViewAdapter sage: GraphGridViewAdapter.from_cells({(0, 0): None, (0, 1): None, (1, 0): None, (1, 1): None, (2, 0): None, (2, 1): None}) Graph on 6 vertices """ g = Graph() g.add_vertices(list(cells.keys())) return cls.objclass(g)
def apply(solver, model, structures): g = structures[0] vertices = solver.get_objects_in_model(model, g, g.internal_graph.vertices()) dims = int(math.log(g.order, 2)) #print(vertices) #print(dims) edges = solver.get_objects_in_model(model, g, g.internal_graph.edges(labels=False)) #print(edges) #create temp graph t = Graph() t.add_vertices(vertices) t.add_edges(edges) for i in range(g.order/2): antipod = g.order - 1 - i #print(i, antipod) if i in vertices and antipod in vertices: path = t.shortest_path(i, antipod) if path: #print(path) return (True, [g, path]) print("COUNTER") return (False, [])
def connection_graph(self): """ Return the graph which has the variables of this system as vertices and edges between two variables if they appear in the same polynomial. EXAMPLE:: sage: B.<x,y,z> = BooleanPolynomialRing() sage: F = Sequence([x*y + y + 1, z + 1]) sage: F.connection_graph() Graph on 3 vertices """ V = sorted(self.variables()) from sage.graphs.graph import Graph g = Graph() g.add_vertices(sorted(V)) for f in self: v = f.variables() a,tail = v[0],v[1:] for b in tail: g.add_edge((a,b)) return g
def decode_fgraph_string(s): data = s.split("_") n = decode_6bits(data[0]) f = [decode_6bits(data[1][i]) for i in range(n)] G = Graph() G.add_vertices(range(n)) # read in the adjacency matrix cur = 0 val = decode_6bits(data[2][cur]) mask = 1 << 5 # start with the high bit for j in range( n): # adj matrix is bit packed in colex order, as in graph6 format for i in range(j): if val & mask != 0: # test whether that bit is nonzero G.add_edge(i, j) mask >>= 1 if mask == 0: # mask has become 0 cur += 1 val = decode_6bits(data[2][cur]) mask = 1 << 5 return G, f
def PermutationGraph(second_permutation, first_permutation = None): r""" Build a permutation graph from one permutation or from two lists. Definition: If `\sigma` is a permutation of `\{ 1, 2, \ldots, n \}`, then the permutation graph of `\sigma` is the graph on vertex set `\{ 1, 2, \ldots, n \}` in which two vertices `i` and `j` satisfying `i < j` are connected by an edge if and only if `\sigma^{-1}(i) > \sigma^{-1}(j)`. A visual way to construct this graph is as follows: Take two horizontal lines in the euclidean plane, and mark points `1, ..., n` from left to right on the first of them. On the second one, still from left to right, mark `n` points `\sigma(1), \sigma(2), \ldots, \sigma(n)`. Now, link by a segment the two points marked with `1`, then link together the points marked with `2`, and so on. The permutation graph of `\sigma` is the intersection graph of those segments: there exists a vertex in this graph for each element from `1` to `n`, two vertices `i, j` being adjacent if the segments `i` and `j` cross each other. The set of edges of the permutation graph can thus be identified with the set of inversions of the inverse of the given permutation `\sigma`. A more general notion of permutation graph can be defined as follows: If `S` is a set, and `(a_1, a_2, \ldots, a_n)` and `(b_1, b_2, \ldots, b_n)` are two lists of elements of `S`, each of which lists contains every element of `S` exactly once, then the permutation graph defined by these two lists is the graph on the vertex set `S` in which two vertices `i` and `j` are connected by an edge if and only if the order in which these vertices appear in the list `(a_1, a_2, \ldots, a_n)` is the opposite of the order in which they appear in the list `(b_1, b_2, \ldots, b_n)`. When `(a_1, a_2, \ldots, a_n) = (1, 2, \ldots, n)`, this graph is the permutation graph of the permutation `(b_1, b_2, \ldots, b_n) \in S_n`. Notice that `S` does not have to be a set of integers here, but can be a set of strings, tuples, or anything else. We can still use the above visual description to construct the permutation graph, but now we have to mark points `a_1, a_2, \ldots, a_n` from left to right on the first horizontal line and points `b_1, b_2, \ldots, b_n` from left to right on the second horizontal line. INPUT: - ``second_permutation`` -- the unique permutation/list defining the graph, or the second of the two (if the graph is to be built from two permutations/lists). - ``first_permutation`` (optional) -- the first of the two permutations/lists from which the graph should be built, if it is to be built from two permutations/lists. When ``first_permutation is None`` (default), it is set to be equal to ``sorted(second_permutation)``, which yields the expected ordering when the elements of the graph are integers. .. SEEALSO: - Recognition of Permutation graphs in the :mod:`comparability module <sage.graphs.comparability>`. - Drawings of permutation graphs as intersection graphs of segments is possible through the :meth:`~sage.combinat.permutation.Permutation.show` method of :class:`~sage.combinat.permutation.Permutation` objects. The correct argument to use in this case is ``show(representation = "braid")``. - :meth:`~sage.combinat.permutation.Permutation.inversions` EXAMPLES:: sage: p = Permutations(5).random_element() sage: PG = graphs.PermutationGraph(p) sage: edges = PG.edges(labels=False) sage: set(edges) == set(p.inverse().inversions()) True sage: PG = graphs.PermutationGraph([3,4,5,1,2]) sage: sorted(PG.edges()) [(1, 3, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 4, None), (2, 5, None)] sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3]) sage: sorted(PG.edges()) [(1, 3, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None), (3, 4, None), (3, 5, None)] sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2]) sage: sorted(PG.edges()) [(1, 3, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None), (3, 4, None), (3, 5, None)] sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3])) sage: sorted(PG.edges()) [(2, 3, None)] sage: graphs.PermutationGraph([]).edges() [] sage: graphs.PermutationGraph([], []).edges() [] sage: PG = graphs.PermutationGraph("graph", "phrag") sage: sorted(PG.edges()) [('a', 'g', None), ('a', 'h', None), ('a', 'p', None), ('g', 'h', None), ('g', 'p', None), ('g', 'r', None), ('h', 'r', None), ('p', 'r', None)] TESTS:: sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6]) Traceback (most recent call last): ... ValueError: The two permutations do not contain the same set of elements ... """ if first_permutation is None: first_permutation = sorted(second_permutation) else: if set(second_permutation) != set(first_permutation): raise ValueError("The two permutations do not contain the same "+ "set of elements ! It is going to be pretty "+ "hard to define a permutation graph from that !") vertex_to_index = {} for i, v in enumerate(first_permutation): vertex_to_index[v] = i+1 from sage.combinat.permutation import Permutation p2 = Permutation([vertex_to_index[x] for x in second_permutation]) p2 = p2.inverse() g = Graph(name="Permutation graph for "+str(second_permutation)) g.add_vertices(second_permutation) for u,v in p2.inversions(): g.add_edge(first_permutation[u-1], first_permutation[v-1]) return g
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 _check_pbd(B,v,S): r""" Checks that ``B`` is a PBD on ``v`` points with given block sizes ``S``. The points of the balanced incomplete block design are implicitely assumed to be `\{0, ..., v-1\}`. INPUT: - ``B`` -- a list of blocks - ``v`` (integer) -- number of points - ``S`` -- list of integers `\geq 2`. EXAMPLE:: sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10], [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28], [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34], ... sage: from sage.combinat.designs.bibd import _check_pbd sage: _check_pbd([[1],[]],1,[1,0]) Traceback (most recent call last): ... RuntimeError: All integers of S must be >=2 TESTS:: sage: _check_pbd([[1,2]],2,[2]) Traceback (most recent call last): ... RuntimeError: The PBD covers a point 2 which is not in {0, 1} sage: _check_pbd([[1,2]]*2,2,[2]) Traceback (most recent call last): ... RuntimeError: The pair (1,2) is covered more than once sage: _check_pbd([],2,[2]) Traceback (most recent call last): ... RuntimeError: The pair (0,1) is not covered sage: _check_pbd([[1,2],[1]],2,[2]) Traceback (most recent call last): ... RuntimeError: A block has size 1 while S=[2] """ from itertools import combinations from sage.graphs.graph import Graph for X in B: if len(X) not in S: raise RuntimeError("A block has size {} while S={}".format(len(X),S)) if any(x < 2 for x in S): raise RuntimeError("All integers of S must be >=2") if v == 0 or v == 1: if B: raise RuntimeError("A PBD with v<=1 is expected to be empty.") g = Graph() g.add_vertices(range(v)) m = 0 for X in B: for i,j in combinations(X,2): g.add_edge(i,j) m_tmp = g.size() if m_tmp != m+1: raise RuntimeError("The pair ({},{}) is covered more than once".format(i,j)) m = m_tmp if g.vertices() != range(v): from sage.sets.integer_range import IntegerRange p = (set(g.vertices())-set(range(v))).pop() raise RuntimeError("The PBD covers a point {} which is not in {}".format(p,IntegerRange(v))) if not g.is_clique(): for p1 in g: if g.degree(p1) != v-1: break neighbors = g.neighbors(p1)+[p1] p2 = (set(g.vertices())-set(neighbors)).pop() raise RuntimeError("The pair ({},{}) is not covered".format(p1,p2)) return B
def PermutationGraph(second_permutation, first_permutation=None): r""" Build a permutation graph from one permutation or from two lists. Definition: If `\sigma` is a permutation of `\{ 1, 2, \ldots, n \}`, then the permutation graph of `\sigma` is the graph on vertex set `\{ 1, 2, \ldots, n \}` in which two vertices `i` and `j` satisfying `i < j` are connected by an edge if and only if `\sigma^{-1}(i) > \sigma^{-1}(j)`. A visual way to construct this graph is as follows: Take two horizontal lines in the euclidean plane, and mark points `1, ..., n` from left to right on the first of them. On the second one, still from left to right, mark `n` points `\sigma(1), \sigma(2), \ldots, \sigma(n)`. Now, link by a segment the two points marked with `1`, then link together the points marked with `2`, and so on. The permutation graph of `\sigma` is the intersection graph of those segments: there exists a vertex in this graph for each element from `1` to `n`, two vertices `i, j` being adjacent if the segments `i` and `j` cross each other. The set of edges of the permutation graph can thus be identified with the set of inversions of the inverse of the given permutation `\sigma`. A more general notion of permutation graph can be defined as follows: If `S` is a set, and `(a_1, a_2, \ldots, a_n)` and `(b_1, b_2, \ldots, b_n)` are two lists of elements of `S`, each of which lists contains every element of `S` exactly once, then the permutation graph defined by these two lists is the graph on the vertex set `S` in which two vertices `i` and `j` are connected by an edge if and only if the order in which these vertices appear in the list `(a_1, a_2, \ldots, a_n)` is the opposite of the order in which they appear in the list `(b_1, b_2, \ldots, b_n)`. When `(a_1, a_2, \ldots, a_n) = (1, 2, \ldots, n)`, this graph is the permutation graph of the permutation `(b_1, b_2, \ldots, b_n) \in S_n`. Notice that `S` does not have to be a set of integers here, but can be a set of strings, tuples, or anything else. We can still use the above visual description to construct the permutation graph, but now we have to mark points `a_1, a_2, \ldots, a_n` from left to right on the first horizontal line and points `b_1, b_2, \ldots, b_n` from left to right on the second horizontal line. INPUT: - ``second_permutation`` -- the unique permutation/list defining the graph, or the second of the two (if the graph is to be built from two permutations/lists). - ``first_permutation`` (optional) -- the first of the two permutations/lists from which the graph should be built, if it is to be built from two permutations/lists. When ``first_permutation is None`` (default), it is set to be equal to ``sorted(second_permutation)``, which yields the expected ordering when the elements of the graph are integers. .. SEEALSO:: - Recognition of Permutation graphs in the :mod:`comparability module <sage.graphs.comparability>`. - Drawings of permutation graphs as intersection graphs of segments is possible through the :meth:`~sage.combinat.permutation.Permutation.show` method of :class:`~sage.combinat.permutation.Permutation` objects. The correct argument to use in this case is ``show(representation = "braid")``. - :meth:`~sage.combinat.permutation.Permutation.inversions` EXAMPLES:: sage: p = Permutations(5).random_element() sage: PG = graphs.PermutationGraph(p) sage: edges = PG.edges(labels=False) sage: set(edges) == set(p.inverse().inversions()) True sage: PG = graphs.PermutationGraph([3,4,5,1,2]) sage: sorted(PG.edges()) [(1, 3, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 4, None), (2, 5, None)] sage: PG = graphs.PermutationGraph([3,4,5,1,2], [1,4,2,5,3]) sage: sorted(PG.edges()) [(1, 3, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None), (3, 4, None), (3, 5, None)] sage: PG = graphs.PermutationGraph([1,4,2,5,3], [3,4,5,1,2]) sage: sorted(PG.edges()) [(1, 3, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None), (3, 4, None), (3, 5, None)] sage: PG = graphs.PermutationGraph(Permutation([1,3,2]), Permutation([1,2,3])) sage: sorted(PG.edges()) [(2, 3, None)] sage: graphs.PermutationGraph([]).edges() [] sage: graphs.PermutationGraph([], []).edges() [] sage: PG = graphs.PermutationGraph("graph", "phrag") sage: sorted(PG.edges()) [('a', 'g', None), ('a', 'h', None), ('a', 'p', None), ('g', 'h', None), ('g', 'p', None), ('g', 'r', None), ('h', 'r', None), ('p', 'r', None)] TESTS:: sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6]) Traceback (most recent call last): ... ValueError: The two permutations do not contain the same set of elements ... """ if first_permutation is None: first_permutation = sorted(second_permutation) else: if set(second_permutation) != set(first_permutation): raise ValueError("The two permutations do not contain the same " + "set of elements ! It is going to be pretty " + "hard to define a permutation graph from that !") vertex_to_index = {} for i, v in enumerate(first_permutation): vertex_to_index[v] = i + 1 from sage.combinat.permutation import Permutation p2 = Permutation([vertex_to_index[x] for x in second_permutation]) p2 = p2.inverse() g = Graph(name="Permutation graph for " + str(second_permutation)) g.add_vertices(second_permutation) for u, v in p2.inversions(): g.add_edge(first_permutation[u - 1], first_permutation[v - 1]) return g
def RandomBipartite(n1,n2, p): r""" Returns a bipartite graph with `n1+n2` vertices such that any edge from `[n1]` to `[n2]` exists with probability `p`. INPUT: - ``n1,n2`` : Cardinalities of the two sets - ``p`` : Probability for an edge to exist EXAMPLE:: sage: g=graphs.RandomBipartite(5,2,0.5) sage: g.vertices() [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)] TESTS:: sage: g=graphs.RandomBipartite(5,-3,0.5) Traceback (most recent call last): ... ValueError: n1 and n2 should be integers strictly greater than 0 sage: g=graphs.RandomBipartite(5,3,1.5) Traceback (most recent call last): ... ValueError: Parameter p is a probability, and so should be a real value between 0 and 1 Trac ticket #12155:: sage: graphs.RandomBipartite(5,6,.2).complement() complement(Random bipartite graph of size 5+6 with edge probability 0.200000000000000): Graph on 11 vertices """ if not (p>=0 and p<=1): raise ValueError, "Parameter p is a probability, and so should be a real value between 0 and 1" if not (n1>0 and n2>0): raise ValueError, "n1 and n2 should be integers strictly greater than 0" from numpy.random import uniform g=Graph(name="Random bipartite graph of size "+str(n1) +"+"+str(n2)+" with edge probability "+str(p)) S1=[(0,i) for i in range(n1)] S2=[(1,i) for i in range(n2)] g.add_vertices(S1) g.add_vertices(S2) for w in range(n2): for v in range(n1): if uniform()<=p : g.add_edge((0,v),(1,w)) pos = {} for i in range(n1): pos[(0,i)] = (0, i/(n1-1.0)) for i in range(n2): pos[(1,i)] = (1, i/(n2-1.0)) g.set_pos(pos) return g
def EuropeMap(continental=False, year=2018): """ Return European states as a graph of common border. "European state" here is defined as an independent state having the capital city in Europe. The graph has an edge between those countries that have common *land* border. INPUT: - ``continental``, a Boolean -- if set, only return states in the continental Europe - ``year`` -- reserved for future use EXAMPLES:: sage: Europe = graphs.EuropeMap(); Europe Europe Map: Graph on 44 vertices sage: Europe.neighbors('Ireland') ['United Kingdom'] sage: cont_Europe = graphs.EuropeMap(continental=True) sage: cont_Europe.order() 40 sage: 'Iceland' in cont_Europe False """ if year != 2018: raise ValueError("currently only year 2018 is implemented") common_border = { 'Poland': [ 'Slovakia', 'Czech Republic', 'Lithuania', 'Russia', 'Ukraine', 'Germany' ], 'Germany': [ 'Czech Republic', 'Netherlands', 'Switzerland', 'Luxembourg', 'Denmark' ], 'Croatia': [ 'Bosnia and Herzegovina', 'Serbia', 'Hungary', 'Montenegro', 'Slovenia' ], 'Austria': [ 'Czech Republic', 'Germany', 'Switzerland', 'Slovenia', 'Liechtenstein' ], 'France': ['Germany', 'Italy', 'Switzerland', 'Monaco', 'Luxembourg', 'Andorra'], 'Hungary': ['Slovakia', 'Serbia', 'Romania', 'Ukraine', 'Slovenia', 'Austria'], 'Italy': ['Switzerland', 'Vatican City', 'San Marino', 'Slovenia', 'Austria'], 'Belarus': ['Poland', 'Latvia', 'Lithuania', 'Russia', 'Ukraine'], 'Montenegro': ['Bosnia and Herzegovina', 'Serbia', 'Albania'], 'Belgium': ['Germany', 'Netherlands', 'Luxembourg', 'France'], 'Russia': ['Finland', 'Lithuania', 'Estonia', 'Ukraine'], 'Romania': ['Serbia', 'Moldova', 'Bulgaria', 'Ukraine'], 'Latvia': ['Lithuania', 'Russia', 'Estonia'], 'Slovakia': ['Czech Republic', 'Ukraine', 'Austria'], 'Switzerland': ['Liechtenstein'], 'Spain': ['Portugal', 'Andorra', 'France'], 'Norway': ['Finland', 'Sweden', 'Russia'], 'Ireland': ['United Kingdom'], 'Serbia': ['Bosnia and Herzegovina', 'Bulgaria'], 'Greece': ['Macedonia', 'Bulgaria', 'Albania'], 'Ukraine': ['Moldova'], 'Macedonia': ['Serbia', 'Bulgaria', 'Albania'], 'Sweden': ['Finland'] } no_land_border = ['Iceland', 'Malta'] G = Graph(common_border, format='dict_of_lists') if continental: G = G.subgraph(G.connected_component_containing_vertex('Austria')) G.name(new="Continental Europe Map") else: G.add_vertices(no_land_border) G.name(new="Europe Map") return G
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 dual_equivalence_class(self, index_set=None): r""" Return the dual equivalence class indexed by ``index_set`` of ``self``. The dual equivalence class of an element `b \in B` is the set of all elements of `B` reachable from `b` via sequences of `i`-elementary dual equivalence relations (i.e., `i`-elementary dual equivalence transformations and their inverses) for `i` in the index set of `B`. For this to be well-defined, the element `b` has to be of weight `0` with respect to `I`; that is, we need to have `\varepsilon_j(b) = \varphi_j(b)` for all `j \in I`. See [Assaf08]_. See also :meth:`dual_equivalence_graph` for a definition of `i`-elementary dual equivalence transformations. INPUT: - ``index_set`` -- (optional) the index set `I` (default: the whole index set of the crystal); this has to be a subset of the index set of the crystal (as a list or tuple) OUTPUT: The dual equivalence class of ``self`` indexed by the subset ``index_set``. This class is returned as an undirected edge-colored multigraph. The color of an edge is the index `i` of the dual equivalence relation it encodes. .. SEEALSO:: - :meth:`~sage.categories.regular_crystals.RegularCrystals.ParentMethods.dual_equivalence_graph` - :meth:`sage.combinat.partition.Partition.dual_equivalence_graph` EXAMPLES:: sage: T = crystals.Tableaux(['A',3], shape=[2,2]) sage: G = T(2,1,4,3).dual_equivalence_class() sage: sorted(G.edges()) [([[1, 3], [2, 4]], [[1, 2], [3, 4]], 2), ([[1, 3], [2, 4]], [[1, 2], [3, 4]], 3)] sage: T = crystals.Tableaux(['A',4], shape=[3,2]) sage: G = T(2,1,4,3,5).dual_equivalence_class() sage: sorted(G.edges()) [([[1, 3, 5], [2, 4]], [[1, 3, 4], [2, 5]], 4), ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 2), ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 3), ([[1, 3, 4], [2, 5]], [[1, 2, 4], [3, 5]], 2), ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 3), ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 4)] """ if index_set is None: index_set = self.index_set() for i in index_set: if self.epsilon(i) != self.phi(i): raise ValueError("the element is not weight 0") visited = set([]) todo = set([self]) edges = [] while todo: x = todo.pop() visited.add(x) for k, i in enumerate(index_set[1:]): im = index_set[k] if x.epsilon(i) == 1 and x.epsilon(im) == 0: y = x.e(i).e(im).f(i).f(im) if [y, x, i] not in edges: edges.append([x, y, i]) if y not in visited: todo.add(y) if x.epsilon(i) == 0 and x.epsilon(im) == 1: y = x.e(im).e(i).f(im).f(i) if [y, x, i] not in edges: edges.append([x, y, i]) if y not in visited: todo.add(y) from sage.graphs.graph import Graph G = Graph(edges, multiedges=True) G.add_vertices(visited) if have_dot2tex(): G.set_latex_options( format="dot2tex", edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring ) return G
def RandomTree(n): """ Returns a random tree on `n` nodes numbered `0` through `n-1`. By Cayley's theorem, there are `n^{n-2}` trees with vertex set `\{0,1,...,n-1\}`. This constructor chooses one of these uniformly at random. ALGORITHM: The algoritm works by generating an `(n-2)`-long random sequence of numbers chosen independently and uniformly from `\{0,1,\ldots,n-1\}` and then applies an inverse Prufer transformation. INPUT: - ``n`` - number of vertices in the tree EXAMPLE:: sage: G = graphs.RandomTree(10) sage: G.is_tree() True sage: G.show() # long TESTS: Ensuring that we encounter no unexpected surprise :: sage: all( graphs.RandomTree(10).is_tree() ....: for i in range(100) ) True """ from sage.misc.prandom import randint g = Graph() # create random Prufer code code = [randint(0, n - 1) for i in xrange(n - 2)] # We count the number of symbols of each type. # count[k] is the no. of times k appears in code # # (count[k] is set to -1 when the corresponding vertex is not # available anymore) count = [0 for i in xrange(n)] for k in code: count[k] += 1 g.add_vertices(range(n)) for s in code: for x in range(n): if count[x] == 0: break count[x] = -1 g.add_edge(x, s) count[s] -= 1 # Adding as an edge the last two available vertices last_edge = [v for v in range(n) if count[v] != -1] g.add_edge(last_edge) return g
def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): """ Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. EXAMPLES: Some infinite ones:: sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]]) sage: C.is_finite() # indirect doctest False sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) sage: C.is_finite() # indirect doctest False Some finite ones:: sage: m = matrix(CoxeterMatrix(['D', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: m = matrix(CoxeterMatrix(['H', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10] sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10] sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6] sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7] sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8] sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4] sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2] sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 3] sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() Coxeter type of ['I', 100] Some affine graphs:: sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 1, 1] sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10, 1] sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10, 1] sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['C', 10, 1] sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10, 1] sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6, 1] sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7, 1] sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8, 1] sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4, 1] sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2, 1] TESTS: Check that we detect relabellings:: sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c']) sage: M.coxeter_type() Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'} sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix sage: for C in CoxeterMatrix.samples(): ....: relabelling_perm = Permutations(C.index_set()).random_element() ....: relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())} ....: relabeled_matrix = C.relabel(relabelling_dict)._matrix ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm) ....: if C.is_finite() or C.is_affine(): ....: assert recognized_type == C.coxeter_type() We check the rank 2 cases (:trac:`20419`):: sage: for i in range(2, 10): ....: M = matrix([[1,i],[i,1]]) ....: CoxeterMatrix(M).coxeter_type() Coxeter type of A1xA1 relabelled by {1: 2} Coxeter type of ['A', 2] Coxeter type of ['B', 2] Coxeter type of ['I', 5] Coxeter type of ['G', 2] Coxeter type of ['I', 7] Coxeter type of ['I', 8] Coxeter type of ['I', 9] sage: CoxeterMatrix(matrix([[1,-1],[-1,1]]), index_set=[0,1]).coxeter_type() Coxeter type of ['A', 1, 1] """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) G = Graph([[index_set[i], index_set[j], coxeter_matrix[i, j]] for i in range(n) for j in range(i, n) if coxeter_matrix[i, j] not in [1, 2]]) G.add_vertices(index_set) types = [] for S in G.connected_components_subgraphs(): r = S.num_verts() # Handle the special cases first if r == 1: types.append(CoxeterType(['A', 1]).relabel({1: S.vertices()[0]})) continue if r == 2: # Type B2, G2, or I_2(p) e = S.edge_labels()[0] if e == 3: # Can't be 2 because it is connected ct = CoxeterType(['A', 2]) elif e == 4: ct = CoxeterType(['B', 2]) elif e == 6: ct = CoxeterType(['G', 2]) elif e > 0 and e < float('inf'): # Remaining non-affine types ct = CoxeterType(['I', e]) else: # Otherwise it is infinite dihedral group Z_2 \ast Z_2 ct = CoxeterType(['A', 1, 1]) if not ct.is_affine(): types.append( ct.relabel({ 1: S.vertices()[0], 2: S.vertices()[1] })) else: types.append( ct.relabel({ 0: S.vertices()[0], 1: S.vertices()[1] })) continue test = [['A', r], ['B', r], ['A', r - 1, 1]] if r >= 3: if r == 3: test += [['G', 2, 1], ['H', 3]] test.append(['C', r - 1, 1]) if r >= 4: if r == 4: test += [['F', 4], ['H', 4]] test += [['D', r], ['B', r - 1, 1]] if r >= 5: if r == 5: test.append(['F', 4, 1]) test.append(['D', r - 1, 1]) if r == 6: test.append(['E', 6]) elif r == 7: test += [['E', 7], ['E', 6, 1]] elif r == 8: test += [['E', 8], ['E', 7, 1]] elif r == 9: test.append(['E', 8, 1]) found = False for ct in test: ct = CoxeterType(ct) T = ct.coxeter_graph() iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if not found: return None return CoxeterType(types)
def PermutationGraph(second_permutation, first_permutation=None): r""" Builds a permutation graph from one (or two) permutations. General definition A Permutation Graph can be encoded by a permutation `\sigma` of `1, ..., n`. It is then built in the following way : Take two horizontal lines in the euclidean plane, and mark points `1, ..., n` from left to right on the first of them. On the second one, still from left to right, mark point in the order in which they appear in `\sigma`. Now, link by a segment the two points marked with 1, then link together the points marked with 2, and so on. The permutation graph defined by the permutation is the intersection graph of those segments : there exists a point in this graph for each element from `1` to `n`, two vertices `i, j` being adjacent if the segments `i` and `j` cross each other. The set of edges of the resulting graph is equal to the set of inversions of the inverse of the given permutation. INPUT: - ``second_permutation`` -- the permutation from which the graph should be built. It corresponds to the ordering of the elements on the second line (see previous definition) - ``first_permutation`` (optional) -- the ordering of the elements on the *first* line. This is useful when the elements have no natural ordering, for instance when they are strings, or tuples, or anything else. When ``first_permutation == None`` (default), it is set to be equal to ``sorted(second_permutation)``, which just yields the expected ordering when the elements of the graph are integers. .. SEEALSO: - Recognition of Permutation graphs in the :mod:`comparability module <sage.graphs.comparability>`. - Drawings of permutation graphs as intersection graphs of segments is possible through the :meth:`~sage.combinat.permutation.Permutation.show` method of :class:`~sage.combinat.permutation.Permutation` objects. The correct argument to use in this case is ``show(representation = "braid")``. - :meth:`~sage.combinat.permutation.Permutation.inversions` EXAMPLE:: sage: p = Permutations(5).random_element() sage: edges = graphs.PermutationGraph(p).edges(labels =False) sage: set(edges) == set(p.inverse().inversions()) True TESTS:: sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6]) Traceback (most recent call last): ... ValueError: The two permutations do not contain the same set of elements ... """ if first_permutation == None: first_permutation = sorted(second_permutation) else: if set(second_permutation) != set(first_permutation): raise ValueError("The two permutations do not contain the same " + "set of elements ! It is going to be pretty " + "hard to define a permutation graph from that !") vertex_to_index = {} for i, v in enumerate(first_permutation): vertex_to_index[v] = i + 1 from sage.combinat.permutation import Permutation p2 = Permutation(map(lambda x: vertex_to_index[x], second_permutation)) p1 = Permutation(map(lambda x: vertex_to_index[x], first_permutation)) p2 = p2 * p1.inverse() p2 = p2.inverse() g = Graph(name="Permutation graph for " + str(second_permutation)) g.add_vertices(second_permutation) for u, v in p2.inversions(): g.add_edge(first_permutation[u - 1], first_permutation[v - 1]) return g
def _check_pbd(B, v, S): r""" Checks that ``B`` is a PBD on ``v`` points with given block sizes ``S``. The points of the balanced incomplete block design are implicitely assumed to be `\{0, ..., v-1\}`. INPUT: - ``B`` -- a list of blocks - ``v`` (integer) -- number of points - ``S`` -- list of integers `\geq 2`. EXAMPLE:: sage: designs.balanced_incomplete_block_design(40,4).blocks() # indirect doctest [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 10], [0, 5, 7, 11], [0, 13, 26, 39], [0, 14, 25, 28], [0, 15, 27, 38], [0, 16, 22, 32], [0, 17, 23, 34], ... sage: from sage.combinat.designs.bibd import _check_pbd sage: _check_pbd([[1],[]],1,[1,0]) Traceback (most recent call last): ... RuntimeError: All integers of S must be >=2 TESTS:: sage: _check_pbd([[1,2]],2,[2]) Traceback (most recent call last): ... RuntimeError: The PBD covers a point 2 which is not in {0, 1} sage: _check_pbd([[1,2]]*2,2,[2]) Traceback (most recent call last): ... RuntimeError: The pair (1,2) is covered more than once sage: _check_pbd([],2,[2]) Traceback (most recent call last): ... RuntimeError: The pair (0,1) is not covered sage: _check_pbd([[1,2],[1]],2,[2]) Traceback (most recent call last): ... RuntimeError: A block has size 1 while S=[2] """ from itertools import combinations from sage.graphs.graph import Graph for X in B: if len(X) not in S: raise RuntimeError("A block has size {} while S={}".format( len(X), S)) if any(x < 2 for x in S): raise RuntimeError("All integers of S must be >=2") if v == 0 or v == 1: if B: raise RuntimeError("A PBD with v<=1 is expected to be empty.") g = Graph() g.add_vertices(range(v)) m = 0 for X in B: for i, j in combinations(X, 2): g.add_edge(i, j) m_tmp = g.size() if m_tmp != m + 1: raise RuntimeError( "The pair ({},{}) is covered more than once".format(i, j)) m = m_tmp if g.vertices() != range(v): from sage.sets.integer_range import IntegerRange p = (set(g.vertices()) - set(range(v))).pop() raise RuntimeError( "The PBD covers a point {} which is not in {}".format( p, IntegerRange(v))) if not g.is_clique(): for p1 in g: if g.degree(p1) != v - 1: break neighbors = g.neighbors(p1) + [p1] p2 = (set(g.vertices()) - set(neighbors)).pop() raise RuntimeError("The pair ({},{}) is not covered".format(p1, p2)) return B
def AffineOrthogonalPolarGraph(d,q,sign="+"): r""" Returns the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. Affine Polar graphs are built from a `d`-dimensional vector space over `F_q`, and a quadratic form which is hyperbolic, elliptic or parabolic according to the value of ``sign``. Note that `VO^+(d,q),VO^-(d,q)` are strongly regular graphs, while `VO(d,q)` is not. For more information on Affine Polar graphs, see `Affine Polar Graphs page of Andries Brouwer's website <http://www.win.tue.nl/~aeb/graphs/VO.html>`_. INPUT: - ``d`` (integer) -- ``d`` must be even if ``sign != None``, and odd otherwise. - ``q`` (integer) -- a power of a prime number, as `F_q` must exist. - ``sign`` -- must be equal to ``"+"``, ``"-"``, or ``None`` to compute (respectively) `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. By default ``sign="+"``. .. NOTE:: The graph `VO^\epsilon(d,q)` is the graph induced by the non-neighbors of a vertex in an :meth:`Orthogonal Polar Graph <OrthogonalPolarGraph>` `O^\epsilon(d+2,q)`. EXAMPLES: The :meth:`Brouwer-Haemers graph <BrouwerHaemersGraph>` is isomorphic to `VO^-(4,3)`:: sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) True Some examples from `Brouwer's table or strongly regular graphs <http://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`_:: sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g Affine Polar Graph VO^-(6,2): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 27, 10, 12) sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g Affine Polar Graph VO^+(6,2): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) When ``sign is None``:: sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g Affine Polar Graph VO^-(5,2): Graph on 32 vertices sage: g.is_strongly_regular(parameters=True) False sage: g.is_regular() True sage: g.is_vertex_transitive() True """ if sign in ["+","-"]: s = 1 if sign == "+" else -1 if d%2 == 1: raise ValueError("d must be even when sign!=None") else: if d%2 == 0: raise ValueError("d must be odd when sign==None") s = 0 from sage.interfaces.gap import gap from sage.modules.free_module import VectorSpace from sage.matrix.constructor import Matrix from sage.libs.gap.libgap import libgap from itertools import combinations M = Matrix(libgap.InvariantQuadraticForm(libgap.GeneralOrthogonalGroup(s,d,q))['matrix']) F = libgap.GF(q).sage() V = list(VectorSpace(F,d)) G = Graph() G.add_vertices([tuple(_) for _ in V]) for x,y in combinations(V,2): if not (x-y)*M*(x-y): G.add_edge(tuple(x),tuple(y)) G.name("Affine Polar Graph VO^"+str('+' if s == 1 else '-')+"("+str(d)+","+str(q)+")") G.relabel() return G
def AfricaMap(continental=False, year=2018): """ Return African states as a graph of common border. "African state" here is defined as an independent state having the capital city in Africa. The graph has an edge between those countries that have common *land* border. INPUT: - ``continental``, a Boolean -- if set, only return states in the continental Africa - ``year`` -- reserved for future use EXAMPLES:: sage: Africa = graphs.AfricaMap(); Africa Africa Map: Graph on 54 vertices sage: sorted(Africa.neighbors('Libya')) ['Algeria', 'Chad', 'Egypt', 'Niger', 'Sudan', 'Tunisia'] sage: cont_Africa = graphs.AfricaMap(continental=True) sage: cont_Africa.order() 48 sage: 'Madagaskar' in cont_Africa False """ if year != 2018: raise ValueError("currently only year 2018 is implemented") common_border = { 'Algeria': ['Libya', 'Mali', 'Mauritania', 'Morocco', 'Niger', 'Tunisia'], 'Angola': ['Namibia', 'Zambia'], 'Benin': ['Burkina Faso', 'Niger', 'Nigeria', 'Togo'], 'Botswana': ['Namibia', 'South Africa', 'Zimbabwe'], 'Burkina Faso': ['Ghana', 'Ivory Coast', 'Mali', 'Niger', 'Togo'], 'Cameroon': ['Central Africa', 'Chad', 'Equatorial Guinea', 'Gabon', 'Nigeria'], 'Central Africa': ['Chad', 'South Sudan', 'Sudan'], 'Chad': ['Libya', 'Niger', 'Nigeria', 'Sudan'], 'Republic of the Congo': [ 'Gabon', 'Cameroon', 'Central Africa', 'Angola', 'Democratic Republic of the Congo' ], 'Democratic Republic of the Congo': [ 'Zambia', 'South Sudan', 'Tanzania', 'Burundi', 'Rwanda', 'Uganda', 'Central Africa', 'Angola' ], 'Djibouti': ['Eritrea', 'Ethiopia', 'Somalia'], 'Ethiopia': ['Eritrea', 'Kenya', 'Somalia', 'South Sudan', 'Sudan'], 'Gabon': ['Equatorial Guinea'], 'Ghana': ['Ivory Coast', 'Togo'], 'Guinea': ['Guinea-Bissau', 'Ivory Coast', 'Liberia', 'Sierra Leone'], 'Kenya': ['Somalia', 'South Sudan', 'Tanzania', 'Uganda'], 'Liberia': ['Ivory Coast', 'Sierra Leone'], 'Libya': ['Egypt', 'Niger', 'Sudan', 'Tunisia'], 'Mali': ['Guinea', 'Ivory Coast', 'Mauritania', 'Niger', 'Senegal'], 'Mozambique': ['Malawi', 'South Africa', 'Swaziland', 'Zimbabwe'], 'Niger': ['Nigeria'], 'Rwanda': ['Burundi', 'Tanzania', 'Uganda'], 'Senegal': ['Guinea', 'Guinea-Bissau', 'Mauritania', 'Gambia'], 'South Africa': ['Lesotho', 'Namibia', 'Swaziland', 'Zimbabwe'], 'South Sudan': ['Uganda', 'Sudan', 'Democratic Republic of the Congo'], 'Sudan': ['Egypt', 'Eritrea'], 'Tanzania': ['Burundi', 'Malawi', 'Mozambique', 'Uganda', 'Zambia'], 'Zambia': ['Malawi', 'Mozambique', 'Namibia', 'Zimbabwe'] } no_land_border = [ 'Cape Verde', 'Seychelles', 'Mauritius', 'S\xc3\xa3o Tom\xc3\xa9 and Pr\xc3\xadncipe', 'Madagascar', 'Comoros' ] G = Graph(common_border, format='dict_of_lists') if continental: G = G.subgraph( G.connected_component_containing_vertex('Central Africa')) G.name(new="Continental Africa Map") else: G.add_vertices(no_land_border) G.name(new="Africa Map") return G
def RandomTree(n): """ Returns a random tree on `n` nodes numbered `0` through `n-1`. By Cayley's theorem, there are `n^{n-2}` trees with vertex set `\{0,1,...,n-1\}`. This constructor chooses one of these uniformly at random. ALGORITHM: The algoritm works by generating an `(n-2)`-long random sequence of numbers chosen independently and uniformly from `\{0,1,\ldots,n-1\}` and then applies an inverse Prufer transformation. INPUT: - ``n`` - number of vertices in the tree EXAMPLE:: sage: G = graphs.RandomTree(10) sage: G.is_tree() True sage: G.show() # long TESTS: Ensuring that we encounter no unexpected surprise :: sage: all( graphs.RandomTree(10).is_tree() ....: for i in range(100) ) True """ from sage.misc.prandom import randint g = Graph() # create random Prufer code code = [ randint(0,n-1) for i in xrange(n-2) ] # We count the number of symbols of each type. # count[k] is the no. of times k appears in code # # (count[k] is set to -1 when the corresponding vertex is not # available anymore) count = [ 0 for i in xrange(n) ] for k in code: count[k] += 1 g.add_vertices(range(n)) for s in code: for x in range(n): if count[x] == 0: break count[x] = -1 g.add_edge(x,s) count[s] -= 1 # Adding as an edge the last two available vertices last_edge = [ v for v in range(n) if count[v] != -1 ] g.add_edge(last_edge) return g
def AfricaMap(continental=False, year=2018): """ Return African states as a graph of common border. "African state" here is defined as an independent state having the capital city in Africa. The graph has an edge between those countries that have common *land* border. INPUT: - ``continental``, a Boolean -- if set, only return states in the continental Africa - ``year`` -- reserved for future use EXAMPLES:: sage: Africa = graphs.AfricaMap(); Africa Africa Map: Graph on 54 vertices sage: sorted(Africa.neighbors('Libya')) ['Algeria', 'Chad', 'Egypt', 'Niger', 'Sudan', 'Tunisia'] sage: cont_Africa = graphs.AfricaMap(continental=True) sage: cont_Africa.order() 48 sage: 'Madagaskar' in cont_Africa False TESTS:: sage: Africa.plot() Graphics object consisting of 159 graphics primitives """ if year != 2018: raise ValueError("currently only year 2018 is implemented") common_border = { 'Algeria': ['Libya', 'Mali', 'Mauritania', 'Morocco', 'Niger', 'Tunisia'], 'Angola': ['Namibia', 'Zambia'], 'Benin': ['Burkina Faso', 'Niger', 'Nigeria', 'Togo'], 'Botswana': ['Namibia', 'South Africa', 'Zimbabwe'], 'Burkina Faso': ['Ghana', 'Ivory Coast', 'Mali', 'Niger', 'Togo'], 'Cameroon': ['Central Africa', 'Chad', 'Equatorial Guinea', 'Gabon', 'Nigeria'], 'Central Africa': ['Chad', 'South Sudan', 'Sudan'], 'Chad': ['Libya', 'Niger', 'Nigeria', 'Sudan'], 'Republic of the Congo': ['Gabon', 'Cameroon', 'Central Africa', 'Angola', 'Democratic Republic of the Congo'], 'Democratic Republic of the Congo': ['Zambia', 'South Sudan', 'Tanzania', 'Burundi', 'Rwanda', 'Uganda', 'Central Africa', 'Angola'], 'Djibouti': ['Eritrea', 'Ethiopia', 'Somalia'], 'Ethiopia': ['Eritrea', 'Kenya', 'Somalia', 'South Sudan', 'Sudan'], 'Gabon': ['Equatorial Guinea'], 'Ghana': ['Ivory Coast', 'Togo'], 'Guinea': ['Guinea-Bissau', 'Ivory Coast', 'Liberia', 'Sierra Leone'], 'Kenya': ['Somalia', 'South Sudan', 'Tanzania', 'Uganda'], 'Liberia': ['Ivory Coast', 'Sierra Leone'], 'Libya': ['Egypt', 'Niger', 'Sudan', 'Tunisia'], 'Mali': ['Guinea', 'Ivory Coast', 'Mauritania', 'Niger', 'Senegal'], 'Mozambique': ['Malawi', 'South Africa', 'Swaziland', 'Zimbabwe'], 'Niger': ['Nigeria'], 'Rwanda': ['Burundi', 'Tanzania', 'Uganda'], 'Senegal': ['Guinea', 'Guinea-Bissau', 'Mauritania', 'Gambia'], 'South Africa': ['Lesotho', 'Namibia', 'Swaziland', 'Zimbabwe'], 'South Sudan': ['Uganda', 'Sudan', 'Democratic Republic of the Congo'], 'Sudan': ['Egypt', 'Eritrea'], 'Tanzania': ['Burundi', 'Malawi', 'Mozambique', 'Uganda', 'Zambia'], 'Zambia': ['Malawi', 'Mozambique', 'Namibia', 'Zimbabwe'] } no_land_border = ['Cape Verde', 'Seychelles', 'Mauritius', u'São Tomé and Príncipe', 'Madagascar', 'Comoros'] G = Graph(common_border, format='dict_of_lists') if continental: G = G.subgraph(G.connected_component_containing_vertex('Central Africa')) G.name(new="Continental Africa Map") else: G.add_vertices(no_land_border) G.name(new="Africa Map") return G
def PermutationGraph(second_permutation, first_permutation = None): r""" Builds a permutation graph from one (or two) permutations. General definition A Permutation Graph can be encoded by a permutation `\sigma` of `1, ..., n`. It is then built in the following way : Take two horizontal lines in the euclidean plane, and mark points `1, ..., n` from left to right on the first of them. On the second one, still from left to right, mark point in the order in which they appear in `\sigma`. Now, link by a segment the two points marked with 1, then link together the points marked with 2, and so on. The permutation graph defined by the permutation is the intersection graph of those segments : there exists a point in this graph for each element from `1` to `n`, two vertices `i, j` being adjacent if the segments `i` and `j` cross each other. The set of edges of the resulting graph is equal to the set of inversions of the inverse of the given permutation. INPUT: - ``second_permutation`` -- the permutation from which the graph should be built. It corresponds to the ordering of the elements on the second line (see previous definition) - ``first_permutation`` (optional) -- the ordering of the elements on the *first* line. This is useful when the elements have no natural ordering, for instance when they are strings, or tuples, or anything else. When ``first_permutation == None`` (default), it is set to be equal to ``sorted(second_permutation)``, which just yields the expected ordering when the elements of the graph are integers. .. SEEALSO: - Recognition of Permutation graphs in the :mod:`comparability module <sage.graphs.comparability>`. - Drawings of permutation graphs as intersection graphs of segments is possible through the :meth:`~sage.combinat.permutation.Permutation.show` method of :class:`~sage.combinat.permutation.Permutation` objects. The correct argument to use in this case is ``show(representation = "braid")``. - :meth:`~sage.combinat.permutation.Permutation.inversions` EXAMPLE:: sage: p = Permutations(5).random_element() sage: edges = graphs.PermutationGraph(p).edges(labels =False) sage: set(edges) == set(p.inverse().inversions()) True TESTS:: sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6]) Traceback (most recent call last): ... ValueError: The two permutations do not contain the same set of elements ... """ if first_permutation == None: first_permutation = sorted(second_permutation) else: if set(second_permutation) != set(first_permutation): raise ValueError("The two permutations do not contain the same "+ "set of elements ! It is going to be pretty "+ "hard to define a permutation graph from that !") vertex_to_index = {} for i, v in enumerate(first_permutation): vertex_to_index[v] = i+1 from sage.combinat.permutation import Permutation p2 = Permutation(map(lambda x:vertex_to_index[x], second_permutation)) p1 = Permutation(map(lambda x:vertex_to_index[x], first_permutation)) p2 = p2 * p1.inverse() p2 = p2.inverse() g = Graph(name="Permutation graph for "+str(second_permutation)) g.add_vertices(second_permutation) for u,v in p2.inversions(): g.add_edge(first_permutation[u-1], first_permutation[v-1]) return g
def EuropeMap(continental=False, year=2018): """ Return European states as a graph of common border. "European state" here is defined as an independent state having the capital city in Europe. The graph has an edge between those countries that have common *land* border. INPUT: - ``continental``, a Boolean -- if set, only return states in the continental Europe - ``year`` -- reserved for future use EXAMPLES:: sage: Europe = graphs.EuropeMap(); Europe Europe Map: Graph on 44 vertices sage: Europe.neighbors('Ireland') ['United Kingdom'] sage: cont_Europe = graphs.EuropeMap(continental=True) sage: cont_Europe.order() 40 sage: 'Iceland' in cont_Europe False """ if year != 2018: raise ValueError("currently only year 2018 is implemented") common_border = { 'Poland': ['Slovakia', 'Czech Republic', 'Lithuania', 'Russia', 'Ukraine', 'Germany'], 'Germany': ['Czech Republic', 'Netherlands', 'Switzerland', 'Luxembourg', 'Denmark'], 'Croatia': ['Bosnia and Herzegovina', 'Serbia', 'Hungary', 'Montenegro', 'Slovenia'], 'Austria': ['Czech Republic', 'Germany', 'Switzerland', 'Slovenia', 'Liechtenstein'], 'France': ['Germany', 'Italy', 'Switzerland', 'Monaco', 'Luxembourg', 'Andorra'], 'Hungary': ['Slovakia', 'Serbia', 'Romania', 'Ukraine', 'Slovenia', 'Austria'], 'Italy': ['Switzerland', 'Vatican City', 'San Marino', 'Slovenia', 'Austria'], 'Belarus': ['Poland', 'Latvia', 'Lithuania', 'Russia', 'Ukraine'], 'Montenegro': ['Bosnia and Herzegovina', 'Serbia', 'Albania'], 'Belgium': ['Germany', 'Netherlands', 'Luxembourg', 'France'], 'Russia': ['Finland', 'Lithuania', 'Estonia', 'Ukraine'], 'Romania': ['Serbia', 'Moldova', 'Bulgaria', 'Ukraine'], 'Latvia': ['Lithuania', 'Russia', 'Estonia'], 'Slovakia': ['Czech Republic', 'Ukraine', 'Austria'], 'Switzerland': ['Liechtenstein'], 'Spain': ['Portugal', 'Andorra', 'France'], 'Norway': ['Finland', 'Sweden', 'Russia'], 'Ireland': ['United Kingdom'], 'Serbia': ['Bosnia and Herzegovina', 'Bulgaria'], 'Greece': ['Macedonia', 'Bulgaria', 'Albania'], 'Ukraine': ['Moldova'], 'Macedonia': ['Serbia', 'Bulgaria', 'Albania'], 'Sweden': ['Finland'] } no_land_border = ['Iceland', 'Malta'] G = Graph(common_border, format='dict_of_lists') if continental: G = G.subgraph(G.connected_component_containing_vertex('Austria')) G.name(new="Continental Europe Map") else: G.add_vertices(no_land_border) G.name(new="Europe Map") return G
def AffineOrthogonalPolarGraph(d, q, sign="+"): r""" Returns the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. Affine Polar graphs are built from a `d`-dimensional vector space over `F_q`, and a quadratic form which is hyperbolic, elliptic or parabolic according to the value of ``sign``. Note that `VO^+(d,q),VO^-(d,q)` are strongly regular graphs, while `VO(d,q)` is not. For more information on Affine Polar graphs, see `Affine Polar Graphs page of Andries Brouwer's website <http://www.win.tue.nl/~aeb/graphs/VO.html>`_. INPUT: - ``d`` (integer) -- ``d`` must be even if ``sign != None``, and odd otherwise. - ``q`` (integer) -- a power of a prime number, as `F_q` must exist. - ``sign`` -- must be equal to ``"+"``, ``"-"``, or ``None`` to compute (respectively) `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. By default ``sign="+"``. .. NOTE:: The graph `VO^\epsilon(d,q)` is the graph induced by the non-neighbors of a vertex in an :meth:`Orthogonal Polar Graph <OrthogonalPolarGraph>` `O^\epsilon(d+2,q)`. EXAMPLES: The :meth:`Brouwer-Haemers graph <BrouwerHaemersGraph>` is isomorphic to `VO^-(4,3)`:: sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) True Some examples from `Brouwer's table or strongly regular graphs <http://www.win.tue.nl/~aeb/graphs/srg/srgtab.html>`_:: sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g Affine Polar Graph VO^-(6,2): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 27, 10, 12) sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g Affine Polar Graph VO^+(6,2): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) When ``sign is None``:: sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g Affine Polar Graph VO^-(5,2): Graph on 32 vertices sage: g.is_strongly_regular(parameters=True) False sage: g.is_regular() True sage: g.is_vertex_transitive() True """ if sign in ["+", "-"]: s = 1 if sign == "+" else -1 if d % 2 == 1: raise ValueError("d must be even when sign!=None") else: if d % 2 == 0: raise ValueError("d must be odd when sign==None") s = 0 from sage.interfaces.gap import gap from sage.rings.finite_rings.constructor import FiniteField from sage.modules.free_module import VectorSpace from sage.matrix.constructor import Matrix from sage.libs.gap.libgap import libgap from itertools import combinations M = Matrix( libgap.InvariantQuadraticForm(libgap.GeneralOrthogonalGroup( s, d, q))['matrix']) F = libgap.GF(q).sage() V = list(VectorSpace(F, d)) G = Graph() G.add_vertices([tuple(_) for _ in V]) for x, y in combinations(V, 2): if not (x - y) * M * (x - y): G.add_edge(tuple(x), tuple(y)) G.name("Affine Polar Graph VO^" + str('+' if s == 1 else '-') + "(" + str(d) + "," + str(q) + ")") G.relabel() return G
def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): """ Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. EXAMPLES: Some infinite ones:: sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]]) sage: C.is_finite() # indirect doctest False sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) sage: C.is_finite() # indirect doctest False Some finite ones:: sage: m = matrix(CoxeterMatrix(['D', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: m = matrix(CoxeterMatrix(['H', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10] sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10] sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6] sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7] sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8] sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4] sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2] sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 3] sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() Coxeter type of ['I', 100] Some affine graphs:: sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 1, 1] sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10, 1] sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10, 1] sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['C', 10, 1] sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10, 1] sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6, 1] sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7, 1] sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8, 1] sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4, 1] sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2, 1] TESTS: Check that we detect relabellings:: sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c']) sage: M.coxeter_type() Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'} sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix sage: for C in CoxeterMatrix.samples(): ....: relabelling_perm = Permutations(C.index_set()).random_element() ....: relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())} ....: relabeled_matrix = C.relabel(relabelling_dict)._matrix ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm) ....: if C.is_finite() or C.is_affine(): ....: assert recognized_type == C.coxeter_type() We check the rank 2 cases (:trac:`20419`):: sage: for i in range(2, 10): ....: M = matrix([[1,i],[i,1]]) ....: CoxeterMatrix(M).coxeter_type() Coxeter type of A1xA1 relabelled by {1: 2} Coxeter type of ['A', 2] Coxeter type of ['B', 2] Coxeter type of ['I', 5] Coxeter type of ['G', 2] Coxeter type of ['I', 7] Coxeter type of ['I', 8] Coxeter type of ['I', 9] sage: CoxeterMatrix(matrix([[1,-1],[-1,1]]), index_set=[0,1]).coxeter_type() Coxeter type of ['A', 1, 1] """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) G = Graph( [ [index_set[i], index_set[j], coxeter_matrix[i, j]] for i in range(n) for j in range(i, n) if coxeter_matrix[i, j] not in [1, 2] ] ) G.add_vertices(index_set) types = [] for S in G.connected_components_subgraphs(): r = S.num_verts() # Handle the special cases first if r == 1: types.append(CoxeterType(["A", 1]).relabel({1: S.vertices()[0]})) continue if r == 2: # Type B2, G2, or I_2(p) e = S.edge_labels()[0] if e == 3: # Can't be 2 because it is connected ct = CoxeterType(["A", 2]) elif e == 4: ct = CoxeterType(["B", 2]) elif e == 6: ct = CoxeterType(["G", 2]) elif e > 0 and e < float("inf"): # Remaining non-affine types ct = CoxeterType(["I", e]) else: # Otherwise it is infinite dihedral group Z_2 \ast Z_2 ct = CoxeterType(["A", 1, 1]) if not ct.is_affine(): types.append(ct.relabel({1: S.vertices()[0], 2: S.vertices()[1]})) else: types.append(ct.relabel({0: S.vertices()[0], 1: S.vertices()[1]})) continue test = [["A", r], ["B", r], ["A", r - 1, 1]] if r >= 3: if r == 3: test += [["G", 2, 1], ["H", 3]] test.append(["C", r - 1, 1]) if r >= 4: if r == 4: test += [["F", 4], ["H", 4]] test += [["D", r], ["B", r - 1, 1]] if r >= 5: if r == 5: test.append(["F", 4, 1]) test.append(["D", r - 1, 1]) if r == 6: test.append(["E", 6]) elif r == 7: test += [["E", 7], ["E", 6, 1]] elif r == 8: test += [["E", 8], ["E", 7, 1]] elif r == 9: test.append(["E", 8, 1]) found = False for ct in test: ct = CoxeterType(ct) T = ct.coxeter_graph() iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if not found: return None return CoxeterType(types)
def RandomBipartite(n1, n2, p): r""" Returns a bipartite graph with `n1+n2` vertices such that any edge from `[n1]` to `[n2]` exists with probability `p`. INPUT: - ``n1,n2`` : Cardinalities of the two sets - ``p`` : Probability for an edge to exist EXAMPLE:: sage: g=graphs.RandomBipartite(5,2,0.5) sage: g.vertices() [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)] TESTS:: sage: g=graphs.RandomBipartite(5,-3,0.5) Traceback (most recent call last): ... ValueError: n1 and n2 should be integers strictly greater than 0 sage: g=graphs.RandomBipartite(5,3,1.5) Traceback (most recent call last): ... ValueError: Parameter p is a probability, and so should be a real value between 0 and 1 Trac ticket #12155:: sage: graphs.RandomBipartite(5,6,.2).complement() complement(Random bipartite graph of size 5+6 with edge probability 0.200000000000000): Graph on 11 vertices """ if not (p >= 0 and p <= 1): raise ValueError, "Parameter p is a probability, and so should be a real value between 0 and 1" if not (n1 > 0 and n2 > 0): raise ValueError, "n1 and n2 should be integers strictly greater than 0" from numpy.random import uniform from sage.graphs.all import Graph g = Graph(name="Random bipartite graph of size " + str(n1) + "+" + str(n2) + " with edge probability " + str(p)) S1 = [(0, i) for i in range(n1)] S2 = [(1, i) for i in range(n2)] g.add_vertices(S1) g.add_vertices(S2) for w in range(n2): for v in range(n1): if uniform() <= p: g.add_edge((0, v), (1, w)) pos = {} for i in range(n1): pos[(0, i)] = (0, i / (n1 - 1.0)) for i in range(n2): pos[(1, i)] = (1, i / (n2 - 1.0)) g.set_pos(pos) return g
def dual_equivalence_class(self, index_set=None): r""" Return the dual equivalence class indexed by ``index_set`` of ``self``. The dual equivalence class of an element `b \in B` is the set of all elements of `B` reachable from `b` via sequences of `i`-elementary dual equivalence relations (i.e., `i`-elementary dual equivalence transformations and their inverses) for `i` in the index set of `B`. For this to be well-defined, the element `b` has to be of weight `0` with respect to `I`; that is, we need to have `\varepsilon_j(b) = \varphi_j(b)` for all `j \in I`. See [Assaf08]_. See also :meth:`dual_equivalence_graph` for a definition of `i`-elementary dual equivalence transformations. INPUT: - ``index_set`` -- (optional) the index set `I` (default: the whole index set of the crystal); this has to be a subset of the index set of the crystal (as a list or tuple) OUTPUT: The dual equivalence class of ``self`` indexed by the subset ``index_set``. This class is returned as an undirected edge-colored multigraph. The color of an edge is the index `i` of the dual equivalence relation it encodes. .. SEEALSO:: - :meth:`~sage.categories.regular_crystals.RegularCrystals.ParentMethods.dual_equivalence_graph` - :meth:`sage.combinat.partition.Partition.dual_equivalence_graph` EXAMPLES:: sage: T = crystals.Tableaux(['A',3], shape=[2,2]) sage: G = T(2,1,4,3).dual_equivalence_class() sage: sorted(G.edges()) [([[1, 3], [2, 4]], [[1, 2], [3, 4]], 2), ([[1, 3], [2, 4]], [[1, 2], [3, 4]], 3)] sage: T = crystals.Tableaux(['A',4], shape=[3,2]) sage: G = T(2,1,4,3,5).dual_equivalence_class() sage: sorted(G.edges()) [([[1, 3, 5], [2, 4]], [[1, 3, 4], [2, 5]], 4), ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 2), ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 3), ([[1, 3, 4], [2, 5]], [[1, 2, 4], [3, 5]], 2), ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 3), ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 4)] """ if index_set is None: index_set = self.index_set() for i in index_set: if self.epsilon(i) != self.phi(i): raise ValueError("the element is not weight 0") visited = set([]) todo = set([self]) edges = [] while todo: x = todo.pop() visited.add(x) for k, i in enumerate(index_set[1:]): im = index_set[k] if x.epsilon(i) == 1 and x.epsilon(im) == 0: y = x.e(i).e(im).f(i).f(im) if [y, x, i] not in edges: edges.append([x, y, i]) if y not in visited: todo.add(y) if x.epsilon(i) == 0 and x.epsilon(im) == 1: y = x.e(im).e(i).f(im).f(i) if [y, x, i] not in edges: edges.append([x, y, i]) if y not in visited: todo.add(y) from sage.graphs.graph import Graph G = Graph(edges, multiedges=True) G.add_vertices(visited) if have_dot2tex(): G.set_latex_options( format="dot2tex", edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) return G