def reflection_group(self, type="matrix"): """ Return the reflection group corresponding to ``self``. EXAMPLES:: sage: C = CartanMatrix(['A',3]) sage: C.reflection_group() Weyl Group of type ['A', 3] (as a matrix group acting on the root space) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup RS = self.root_space() G = RS.weyl_group() if type == "matrix": return G elif type == "permutation": assert G.is_finite() Phi = RS.roots() gens = {} S = SymmetricGroup(len(Phi)) for i in self.index_set(): pi = S([ Phi.index( beta.simple_reflection(i) ) + 1 for beta in Phi ]) gens[i] = pi return S.subgroup( gens[i] for i in gens ) else: raise ValueError("The reflection group is only available as a matrix group or as a permutation group.")
def reflection_group(self, type="matrix"): """ Return the reflection group corresponding to ``self``. EXAMPLES:: sage: C = CartanMatrix(['A',3]) sage: C.reflection_group() Weyl Group of type ['A', 3] (as a matrix group acting on the root space) """ RS = self.root_space() if type == "matrix": return RS.weyl_group() if type == "permutation": if not self.is_finite(): raise ValueError("only works for finite types") Phi = RS.roots() gens = {} from sage.groups.perm_gps.permgroup_named import SymmetricGroup S = SymmetricGroup(len(Phi)) for i in self.index_set(): pi = S( [Phi.index(beta.simple_reflection(i)) + 1 for beta in Phi]) gens[i] = pi return S.subgroup(gens[i] for i in gens) raise ValueError( "The reflection group is only available as a matrix group or as a permutation group." )
def _generate_decreasing_hecke_factorizations(w, factors, ex, weight=None, parent=None): """ Generate all decreasing factorizations of word ``w`` in a 0-Hecke monoid with fixed excess and number of factors. INPUT: - ``w`` -- a reduced word, expressed as an iterable - ``factors`` -- number of factors for each decreasing factorization - ``ex`` -- number of extra letters in each decreasing factorizations - ``weight`` -- (default: None) if None, returns all possible decreasing factorizations, otherwise return all those with the specified weight EXAMPLES:: sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import _generate_decreasing_hecke_factorizations sage: _generate_decreasing_hecke_factorizations([1, 2, 1], 3, 1) [()(2, 1)(2, 1), (2)(1)(2, 1), (1)(2)(2, 1), (1)(1)(2, 1), (2, 1)()(2, 1), (2)(2, 1)(2), (1)(2, 1)(2), (1)(2, 1)(1), (2, 1)(2)(2), (2, 1)(2)(1), (2, 1)(1)(2), (2, 1)(2, 1)()] sage: _generate_decreasing_hecke_factorizations([1, 2, 1], 3, 1, weight=[1, 1, 2]) [(2, 1)(2)(2), (2, 1)(2)(1), (2, 1)(1)(2)] """ if parent is None: max_value = max(w) if w else 1 S = SymmetricGroup(max_value + 1) v = S.from_reduced_word(w) parent = DecreasingHeckeFactorizations(v, factors, ex) _canonical_word = lambda w, ex: [list(w)[0]] * ex + list(w) wt = lambda t: [len(factor) for factor in reversed(t)] L = _list_equivalent_words(_canonical_word(w, ex)) Factors = [] for word in L: F = _list_all_decreasing_runs(word, factors) for f in F: t = [[word[j] for j in range(len(word)) if f[j] == i] for i in range(factors, 0, -1)] if weight is None or weight == wt(t): Factors.append(parent.element_class(parent, t)) return sorted(Factors, reverse=True)
def __classcall_private__(self, t, max_value=None, parent=None): """ Assign the correct parent for ``t`` and call ``t`` as an element of that parent EXAMPLES:: sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import DecreasingHeckeFactorization sage: h1 = DecreasingHeckeFactorization([[3, 1], [], [3, 2]]) sage: h1.parent() Fully commutative stable Grothendieck crystal of type A_2 associated to [1, 3, 2] with excess 1 sage: h2 = DecreasingHeckeFactorization(h1) sage: h1 == h2 True sage: h1 = DecreasingHeckeFactorization([[3, 1], [2, 1], [2, 1]]) sage: F = h1.parent(); F Decreasing Hecke factorizations with 3 factors associated to [1, 3, 2, 1] with excess 2 sage: h2 = F(h1) sage: h1 == h2 True TESTS:: sage: DecreasingHeckeFactorization([[]]) () """ _check_decreasing_hecke_factorization(t) if isinstance(t, DecreasingHeckeFactorization): u = t.value if parent is None: parent = t.parent() else: u = t if parent is None: if max_value is None: letters = [x for factor in t for x in factor] max_value = max(letters) if letters else 1 from sage.monoids.hecke_monoid import HeckeMonoid S = SymmetricGroup(max_value + 1) H = HeckeMonoid(S) word = H.from_reduced_word(x for factor in t for x in factor).reduced_word() factors = len(t) excess = sum(len(l) for l in t) - len(word) p = permutation.from_reduced_word(word) if p.has_pattern([3, 2, 1]): word = S.from_reduced_word(word) parent = DecreasingHeckeFactorizations( word, factors, excess) else: word = S.from_reduced_word(word) parent = FullyCommutativeStableGrothendieckCrystal( word, factors, excess) return parent.element_class(parent, u)
def SymmetricPresentation(n): r""" Build the Symmetric group of order `n!` as a finitely presented group. INPUT: - ``n`` -- The size of the underlying set of arbitrary symbols being acted on by the Symmetric group of order `n!`. OUTPUT: Symmetric group as a finite presentation, implementation uses GAP to find an isomorphism from a permutation representation to a finitely presented group representation. Due to this fact, the exact output presentation may not be the same for every method call on a constant ``n``. EXAMPLES:: sage: S4 = groups.presentation.Symmetric(4) sage: S4.as_permutation_group().is_isomorphic(SymmetricGroup(4)) True TESTS:: sage: S = [groups.presentation.Symmetric(i) for i in range(1,4)]; S[0].order() 1 sage: S[1].order(), S[2].as_permutation_group().is_isomorphic(DihedralGroup(3)) (2, True) sage: S5 = groups.presentation.Symmetric(5) sage: perm_S5 = S5.as_permutation_group(); perm_S5.is_isomorphic(SymmetricGroup(5)) True sage: groups.presentation.Symmetric(8).order() 40320 """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.free_group import _lexi_gen n = Integer(n) perm_rep = SymmetricGroup(n) GAP_fp_rep = libgap.Image( libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens())) image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) ret_rls = tuple([ F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup() ]) return FinitelyPresentedGroup(F, ret_rls)
def gens(self): r""" Return a tuple of generators of ``self``. EXAMPLES:: sage: F.<a> = GF(4) sage: SemimonomialTransformationGroup(F, 3).gens() [((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (1,2,3), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (1,2), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a + 1)] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup R = self.base_ring() l = [ self(v=([R.primitive_element()] + [R.one()] * (self.degree() - 1))) ] for g in SymmetricGroup(self.degree()).gens(): l.append(self(perm=Permutation(g))) if R.is_field() and not R.is_prime_field(): l.append( self(autom=R.hom([R.primitive_element()**R.characteristic()]))) return l
def antisymmetrized_coordinate_sums(dim, n): """ Return formal anti-symmetrized sum of multi-indices INPUT: - ``dim`` -- integer. The dimension (range of each index). - ``n`` -- integer. The total number of indices. OUTPUT: An anti-symmetrized formal sum of multi-indices (tuples of integers) EXAMPLES:: sage: from sage.modules.tensor_operations import antisymmetrized_coordinate_sums sage: antisymmetrized_coordinate_sums(3, 2) ((0, 1) - (1, 0), (0, 2) - (2, 0), (1, 2) - (2, 1)) """ from sage.structure.formal_sum import FormalSum table = [] from sage.groups.perm_gps.permgroup_named import SymmetricGroup S_d = SymmetricGroup(n) from sage.combinat.combination import Combinations for i in Combinations(range(dim), n): i = tuple(i) x = [] for g in S_d: x.append([g.sign(), g(i)]) x = FormalSum(x) table.append(x) return tuple(table)
def automorphism_group(self): """ Returns the subgroup of the automorphism group of the incidence graph which respects the P B partition. This is (isomorphic to) the automorphism group of the block design, although the degrees differ. EXAMPLES:: sage: from sage.combinat.designs.block_design import BlockDesign sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) sage: G = BD.automorphism_group(); G Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)] sage: BD = BlockDesign(4,[[0],[0,1],[1,2],[3,3]],test=False) sage: G = BD.automorphism_group(); G Permutation Group with generators [()] sage: BD = BlockDesign(7,[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]]) sage: G = BD.automorphism_group(); G Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)] """ from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct from sage.groups.perm_gps.permgroup import PermutationGroup from sage.groups.perm_gps.permgroup_named import SymmetricGroup M1 = self.incidence_matrix() M2 = MatrixStruct(M1) M2.run() gens = M2.automorphism_group()[0] v = len(self.points()) G = SymmetricGroup(v) gns = [] for g in gens: L = [j+1 for j in g] gns.append(G(L)) return PermutationGroup(gns)
def SymmetricPresentation(n): r""" Build the Symmetric group of order `n!` as a finitely presented group. INPUT: - ``n`` -- The size of the underlying set of arbitrary symbols being acted on by the Symmetric group of order `n!`. OUTPUT: Symmetric group as a finite presentation, implementation uses GAP to find an isomorphism from a permutation representation to a finitely presented group representation. Due to this fact, the exact output presentation may not be the same for every method call on a constant ``n``. EXAMPLES:: sage: S4 = groups.presentation.Symmetric(4) sage: S4.as_permutation_group().is_isomorphic(SymmetricGroup(4)) True TESTS:: sage: S = [groups.presentation.Symmetric(i) for i in range(1,4)]; S[0].order() 1 sage: S[1].order(), S[2].as_permutation_group().is_isomorphic(DihedralGroup(3)) (2, True) sage: S5 = groups.presentation.Symmetric(5) sage: perm_S5 = S5.as_permutation_group(); perm_S5.is_isomorphic(SymmetricGroup(5)) True sage: groups.presentation.Symmetric(8).order() 40320 """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.free_group import _lexi_gen n = Integer(n) perm_rep = SymmetricGroup(n) GAP_fp_rep = libgap.Image(libgap.IsomorphismFpGroupByGenerators(perm_rep, perm_rep.gens())) image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) ret_rls = tuple( [F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()] ) return FinitelyPresentedGroup(F, ret_rls)
def _get_random_ribbon_graph(self): r""" Return a random ribbon graph with right parameters. """ n = random.randint(self.min_num_seps, self.max_num_seps) S = SymmetricGroup(2 * n) e = S([(2 * i + 1, 2 * i + 2) for i in range(n)]) f = S.random_element() P = PermutationGroup([e, f]) while not P.is_transitive(): f = S.random_element() P = PermutationGroup([e, f]) return RibbonGraph(edges=[e(i + 1) - 1 for i in range(2 * n)], faces=[f(i + 1) - 1 for i in range(2 * n)])
def _get_random_ribbon_graph(self): r""" Return a random ribbon graph with right parameters. """ n = random.randint(self.min_num_seps,self.max_num_seps) S = SymmetricGroup(2*n) e = S([(2*i+1,2*i+2) for i in xrange(n)]) f = S.random_element() P = PermutationGroup([e,f]) while not P.is_transitive(): f = S.random_element() P = PermutationGroup([e,f]) return RibbonGraph( edges=[e(i+1)-1 for i in xrange(2*n)], faces=[f(i+1)-1 for i in xrange(2*n)])
def group(self): """ Returns the underlying group EXAMPLES :: sage: SymmetricGroupAlgebra(QQ,4).group() Symmetric group of order 4! as a permutation group """ return SymmetricGroup(self.n)
def test2(): from sage.groups.perm_gps.permgroup_named import SymmetricGroup S = SymmetricGroup(3) r = S('(1,2)') u = S('(1,3)') o = translation_surfaces.origami(r, u) o.edit() se, sb = o.get_bundle() sb.set_transform(200, 300, 300) sb.redraw_all()
def to_character(self): r""" Return the character of the representation. EXAMPLES: The trivial character:: sage: rho = SymmetricGroupRepresentation([3]) sage: chi = rho.to_character(); chi Character of Symmetric group of order 3! as a permutation group sage: chi.values() [1, 1, 1] sage: all(chi(g) == 1 for g in SymmetricGroup(3)) True The sign character:: sage: rho = SymmetricGroupRepresentation([1,1,1]) sage: chi = rho.to_character(); chi Character of Symmetric group of order 3! as a permutation group sage: chi.values() [1, -1, 1] sage: all(chi(g) == g.sign() for g in SymmetricGroup(3)) True The defining representation:: sage: triv = SymmetricGroupRepresentation([4]) sage: hook = SymmetricGroupRepresentation([3,1]) sage: def_rep = lambda p : triv(p).block_sum(hook(p)).trace() sage: map(def_rep, Permutations(4)) [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0] sage: [p.to_matrix().trace() for p in Permutations(4)] [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup Sym = SymmetricGroup(sum(self._partition)) values = [ self(g).trace() for g in Sym.conjugacy_classes_representatives() ] return Sym.character(values)
def to_character(self): r""" Return the character of the representation. EXAMPLES: The trivial character:: sage: rho = SymmetricGroupRepresentation([3]) sage: chi = rho.to_character(); chi Character of Symmetric group of order 3! as a permutation group sage: chi.values() [1, 1, 1] sage: all(chi(g) == 1 for g in SymmetricGroup(3)) True The sign character:: sage: rho = SymmetricGroupRepresentation([1,1,1]) sage: chi = rho.to_character(); chi Character of Symmetric group of order 3! as a permutation group sage: chi.values() [1, -1, 1] sage: all(chi(g) == g.sign() for g in SymmetricGroup(3)) True The defining representation:: sage: triv = SymmetricGroupRepresentation([4]) sage: hook = SymmetricGroupRepresentation([3,1]) sage: def_rep = lambda p : triv(p).block_sum(hook(p)).trace() sage: map(def_rep, Permutations(4)) [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0] sage: [p.to_matrix().trace() for p in Permutations(4)] [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup Sym = SymmetricGroup(sum(self._partition)) values = [self(g).trace() for g in Sym.conjugacy_classes_representatives()] return Sym.character(values)
def an_instance(cls): """ Returns an instance of this class. EXAMPLES:: sage: Groupoid.an_instance() # indirect doctest Groupoid with underlying set Symmetric group of order 8! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup G = SymmetricGroup(8) return cls(G)
def _check_containment(t, parent): """ Check if ``t`` is an element of ``parent``. EXAMPLES:: sage: S = SymmetricGroup(3+1) sage: w = S.from_reduced_word([1, 3, 2]) sage: B = crystals.FullyCommutativeStableGrothendieck(w, 3, 2) sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import DecreasingHeckeFactorization, _check_containment sage: h1 = DecreasingHeckeFactorization([[3, 1], [3], [3, 2]], 4) sage: _check_containment(h1, B) sage: h2 = DecreasingHeckeFactorization([[3, 1], [3], [], [3, 2]]) sage: _check_containment(h2, B) Traceback (most recent call last): ... ValueError: number of factors do not match sage: h3 = [[3, 1], [2], [3, 2]] sage: _check_containment(h3, B) Traceback (most recent call last): ... ValueError: self and parent must be specified based on equivalent words sage: h4 = DecreasingHeckeFactorization([[3, 1], [3, 1], [3, 2]], 3) sage: _check_containment(h4, B) Traceback (most recent call last): ... ValueError: number of excess letters do not match """ if isinstance(t, DecreasingHeckeFactorization): factors = t.factors w = t.w excess = t.excess else: factors = len(t) max_value = parent.max_value from sage.monoids.hecke_monoid import HeckeMonoid H = HeckeMonoid(SymmetricGroup(max_value + 1)) w = tuple( H.from_reduced_word(x for factor in t for x in factor).reduced_word()) excess = sum(len(l) for l in t) - len(w) if factors != parent.factors: raise ValueError("number of factors do not match") if w != parent.w: raise ValueError( "self and parent must be specified based on equivalent words") if excess != parent.excess: raise ValueError("number of excess letters do not match")
def _get_random_cylinder_diagram(self): r""" Return a random cylinder diagram with right parameters """ test = False while test: n = random.randint(self.min_num_seps, self.max_num_seps) S = SymmetricGroup(2 * n) bot = S.random_element() b = [[i - 1 for i in c] for c in bot.cycle_tuples(singletons=True)] p = Partitions(2 * n, length=len(b)).random_element() top = S([i + 1 for i in canonical_perm(p)]) t = [[i - 1 for i in c] for c in top.cycle_tuples(singletons=True)] prandom.shuffle(t) c = CylinderDiagram(zip(b, t)) test = c.is_connected() return c
def _get_random_cylinder_diagram(self): r""" Return a random cylinder diagram with right parameters """ test = False while test: n = random.randint(self.min_num_seps,self.max_num_seps) S = SymmetricGroup(2*n) bot = S.random_element() b = [[i-1 for i in c] for c in bot.cycle_tuples(singletons=True)] p = Partitions(2*n,length=len(b)).random_element() top = S([i+1 for i in canonical_perm(p)]) t = [[i-1 for i in c] for c in top.cycle_tuples(singletons=True)] prandom.shuffle(t) c = CylinderDiagram(zip(b,t)) test = c.is_connected() return c
def an_instance(cls): """ Returns an instance of this class. EXAMPLES:: sage: GSets.an_instance() # indirect doctest Category of G-sets for Symmetric group of order 8! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup G = SymmetricGroup(8) return cls(G)
def __init__(self, G=None): """ TESTS:: sage: S8 = SymmetricGroup(8) sage: C = Groupoid(S8) sage: TestSuite(C).run() """ CategoryWithParameters.__init__(self) #, "Groupoid") if G is None: from sage.groups.perm_gps.permgroup_named import SymmetricGroup G = SymmetricGroup(8) self.__G = G
def _latex_(self): r""" Method for describing ``self`` in LaTeX. EXAMPLES:: sage: F.<a> = GF(4) sage: latex(SemimonomialTransformationGroup(F, 3)) # indirect doctest \left(\Bold{F}_{2^{2}}^3\wr\langle (1,2,3), (1,2) \rangle \right) \rtimes \operatorname{Aut}(\Bold{F}_{2^{2}}) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup ring_latex = self.base_ring()._latex_() return ('\\left(' + ring_latex + '^' + str(self.degree()) + '\\wr' + SymmetricGroup(self.degree())._latex_() + ' \\right) \\rtimes \operatorname{Aut}(' + ring_latex + ')')
def profile(self): r""" Return the profile of the surface. Return the list of angles of singularities in the surface divided by pi. EXAMPLES:: sage: from surface_dynamics.all import * sage: p = iet.Permutation('a b', 'b a') sage: p.cover(['(1,2)', '(1,3)']).profile() [6] sage: p.cover(['(1,2,3)','(1,4)']).profile() [6, 2] sage: p.cover(['(1,2,3)(4,5,6)','(1,4,7)(2,5)(3,6)']).profile() [6, 2, 2, 2, 2] sage: p = iet.GeneralizedPermutation('a a b', 'b c c') sage: p.cover(['(1,2)', '()', '(1,2)']).profile() [2, 2, 2, 2] """ from sage.combinat.partition import Partition from sage.groups.perm_gps.permgroup_named import SymmetricGroup s = [] base_diagram = self._base.interval_diagram(sign=True, glue_ends=True) p_id = SymmetricGroup(self._degree_cover).identity() for orbit in base_diagram: flat_orbit = [] for x in orbit: if isinstance(x[0], tuple): flat_orbit.extend(x) else: flat_orbit.append(x) p = p_id for lab,sign in flat_orbit: q = self.covering_data(lab) if sign: q = q.inverse() p = p*q for c in p.cycle_type(): s.append(len(orbit)*c) return Partition(sorted(s,reverse=True))
def random_permutation(self): r""" Return a random permutation of ``self``. """ from sage.misc.prandom import randint from sage.groups.perm_gps.permgroup_named import SymmetricGroup A = self.alphabet() P = A.positive_letters() s = SymmetricGroup(P).random_element() f = {} for a in P: if randint(0,1): f[a] = self([s(a)]) else: f[a] = self([A.inverse_letter(s(a))]) from free_group_automorphism import FreeGroupAutomorphism #this has to be here and not in the preamble to prevent loop on import statements return FreeGroupAutomorphism(f, group=self)
def __classcall_private__(cls, w, factors, excess, shape=False): """ Classcall to mend the input. EXAMPLES:: sage: A = crystals.FullyCommutativeStableGrothendieck([[3, 3], [2, 1]], 4, 1, shape=True); A Fully commutative stable Grothendieck crystal of type A_3 associated to [3, 2, 4] with excess 1 sage: B = crystals.FullyCommutativeStableGrothendieck(SkewPartition([[3, 3], [2, 1]]), 4, 1, shape=True) sage: A is B True sage: C = crystals.FullyCommutativeStableGrothendieck((2, 1), 3, 2, shape=True); C Fully commutative stable Grothendieck crystal of type A_2 associated to [1, 3, 2] with excess 2 sage: D = crystals.FullyCommutativeStableGrothendieck(Partition([2, 1]), 3, 2, shape=True) sage: C is D True """ from sage.monoids.hecke_monoid import HeckeMonoid if shape: from sage.combinat.partition import _Partitions from sage.combinat.skew_partition import SkewPartition cond1 = isinstance(w, (tuple, list)) and len( w) == 2 and w[0] in _Partitions and w[1] in _Partitions cond2 = isinstance(w, SkewPartition) if cond1 or cond2: sh = SkewPartition([w[0], w[1]]) elif w in _Partitions: sh = SkewPartition([w, []]) else: raise ValueError("w needs to be a (skew) partition") word = _to_reduced_word(sh) max_value = max(word) if word else 1 H = HeckeMonoid(SymmetricGroup(max_value + 1)) w = H.from_reduced_word(word) else: if isinstance(w.parent(), SymmetricGroup): H = HeckeMonoid(w.parent()) w = H.from_reduced_word(w.reduced_word()) if (not w.reduced_word()) and excess != 0: raise ValueError("excess must be 0 for the empty word") return super(FullyCommutativeStableGrothendieckCrystal, cls).__classcall__(cls, w, factors, excess)
def automorphism_group(self): r""" Return the Deck group of the cover. EXAMPLES:: sage: from surface_dynamics.all import * sage: p = iet.GeneralizedPermutation('a a b', 'b c c') sage: p.cover(['(1,2,3)', '(1,3,2)', '']).automorphism_group() Permutation Group with generators [(1,2,3), (1,3,2)] sage: p.cover(['(1,2)', '(1,3)', '']).automorphism_group() Permutation Group with generators [()] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.perm_gps.permgroup import PermutationGroup Sd = SymmetricGroup(self._degree_cover) G = libgap.Subgroup(Sd, [self.covering_data(a) for a in self._base.letters()]) C = libgap.Centralizer(Sd, G) return PermutationGroup(libgap.GeneratorsOfGroup(C).sage())
def SymmetricGroupAbsoluteOrderPoset(n, labels="permutations"): r""" Return the poset of permutations with respect to absolute order. INPUT: - ``n`` -- a positive integer - ``label`` -- (default: ``'permutations'``) a label for the elements of the poset returned by the function; the options are * ``'permutations'`` - labels the elements are given by their one-line notation * ``'reduced_words'`` - labels the elements by the lexicographically minimal reduced word * ``'cycles'`` - labels the elements by their expression as a product of cycles EXAMPLES:: sage: Posets.SymmetricGroupAbsoluteOrderPoset(4) Finite poset containing 24 elements sage: Posets.SymmetricGroupAbsoluteOrderPoset(3, labels="cycles") Finite poset containing 6 elements sage: Posets.SymmetricGroupAbsoluteOrderPoset(3, labels="reduced_words") Finite poset containing 6 elements """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup W = SymmetricGroup(n) if labels == "permutations": element_labels = {s: s.tuple() for s in W} if labels == "reduced_words": element_labels = {s: tuple(s.reduced_word()) for s in W} if labels == "cycles": element_labels = { s: "".join(x for x in s.cycle_string() if x != ',') for s in W } return Poset({s: s.absolute_covers() for s in W}, element_labels)
def covering_data(self, label): r""" Returns the permutation associated to the given ``label``. EXAMPLES:: sage: from surface_dynamics.all import * sage: p = QuadraticStratum([1,1,-1,-1]).components()[0].permutation_representative() sage: pc = p.orientation_cover() sage: pc Covering of degree 2 of the permutation: 0 1 2 3 3 2 1 4 4 0 sage: pc.covering_data(1) () sage: pc.covering_data(3) (1,2) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup S = SymmetricGroup(self._degree_cover) return S([i+1 for i in self.covering_data_tuple(label)])
def galois_action_on_embeddings(G_K): K = G_K.number_field() Kgal = G_K.splitting_field() embeddings = K.embeddings(Kgal) # first a shortcut in the case where G_K is normal in S_d since then it doesn't # matter for our application since we only care about the image # of the galois group in S_d d = K.absolute_degree() G_K_roots = TransitiveGroup(d, G_K.transitive_number()) if G_K_roots.is_normal(SymmetricGroup(d)): id_G_K = G_K.Hom(G_K).identity() return G_K, id_G_K, id_G_K, Kgal, embeddings # now for the actual computation permutations = [] for g in G_K.gens(): phi = g.as_hom() g_perm = Permutation( [embeddings.index(phi * emb) + 1 for emb in embeddings]).inverse() permutations.append(g_perm) G_K_emb = PermutationGroup(permutations, canonicalize=False) to_emb = G_K.hom(G_K_emb.gens()) from_emb = G_K_emb.hom(G_K.gens()) return G_K_emb, to_emb, from_emb, Kgal, embeddings
def _symmetric_group(self): from sage.groups.perm_gps.permgroup_named import SymmetricGroup return SymmetricGroup([i for i,j in enumerate(self._active_darts) if j])
def reorder(self, order): """ Return a new isogeny class with the curves reordered. INPUT: - ``order`` -- None, a string or an iterable over all curves in this class. See :meth:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field.isogeny_class` for more details. OUTPUT: - Another :class:`IsogenyClass_EC` with the curves reordered (and matrices and maps changed as appropriate) EXAMPLES:: sage: isocls = EllipticCurve('15a1').isogeny_class(use_tuple=False) sage: print "\n".join([repr(C) for C in isocls.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field sage: isocls2 = isocls.reorder('lmfdb') sage: print "\n".join([repr(C) for C in isocls2.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field """ if order is None or isinstance(order, basestring) and order == self._algorithm: return self if isinstance(order, basestring): if order == "lmfdb": reordered_curves = sorted(self.curves, key = lambda E: E.a_invariants()) else: reordered_curves = list(self.E.isogeny_class(algorithm=order, use_tuple=False)) elif isinstance(order, (list, tuple, IsogenyClass_EC)): reordered_curves = list(order) if len(reordered_curves) != len(self.curves): raise ValueError("Incorrect length") else: raise TypeError("order parameter should be a string, list of curves or isogeny class") need_perm = self._mat is not None cpy = self.copy() curves = [] perm = [] for E in reordered_curves: try: j = self.curves.index(E) except ValueError: try: j = self.curves.index(E.minimal_model()) except ValueError: raise ValueError("order does not yield a permutation of curves") curves.append(self.curves[j]) if need_perm: perm.append(j+1) cpy.curves = tuple(curves) if need_perm: from sage.groups.perm_gps.permgroup_named import SymmetricGroup perm = SymmetricGroup(len(self.curves))(perm) cpy._mat = perm.matrix() * self._mat * (~perm).matrix() if self._maps is not None: n = len(self._maps) cpy._maps = [self._maps[perm(i+1)-1] for i in range(n)] for i in range(n): cpy._maps[i] = [cpy._maps[i][perm(j+1)-1] for j in range(n)] else: cpy._mat = None cpy._maps = None return cpy
def CyclicCodeFromGeneratingPolynomial(n,g,ignore=True): r""" If g is a polynomial over GF(q) which divides `x^n-1` then this constructs the code "generated by g" (ie, the code associated with the principle ideal `gR` in the ring `R = GF(q)[x]/(x^n-1)` in the usual way). The option "ignore" says to ignore the condition that (a) the characteristic of the base field does not divide the length (the usual assumption in the theory of cyclic codes), and (b) `g` must divide `x^n-1`. If ignore=True, instead of returning an error, a code generated by `gcd(x^n-1,g)` is created. EXAMPLES:: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 3 sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^3+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C Linear code of length 9, dimension 6 over Finite Field in a of size 2^2 sage: P.<x> = PolynomialRing(GF(2),"x") sage: g = x^3+x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C Linear code of length 7, dimension 4 over Finite Field of size 2 sage: C.gen_mat() [1 1 0 1 0 0 0] [0 1 1 0 1 0 0] [0 0 1 1 0 1 0] [0 0 0 1 1 0 1] sage: g = x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 2 sage: C.gen_mat() [1 1 0 0] [0 1 1 0] [0 0 1 1] On the other hand, CyclicCodeFromPolynomial(4,x) will produce a ValueError including a traceback error message: "`x` must divide `x^4 - 1`". You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^2+1 followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x^2-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C Linear code of length 5, dimension 4 over Finite Field of size 3 followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with a traceback message including "`x^2 + 2` must divide `x^5 - 1`". """ P = g.parent() x = P.gen() F = g.base_ring() p = F.characteristic() if not(ignore) and p.divides(n): raise ValueError, 'The characteristic %s must not divide %s'%(p,n) if not(ignore) and not(g.divides(x**n-1)): raise ValueError, '%s must divide x^%s - 1'%(g,n) gn = GCD([g,x**n-1]) d = gn.degree() coeffs = Sequence(gn.list()) r1 = Sequence(coeffs+[0]*(n - d - 1)) Sn = SymmetricGroup(n) s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n) rows = [permutation_action(s**(-i),r1) for i in range(n-d)] MS = MatrixSpace(F,n-d,n) return LinearCode(MS(rows))
def PermutationGroupElement(g, parent=None, check=True): r""" Builds a permutation from ``g``. INPUT: - ``g`` -- either - a list of images - a tuple describing a single cycle - a list of tuples describing the cycle decomposition - a string describing the cycle decomposition - ``parent`` -- (optional) an ambient permutation group for the result; it is mandatory if you want a permutation on a domain different from `\{1, \ldots, n\}` - ``check`` -- (default: ``True``) whether additional check are performed; setting it to ``False`` is likely to result in faster code EXAMPLES: Initialization as a list of images:: sage: p = PermutationGroupElement([1,4,2,3]) sage: p (2,4,3) sage: p.parent() Symmetric group of order 4! as a permutation group Initialization as a list of cycles:: sage: p = PermutationGroupElement([(3,5),(4,6,9)]) sage: p (3,5)(4,6,9) sage: p.parent() Symmetric group of order 9! as a permutation group Initialization as a string representing a cycle decomposition:: sage: p = PermutationGroupElement('(2,4)(3,5)') sage: p (2,4)(3,5) sage: p.parent() Symmetric group of order 5! as a permutation group By default the constructor assumes that the domain is `\{1, \dots, n\}` but it can be set to anything via its second ``parent`` argument:: sage: S = SymmetricGroup(['a', 'b', 'c', 'd', 'e']) sage: PermutationGroupElement(['e', 'c', 'b', 'a', 'd'], S) ('a','e','d')('b','c') sage: PermutationGroupElement(('a', 'b', 'c'), S) ('a','b','c') sage: PermutationGroupElement([('a', 'c'), ('b', 'e')], S) ('a','c')('b','e') sage: PermutationGroupElement("('a','b','e')('c','d')", S) ('a','b','e')('c','d') But in this situation, you might want to use the more direct:: sage: S(['e', 'c', 'b', 'a', 'd']) ('a','e','d')('b','c') sage: S(('a', 'b', 'c')) ('a','b','c') sage: S([('a', 'c'), ('b', 'e')]) ('a','c')('b','e') sage: S("('a','b','e')('c','d')") ('a','b','e')('c','d') """ if isinstance(g, permgroup_element.PermutationGroupElement): if parent is None or g.parent() is parent: return g if parent is None: from sage.groups.perm_gps.permgroup_named import SymmetricGroup try: v = standardize_generator(g, None) except KeyError: raise ValueError("invalid permutation vector: %s" % g) parent = SymmetricGroup(len(v)) # We have constructed the parent from the element and already checked # that it is a valid permutation check = False return parent.element_class(g, parent, check)
def CyclicCodeFromGeneratingPolynomial(n,g,ignore=True): r""" If g is a polynomial over GF(q) which divides `x^n-1` then this constructs the code "generated by g" (ie, the code associated with the principle ideal `gR` in the ring `R = GF(q)[x]/(x^n-1)` in the usual way). The option "ignore" says to ignore the condition that (a) the characteristic of the base field does not divide the length (the usual assumption in the theory of cyclic codes), and (b) `g` must divide `x^n-1`. If ignore=True, instead of returning an error, a code generated by `gcd(x^n-1,g)` is created. EXAMPLES:: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 3 sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^3+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C Linear code of length 9, dimension 6 over Finite Field in a of size 2^2 sage: P.<x> = PolynomialRing(GF(2),"x") sage: g = x^3+x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C Linear code of length 7, dimension 4 over Finite Field of size 2 sage: C.generator_matrix() [1 1 0 1 0 0 0] [0 1 1 0 1 0 0] [0 0 1 1 0 1 0] [0 0 0 1 1 0 1] sage: g = x+1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C Linear code of length 4, dimension 3 over Finite Field of size 2 sage: C.generator_matrix() [1 1 0 0] [0 1 1 0] [0 0 1 1] On the other hand, CyclicCodeFromPolynomial(4,x) will produce a ValueError including a traceback error message: "`x` must divide `x^4 - 1`". You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(4,"a"),"x") sage: g = x^2+1 followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also get a ValueError if you type :: sage: P.<x> = PolynomialRing(GF(3),"x") sage: g = x^2-1 sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C Linear code of length 5, dimension 4 over Finite Field of size 3 followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with a traceback message including "`x^2 + 2` must divide `x^5 - 1`". """ P = g.parent() x = P.gen() F = g.base_ring() p = F.characteristic() if not(ignore) and p.divides(n): raise ValueError('The characteristic %s must not divide %s'%(p,n)) if not(ignore) and not(g.divides(x**n-1)): raise ValueError('%s must divide x^%s - 1'%(g,n)) gn = GCD([g,x**n-1]) d = gn.degree() coeffs = Sequence(gn.list()) r1 = Sequence(coeffs+[0]*(n - d - 1)) Sn = SymmetricGroup(n) s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n) rows = [permutation_action(s**(-i),r1) for i in range(n-d)] MS = MatrixSpace(F,n-d,n) return LinearCode(MS(rows))
def _lowest_weights(w, factors, ex, parent=None): """ Generate all decreasing factorizations in the 0-Hecke monoid that correspond to some valid semistandard Young tableaux. The semistandard Young tableaux should have at most ``factors`` columns and their column reading words should be equivalent to ``w`` in a 0-Hecke monoid. INPUT: - ``w`` -- a fully commutative reduced word, expressed as an iterable - ``factors`` -- number of factors for each decreasing factorization - ``ex`` -- number of extra letters in each decreasing factorizations - ``parent`` -- (default: None) parent of the decreasing factorizations, automatically assigned if it is None EXAMPLES:: sage: from sage.combinat.crystals.fully_commutative_stable_grothendieck import _lowest_weights sage: _lowest_weights([1, 2, 1], 3, 1) Traceback (most recent call last): ... ValueError: the word w should be fully commutative sage: _lowest_weights([2, 1, 3, 2], 4, 3) [(2, 1)(3, 1)(3, 1)(2), (2, 1)(3, 1)(3, 2)(2)] sage: _lowest_weights([2, 1, 3, 2], 5, 3) [(2, 1)(3, 1)(3, 1)(2)(), (2, 1)(3, 1)(3, 2)(2)(), (2, 1)(3, 1)(1)(1)(2), (2, 1)(3, 1)(1)(2)(2), (2, 1)(3, 1)(2)(2)(2), (2, 1)(3, 2)(2)(2)(2)] sage: _lowest_weights([1, 3], 3, 1) [(3, 1)(1)(), (3, 1)(3)(), (1)(1)(3), (1)(3)(3)] sage: _lowest_weights([3, 2, 1], 5, 2) [(3, 2, 1)(1)(1)()()] """ p = permutation.from_reduced_word(w) if p.has_pattern([3, 2, 1]): raise ValueError("the word w should be fully commutative") if parent is None: k = max(w) S = SymmetricGroup(k + 1) word = S.from_reduced_word(w) parent = FullyCommutativeStableGrothendieckCrystal(word, factors, ex) _canonical_word = lambda w, ex: [list(w)[0]] * ex + list(w) L = _list_equivalent_words(_canonical_word(w, ex)) M = [] for v in L: if _is_valid_column_word(v, factors): J = [0] + _jumps(v) + [len(v)] t = [v[J[i]:J[i + 1]] for i in range(len(J) - 1)] if len(J) < factors + 1: t += [()] * (factors + 1 - len(J)) M.append(parent.element_class(parent, t)) return sorted(M)
def braid_from_piecewise(strands): r""" Compute the braid corresponding to the piecewise linear curves strands. INPUT: - ``strands`` -- a list of lists of tuples ``(t, c)``, where ``t`` is a number bewteen 0 and 1, and ``c`` is a complex number OUTPUT: The braid formed by the piecewise linear strands. EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise # optional - sirocco sage: paths = [[(0, I), (0.2, -1 - 0.5*I), (0.8, -1), (1, -I)], ....: [(0, -1), (0.5, -I), (1, 1)], ....: [(0, 1), (0.5, 1 + I), (1, I)]] sage: braid_from_piecewise(paths) # optional - sirocco s0*s1 """ L = strands i = min(val[1][0] for val in L) totalpoints = [[[a[0][1].real(), a[0][1].imag()]] for a in L] indices = [1 for a in range(len(L))] while i < 1: for j, val in enumerate(L): if val[indices[j]][0] > i: xaux = val[indices[j] - 1][1] yaux = val[indices[j]][1] aaux = val[indices[j] - 1][0] baux = val[indices[j]][0] interpola = xaux + (yaux - xaux)*(i - aaux)/(baux - aaux) totalpoints[j].append([interpola.real(), interpola.imag()]) else: totalpoints[j].append([val[indices[j]][1].real(), val[indices[j]][1].imag()]) indices[j] = indices[j] + 1 i = min(val[indices[k]][0] for k,val in enumerate(L)) for j, val in enumerate(L): totalpoints[j].append([val[-1][1].real(), val[-1][1].imag()]) braid = [] G = SymmetricGroup(len(totalpoints)) def sgn(x, y): # Opposite sign of cmp if x < y: return 1 if x > y: return -1 return 0 for i in range(len(totalpoints[0]) - 1): l1 = [totalpoints[j][i] for j in range(len(L))] l2 = [totalpoints[j][i+1] for j in range(len(L))] M = [[l1[s], l2[s]] for s in range(len(l1))] M.sort() l1 = [a[0] for a in M] l2 = [a[1] for a in M] cruces = [] for j in range(len(l2)): for k in range(j): if l2[j] < l2[k]: t = (l1[j][0] - l1[k][0])/(l2[k][0] - l1[k][0] + l1[j][0] - l2[j][0]) s = sgn(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1]) cruces.append([t, k, j, s]) if cruces: cruces.sort() P = G(Permutation([])) while cruces: # we select the crosses in the same t crucesl = [c for c in cruces if c[0]==cruces[0][0]] crossesl = [(P(c[2]+1) - P(c[1]+1),c[1],c[2],c[3]) for c in crucesl] cruces = cruces[len(crucesl):] while crossesl: crossesl.sort() c = crossesl.pop(0) braid.append(c[3]*min(map(P, [c[1] + 1, c[2] + 1]))) P = G(Permutation([(c[1] + 1, c[2] + 1)]))*P crossesl = [(P(c[2]+1) - P(c[1]+1),c[1],c[2],c[3]) for c in crossesl] B = BraidGroup(len(L)) return B(braid)
def reorder(self, order): """ Return a new isogeny class with the curves reordered. INPUT: - ``order`` -- None, a string or an iterable over all curves in this class. See :meth:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field.isogeny_class` for more details. OUTPUT: - Another :class:`IsogenyClass_EC` with the curves reordered (and matrices and maps changed as appropriate) EXAMPLES:: sage: isocls = EllipticCurve('15a1').isogeny_class(use_tuple=False) sage: print "\n".join([repr(C) for C in isocls.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field sage: isocls2 = isocls.reorder('lmfdb') sage: print "\n".join([repr(C) for C in isocls2.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field """ if order is None or isinstance( order, basestring) and order == self._algorithm: return self if isinstance(order, basestring): if order == "lmfdb": reordered_curves = sorted(self.curves, key=lambda E: E.a_invariants()) else: reordered_curves = list( self.E.isogeny_class(algorithm=order, use_tuple=False)) elif isinstance(order, (list, tuple, IsogenyClass_EC)): reordered_curves = list(order) if len(reordered_curves) != len(self.curves): raise ValueError("Incorrect length") else: raise TypeError( "order parameter should be a string, list of curves or isogeny class" ) need_perm = self._mat is not None cpy = self.copy() curves = [] perm = [] for E in reordered_curves: try: j = self.curves.index(E) except ValueError: try: j = self.curves.index(E.minimal_model()) except ValueError: raise ValueError( "order does not yield a permutation of curves") curves.append(self.curves[j]) if need_perm: perm.append(j + 1) cpy.curves = tuple(curves) if need_perm: from sage.groups.perm_gps.permgroup_named import SymmetricGroup perm = SymmetricGroup(len(self.curves))(perm) cpy._mat = perm.matrix() * self._mat * (~perm).matrix() if self._maps is not None: n = len(self._maps) cpy._maps = [self._maps[perm(i + 1) - 1] for i in range(n)] for i in range(n): cpy._maps[i] = [ cpy._maps[i][perm(j + 1) - 1] for j in range(n) ] else: cpy._mat = None cpy._maps = None return cpy