def __iter__(self): """ Iterate over ``self``. EXAMPLES:: sage: G = SymmetricGroup(4) sage: C = G.conjugacy_class(Partition([3,1])) sage: for x in C: x (2,3,4) (2,4,3) (1,3,4) (1,4,3) (1,2,4) (1,4,2) (1,2,3) (1,3,2) """ if self._set: for x in self._set: yield x return for x in conjugacy_class_iterator(self._part, self._parent.domain()): yield PermutationGroupElement(x, self._parent, check=False)
def perm_to_permutation(l): r""" Returns a permutation on `[1, n]` from a list on `[0, n-1]` EXAMPLES:: sage: from surface_dynamics.misc.permutation import perm_to_permutation sage: perm_to_permutation([2,1,0]) (1,3) """ from sage.groups.perm_gps.permgroup_element import PermutationGroupElement return PermutationGroupElement(map(lambda x: x + 1, l))
def __cmp__(self, other): r""" Compare self to other. For some bizarre reason, if you just let it inherit the cmp routine from PermutationGroupElement, cmp(x, y) works but sorting lists doesn't. TEST:: sage: K.<a> = NumberField(x^6 + 40*x^3 + 1372);G = K.galois_group() sage: sorted([G.artin_symbol(Q) for Q in K.primes_above(5)]) [(1,3)(2,6)(4,5), (1,2)(3,4)(5,6), (1,5)(2,4)(3,6)] """ return PermutationGroupElement.__cmp__(self, other)
def __cmp__(self, other): r""" Compare self to other. For some bizarre reason, if you just let it inherit the cmp routine from PermutationGroupElement, cmp(x, y) works but sorting lists doesn't. TEST:: sage: K.<a> = NumberField(x^6 + 40*x^3 + 1372);G = K.galois_group() sage: sorted([G.artin_symbol(Q) for Q in K.primes_above(5)]) [(1,3)(2,6)(4,5), (1,2)(3,4)(5,6), (1,5)(2,4)(3,6)] """ return PermutationGroupElement.__cmp__(self, other)
def set(self): r""" The set of all elements in the conjugacy class ``self``. EXAMPLES:: sage: G = SymmetricGroup(3) sage: g = G((1,2)) sage: C = G.conjugacy_class(g) sage: S = [(2,3), (1,2), (1,3)] sage: C.set() == Set(G(x) for x in S) True """ if not self._set: self._set = Set(PermutationGroupElement(x, self._parent, check=False) for x in conjugacy_class_iterator(self._part, self._domain) ) return self._set
def _tableau_dict(self): r""" A dictionary pairing the vertices of the underlying Yang-Baxter graph with standard tableau. EXAMPLES:: sage: orth = SymmetricGroupRepresentation([3,2], "orthogonal") sage: orth._tableau_dict {(0, 2, 1, -1, 0): [[1, 3, 4], [2, 5]], (2, 0, -1, 1, 0): [[1, 2, 5], [3, 4]], (2, 0, 1, -1, 0): [[1, 3, 5], [2, 4]], (0, 2, -1, 1, 0): [[1, 2, 4], [3, 5]], (0, -1, 2, 1, 0): [[1, 2, 3], [4, 5]]} """ # construct a dictionary pairing vertices with tableau t = StandardTableaux(self._partition).last() tableau_dict = {self._yang_baxter_graph.root():t} for (u,w,(i,beta)) in self._yang_baxter_graph._edges_in_bfs(): # TODO: improve the following si = PermutationGroupElement((i,i+1)) tableau_dict[w] = Tableau([map(si, row) for row in tableau_dict[u]]) return tableau_dict
def default_representative(part, G): r""" Construct the default representative for the conjugacy class of cycle type ``part`` of a symmetric group ``G``. Let `\lambda` be a partition of `n`. We pick a representative by .. MATH:: (1, 2, \ldots, \lambda_1) (\lambda_1 + 1, \ldots, \lambda_1 + \lambda_2) (\lambda_1 + \lambda_2 + \cdots + \lambda_{\ell-1}, \ldots, n), where `\ell` is the length (or number of parts) of `\lambda`. INPUT: - ``part`` -- partition - ``G`` -- a symmetric group EXAMPLES:: sage: from sage.groups.perm_gps.symgp_conjugacy_class import default_representative sage: S = SymmetricGroup(4) sage: for p in Partitions(4): ....: print default_representative(p, S) (1,2,3,4) (1,2,3) (1,2)(3,4) (1,2) () """ D = G.domain() total = 0 cycles = [] for p in part: cycles.append(tuple(D[total:total+p])) total += p # TODO: Change this to G.element_class(cycles, check=False) # once SymmetricGroup is a proper parent. return PermutationGroupElement(cycles, G, check=False)
def extrude_edge(self, vertex, dart1, dart2): r""" Return a ribbon graph resulting from extruding an edge from a vertex, pulling from it, all darts from ``dart1`` to ``dart2`` including both. INPUT: - ``vertex`` -- the position of the vertex in the permutation `\sigma`, which must have valency at least 2 - ``dart1`` -- the position of the first in the cycle corresponding to ``vertex`` - ``dart2`` -- the position of the second dart in the cycle corresponding to ``vertex`` OUTPUT: A ribbon graph resulting from extruding a new edge that pulls from ``vertex`` a new vertex that is, now, adjacent to all the darts from ``dart1``to ``dart2`` (not including ``dart2``) in the cyclic ordering given by the cycle corresponding to ``vertex``. Note that ``dart1`` may be equal to ``dart2`` allowing thus to extrude a contractible edge from a vertex. EXAMPLES: We try several possibilities in the same graph:: sage: s1 = PermutationGroupElement('(1,3,5)(2,4,6)') sage: r1 = PermutationGroupElement('(1,2)(3,4)(5,6)') sage: R1 = RibbonGraph(s1,r1); R1 Ribbon graph of genus 1 and 1 boundary components sage: E1 = R1.extrude_edge(1,1,2); E1 Ribbon graph of genus 1 and 1 boundary components sage: E1.sigma() (1,3,5)(2,8,6)(4,7) sage: E1.rho() (1,2)(3,4)(5,6)(7,8) sage: E2 = R1.extrude_edge(1,1,3); E2 Ribbon graph of genus 1 and 1 boundary components sage: E2.sigma() (1,3,5)(2,8)(4,6,7) sage: E2.rho() (1,2)(3,4)(5,6)(7,8) We can also extrude a contractible edge from a vertex. This new edge will end at a vertex of valency 1:: sage: E1p = R1.extrude_edge(0,0,0); E1p Ribbon graph of genus 1 and 1 boundary components sage: E1p.sigma() (1,3,5,8)(2,4,6) sage: E1p.rho() (1,2)(3,4)(5,6)(7,8) In the following example we first extrude one edge from a vertex of valency 3 generating a new vertex of valency 2. Then we extrude a new edge from this vertex of valency 2:: sage: s1 = PermutationGroupElement('(1,3,5)(2,4,6)') sage: r1 = PermutationGroupElement('(1,2)(3,4)(5,6)') sage: R1 = RibbonGraph(s1,r1); R1 Ribbon graph of genus 1 and 1 boundary components sage: E1 = R1.extrude_edge(0,0,1); E1 Ribbon graph of genus 1 and 1 boundary components sage: E1.sigma() (1,7)(2,4,6)(3,5,8) sage: E1.rho() (1,2)(3,4)(5,6)(7,8) sage: F1 = E1.extrude_edge(0,0,1); F1 Ribbon graph of genus 1 and 1 boundary components sage: F1.sigma() (1,9)(2,4,6)(3,5,8)(7,10) sage: F1.rho() (1,2)(3,4)(5,6)(7,8)(9,10) """ #We first compute the vertices of valency 1 as in _repr_ repr_sigma = [list(x) for x in self._sigma.cycle_tuples()] repr_rho = [list(x) for x in self._rho.cycle_tuples()] darts_rho = flatten(repr_rho) darts_sigma = flatten(repr_sigma) val_one = [x for x in darts_rho if x not in darts_sigma] for val in val_one: repr_sigma += [[val]] # We find which is the highes value a dart has, in order to # add new darts that do not conflict with previous ones. k = max(darts_rho) # We create the new vertex and append it to sigma. new_vertex = [repr_sigma[vertex][j] for j in range(dart1, dart2)] new_vertex.insert(0, k + 1) repr_sigma.append(new_vertex) # We add the new dart at the vertex from which we are extruding # an edge. Also we delete the darts that have been extruded. repr_sigma[vertex].insert(dart1, k + 2) del repr_sigma[vertex][dart1 + 1:dart2 + 1] #We update rho repr_rho.append([k + 1, k + 2]) perm_group = self._sigma.parent() return RibbonGraph( PermutationGroupElement([tuple(x) for x in repr_sigma]), PermutationGroupElement([tuple(x) for x in repr_rho]))
def contract_edge(self, k): r""" Return the ribbon graph resulting from the contraction of the ``k``-th edge in ``self``. For a ribbon graph `(\sigma, \rho)`, we contract the edge corresponding to the `k`-th transposition of `\rho`. INPUT: - ``k`` -- non-negative integer; the position in `\rho` of the transposition that is going to be contracted OUTPUT: - a ribbon graph resulting from the contraction of that edge EXAMPLES: We start again with the one-holed torus ribbon graph:: sage: s1 = PermutationGroupElement('(1,3,5)(2,4,6)') sage: r1 = PermutationGroupElement('(1,2)(3,4)(5,6)') sage: R1 = RibbonGraph(s1,r1); R1 Ribbon graph of genus 1 and 1 boundary components sage: S1 = R1.contract_edge(1); S1 Ribbon graph of genus 1 and 1 boundary components sage: S1.sigma() (1,6,2,5) sage: S1.rho() (1,2)(5,6) However, this ribbon graphs is formed only by loops and hence it cannot be longer reduced, we get an error if we try to contract a loop:: sage: S1.contract_edge(1) Traceback (most recent call last): ... ValueError: the edge is a loop and cannot be contracted In this example, we consider a graph that has one edge ``(19,20)`` such that one of its ends is a vertex of valency 1. This is the vertex ``(20)`` that is not specified when defining `\sigma`. We contract precisely this edge and get a ribbon graph with no vertices of valency 1:: sage: s2 = PermutationGroupElement('(1,2,3)(4,5,6)(7,8,9)(10,11,12)(13,14,15)(16,17,18,19)') sage: r2 = PermutationGroupElement('(1,16)(2,13)(3,10)(4,17)(5,14)(6,11)(7,18)(8,15)(9,12)(19,20)') sage: R2 = RibbonGraph(s2,r2); R2 Ribbon graph of genus 1 and 3 boundary components sage: R2.sigma() (1,2,3)(4,5,6)(7,8,9)(10,11,12)(13,14,15)(16,17,18,19) sage: R2c = R2.contract_edge(9); R2; R2c.sigma(); R2c.rho() Ribbon graph of genus 1 and 3 boundary components (1,2,3)(4,5,6)(7,8,9)(10,11,12)(13,14,15)(16,17,18) (1,16)(2,13)(3,10)(4,17)(5,14)(6,11)(7,18)(8,15)(9,12) """ #the following two lines convert the list of tuples to list of lists aux_sigma = [ list(x) for x in self._sigma.cycle_tuples(singletons=True) ] aux_rho = [list(x) for x in self._rho.cycle_tuples()] #The following ''if'' rules out the cases when we would be #contracting a loop (which is not admissible since we would #lose the topological type of the graph). if (_find(aux_sigma, aux_rho[k][0])[0] == _find(aux_sigma, aux_rho[k][1])[0]): raise ValueError("the edge is a loop and cannot be contracted") #We store in auxiliary variables the positions of the vertices #that are the ends of the edge to be contracted and we delete #from them the darts corresponding to the edge that is going #to be contracted. We also delete the contracted edge #from aux_rho pos1 = _find(aux_sigma, aux_rho[k][0]) pos2 = _find(aux_sigma, aux_rho[k][1]) del aux_sigma[pos1[0]][pos1[1]] del aux_sigma[pos2[0]][pos2[1]] del aux_rho[k] #Now we insert in one of the two vertices, the darts of the other #vertex that appears after. We make sure that we don't #change the topological type of the thickening of the graph by #preserving the cyclic ordering. n = len(aux_sigma[pos2[0]]) for i in range(n): aux_sigma[pos1[0]].insert(pos1[1] + i, aux_sigma[pos2[0]][(pos2[1] + i) % n]) #Finally we delete the vertex from which we copied all the darts. del aux_sigma[pos2[0]] #Now we convert this data that is on the form of lists of lists #to actual permutations that form a ribbon graph. return RibbonGraph( PermutationGroupElement([tuple(x) for x in aux_sigma]), PermutationGroupElement([tuple(x) for x in aux_rho]))
def bipartite_ribbon_graph(p, q): r""" Return the bipartite graph modeling the corresponding Brieskorn-Pham singularity. Take two parallel lines in the plane, and consider `p` points in one of them and `q` points in the other. Join with a line each point from the first set with every point with the second set. The resulting is a planar projection of the complete bipartite graph of type `(p,q)`. If you consider the cyclic ordering at each vertex induced by the positive orientation of the plane, the result is a ribbon graph whose associated orientable surface with boundary is homeomorphic to the Milnor fiber of the Brieskorn-Pham singularity `x^p + y^q`. It satisfies that it has `\gcd(p,q)` number of boundary components and genus `(pq - p - q - \gcd(p,q) - 2) / 2`. INPUT: - ``p`` -- a positive integer - ``q`` -- a positive integer EXAMPLES:: sage: B23 = RibbonGraph(2,3,bipartite=True); B23; B23.sigma(); B23.rho() Ribbon graph of genus 1 and 1 boundary components (1,2,3)(4,5,6)(7,8)(9,10)(11,12) (1,8)(2,10)(3,12)(4,7)(5,9)(6,11) sage: B32 = RibbonGraph(3,2,bipartite=True); B32; B32.sigma(); B32.rho() Ribbon graph of genus 1 and 1 boundary components (1,2)(3,4)(5,6)(7,8,9)(10,11,12) (1,9)(2,12)(3,8)(4,11)(5,7)(6,10) sage: B33 = RibbonGraph(3,3,bipartite=True); B33; B33.sigma(); B33.rho() Ribbon graph of genus 1 and 3 boundary components (1,2,3)(4,5,6)(7,8,9)(10,11,12)(13,14,15)(16,17,18) (1,12)(2,15)(3,18)(4,11)(5,14)(6,17)(7,10)(8,13)(9,16) sage: B24 = RibbonGraph(2,4,bipartite=True); B24; B24.sigma(); B24.rho() Ribbon graph of genus 1 and 2 boundary components (1,2,3,4)(5,6,7,8)(9,10)(11,12)(13,14)(15,16) (1,10)(2,12)(3,14)(4,16)(5,9)(6,11)(7,13)(8,15) sage: B47 = RibbonGraph(4,7, bipartite=True); B47; B47.sigma(); B47.rho() Ribbon graph of genus 9 and 1 boundary components (1,2,3,4,5,6,7)(8,9,10,11,12,13,14)(15,16,17,18,19,20,21)(22,23,24,25,26,27,28)(29,30,31,32)(33,34,35,36)(37,38,39,40)(41,42,43,44)(45,46,47,48)(49,50,51,52)(53,54,55,56) (1,32)(2,36)(3,40)(4,44)(5,48)(6,52)(7,56)(8,31)(9,35)(10,39)(11,43)(12,47)(13,51)(14,55)(15,30)(16,34)(17,38)(18,42)(19,46)(20,50)(21,54)(22,29)(23,33)(24,37)(25,41)(26,45)(27,49)(28,53) """ sigma = [] rho = [] for i in range(p): aux_tuple = [i * q + j + 1 for j in range(q)] sigma += [aux_tuple] for i in range(q): aux_tuple = [p * q + i * p + j + 1 for j in range(p)] sigma += [aux_tuple] for i in range(p * q): if (i + 1) % q == 0: k = q elif (i + 1) % q != 0: k = (i + 1) % q t = 0 if (i + 1) % q != 0: t = 1 aux_edge = [i + 1, p * q + k * p - ((i + 1 + t * q) / q).floor() + 1] rho += [aux_edge] return RibbonGraph(PermutationGroupElement([tuple(x) for x in sigma]), PermutationGroupElement([tuple(x) for x in rho]))
def make_ribbon(g, r): r""" Return a ribbon graph whose thickening has genus ``g`` and ``r`` boundary components. INPUT: - ``g`` -- non-negative integer representing the genus of the thickening - ``r`` -- positive integer representing the number of boundary components of the thickening OUTPUT: - a ribbon graph that has 2 vertices (two non-trivial cycles in its sigma permutation) of valency `2g + r` and it has `2g + r` edges (and hence `4g + 2r` darts) EXAMPLES:: sage: from sage.geometry.ribbon_graph import make_ribbon sage: R = make_ribbon(0,1); R Ribbon graph of genus 0 and 1 boundary components sage: R.sigma() () sage: R.rho() (1,2) sage: R = make_ribbon(0,5); R Ribbon graph of genus 0 and 5 boundary components sage: R.sigma() (1,9,7,5,3)(2,4,6,8,10) sage: R.rho() (1,2)(3,4)(5,6)(7,8)(9,10) sage: R = make_ribbon(1,1); R Ribbon graph of genus 1 and 1 boundary components sage: R.sigma() (1,2,3)(4,5,6) sage: R.rho() (1,4)(2,5)(3,6) sage: R = make_ribbon(7,3); R Ribbon graph of genus 7 and 3 boundary components sage: R.sigma() (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,33,31)(16,32,34,17,18,19,20,21,22,23,24,25,26,27,28,29,30) sage: R.rho() (1,16)(2,17)(3,18)(4,19)(5,20)(6,21)(7,22)(8,23)(9,24)(10,25)(11,26)(12,27)(13,28)(14,29)(15,30)(31,32)(33,34) """ #Initialize the two vertices of sigma and the edge joining them repr_sigma = [[1], [2 * g + 2]] repr_rho = [[1, 2 * g + 2]] #We first generate the surface of genus g and 1 boundary component. #This is done by considering the usual planar representation of #a surface as a polygon of 4*g+2 edges with identifications. (see #any topology book on the classification of surfaces) for i in range(2 * g): repr_sigma[0].append(i + 2) repr_sigma[1].append(i + (2 * g + 2) + 1) repr_rho += [[i + 2, i + (2 * g + 2) + 1]] #finally we add an edge for each additional boundary component. max_dart = 4 * g + 2 for j in range(r - 1): repr_sigma[0].insert(0, max_dart + 2 * (j + 1) - 1) repr_sigma[1].insert(j + 1, max_dart + 2 * (j + 1)) repr_rho += [[max_dart + 2 * (j + 1) - 1, max_dart + 2 * (j + 1)]] return RibbonGraph(PermutationGroupElement([tuple(x) for x in repr_sigma]), PermutationGroupElement([tuple(x) for x in repr_rho]))
def normalize(self): r""" Return an equivalent graph such that the enumeration of its darts exhausts all numbers from 1 to the number of darts. OUTPUT: - a ribbon graph equivalent to ``self`` such that the enumeration of its darts exhausts all numbers from 1 to the number of darts. EXAMPLES:: sage: s0 = PermutationGroupElement('(1,22,3,4,5,6,7,15)(8,16,9,10,11,12,13,14)') sage: r0 = PermutationGroupElement('(1,8)(22,9)(3,10)(4,11)(5,12)(6,13)(7,14)(15,16)') sage: R0 = RibbonGraph(s0,r0); R0 Ribbon graph of genus 3 and 2 boundary components sage: RN0 = R0.normalize(); RN0; RN0.sigma(); RN0.rho() Ribbon graph of genus 3 and 2 boundary components (1,16,2,3,4,5,6,14)(7,15,8,9,10,11,12,13) (1,7)(2,9)(3,10)(4,11)(5,12)(6,13)(8,16)(14,15) sage: s1 = PermutationGroupElement('(5,10,12)(30,34,78)') sage: r1 = PermutationGroupElement('(5,30)(10,34)(12,78)') sage: R1 = RibbonGraph(s1,r1); R1 Ribbon graph of genus 1 and 1 boundary components sage: RN1 = R1.normalize(); RN1; RN1.sigma(); RN1.rho() Ribbon graph of genus 1 and 1 boundary components (1,2,3)(4,5,6) (1,4)(2,5)(3,6) """ #First we compute the vertices of valency 1 and store them in val_one. aux_sigma = [list(x) for x in self._sigma.cycle_tuples()] aux_rho = [list(x) for x in self._rho.cycle_tuples()] darts_rho = flatten(aux_rho) darts_sigma = flatten(aux_sigma) val_one = [x for x in darts_rho if x not in darts_sigma] #We add them to aux_sigma for i in range(len(val_one)): aux_sigma += [[val_one[i]]] #Now we proceed to normalize the numbers enumerating the darts. #We do this by checking if every number from 1 to len(darts_rho) #is actually in darts_rho. for i in range(len(darts_rho)): found = i + 1 in darts_rho #if a value is not in darts_rho, we take the next number that appears #and change it to the new value. if not found: aux_val = min(x for x in darts_rho if x > i + 1) pos_darts = darts_rho.index(aux_val) pos_rho = _find(aux_rho, aux_val) pos_sigma = _find(aux_sigma, aux_val) #Now we set the found positions to the new normalized value darts_rho[pos_darts] = i + 1 aux_sigma[pos_sigma[0]][pos_sigma[1]] = i + 1 aux_rho[pos_rho[0]][pos_rho[1]] = i + 1 return RibbonGraph( PermutationGroupElement([tuple(x) for x in aux_sigma]), PermutationGroupElement([tuple(x) for x in aux_rho]))