# Ticket #10335: trac_10335-permgroup_domain-rebase.patch

File trac_10335-permgroup_domain-rebase.patch, 133.5 KB (added by davidloeffler, 10 years ago)

patch against 4.7.2.alpha3 prerelease

• ## doc/de/tutorial/interfaces.rst

# HG changeset patch
# User Mike Hansen <mhansen@gmail.com>
# Date 1307563431 25200
# Node ID 4e461492179a94b3fa1bd7e49bd3c5fe4b20c286
# Parent  10f49e34d981dccab46b3c81dc60a14f0ee2d747
#10335: Add support for domains of permutation groups.
This includes the functionality from #8929 by Jason Hill.

diff --git a/doc/de/tutorial/interfaces.rst b/doc/de/tutorial/interfaces.rst
 a sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.group_id()    # requires optional database_gap package [120, 34] sage: n = G.order(); n
• ## doc/de/tutorial/tour_groups.rst

diff --git a/doc/de/tutorial/tour_groups.rst b/doc/de/tutorial/tour_groups.rst
 a [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.random_element()           # random output (1,5,3)(2,4) sage: print latex(G)
• ## doc/en/bordeaux_2008/nf_galois_groups.rst

diff --git a/doc/en/bordeaux_2008/nf_galois_groups.rst b/doc/en/bordeaux_2008/nf_galois_groups.rst
 a sage: P = K.primes_above(2)[0] sage: G.inertia_group(P) Subgroup [(), (1,4,6)(2,5,3), (1,6,4)(2,3,5)] of Galois group of Number Field in alpha with defining polynomial x^6 + 40*x^3 + 1372 sage: sorted([G.artin_symbol(Q) for Q in K.primes_above(5)]) # (order is platform-dependent) [(1,2)(3,4)(5,6), (1,3)(2,6)(4,5), (1,5)(2,4)(3,6)] 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)] If the number field is not Galois over \QQ, then the galois_group command will construct its Galois closure and return the Galois group of that;
• ## doc/en/constructions/groups.rst

diff --git a/doc/en/constructions/groups.rst b/doc/en/constructions/groups.rst
 a sage: G = PermutationGroup(['(1,2,3)(4,5)', '(3,4)']) sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] A similar syntax for matrix groups also works: [[[4, 0], [0, 4]]] sage: G = PSL(2, 5 ) sage: G.center() Permutation Group with generators [()] Subgroup of (The projective special linear group of degree 2 over Finite Field of size 5) generated by [()] Note: center can be spelled either way in GAP, not so in Sage.
• ## doc/en/thematic_tutorials/group_theory.rst

diff --git a/doc/en/thematic_tutorials/group_theory.rst b/doc/en/thematic_tutorials/group_theory.rst
 a sage: C20 = CyclicPermutationGroup(20) sage: C20.conjugacy_classes_subgroups() [Permutation Group with generators [()], Permutation Group with generators [(1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)], Permutation Group with generators [(1,6,11,16)(2,7,12,17)(3,8,13,18)(4,9,14,19)(5,10,15,20)], Permutation Group with generators [(1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)], Permutation Group with generators [(1,3,5,7,9,11,13,15,17,19)(2,4,6,8,10,12,14,16,18,20)], Permutation Group with generators [(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)]] [Subgroup of (Cyclic group of order 20 as a permutation group) generated by [()], Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)], Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,6,11,16)(2,7,12,17)(3,8,13,18)(4,9,14,19)(5,10,15,20)], Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)], Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,3,5,7,9,11,13,15,17,19)(2,4,6,8,10,12,14,16,18,20)], Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)]] Be careful, this command uses some more advanced ideas and will not usually list *all* of the subgroups of a group. Here we are relying on sage: sg = K.conjugacy_classes_subgroups() sage: print "sg:\n", sg sg: [Permutation Group with generators [()], Permutation Group with generators [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8)], Permutation Group with generators [(1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], Permutation Group with generators [(2,12)(3,11)(4,10)(5,9)(6,8)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12)], Permutation Group with generators [(2,12)(3,11)(4,10)(5,9)(6,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], Permutation Group with generators [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], Permutation Group with generators [(1,10,7,4)(2,11,8,5)(3,12,9,6)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,3,5,7,9,11)(2,4,6,8,10,12)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,2)(3,12)(4,11)(5,10)(6,9)(7,8)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (2,12)(3,11)(4,10)(5,9)(6,8)], Permutation Group with generators [(2,12)(3,11)(4,10)(5,9)(6,8), (1,10,7,4)(2,11,8,5)(3,12,9,6)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (2,12)(3,11)(4,10)(5,9)(6,8)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,2)(3,12)(4,11)(5,10)(6,9)(7,8)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,2,3,4,5,6,7,8,9,10,11,12)], Permutation Group with generators [(1,5,9)(2,6,10)(3,7,11)(4,8,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (2,12)(3,11)(4,10)(5,9)(6,8), (1,2,3,4,5,6,7,8,9,10,11,12)]] [Subgroup of (Dihedral group of order 24 as a permutation group) generated by [()], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,10,7,4)(2,11,8,5)(3,12,9,6)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,10,7,4)(2,11,8,5)(3,12,9,6)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2,3,4,5,6,7,8,9,10,11,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,2,3,4,5,6,7,8,9,10,11,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)]] sage: print "\nAn order two subgroup:\n", sg[1].list() An order two subgroup:
• ## doc/en/tutorial/interfaces.rst

diff --git a/doc/en/tutorial/interfaces.rst b/doc/en/tutorial/interfaces.rst
 a sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.group_id()     # requires optional database_gap package [120, 34] sage: n = G.order(); n
• ## doc/en/tutorial/tour_groups.rst

diff --git a/doc/en/tutorial/tour_groups.rst b/doc/en/tutorial/tour_groups.rst
 a [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.random_element()           # random output (1,5,3)(2,4) sage: print latex(G)
• ## doc/fr/tutorial/interfaces.rst

diff --git a/doc/fr/tutorial/interfaces.rst b/doc/fr/tutorial/interfaces.rst
 a sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.group_id()    # nécessite le paquet facultatif database_gap (optional) [120, 34] sage: n = G.order(); n
• ## doc/fr/tutorial/tour_groups.rst

diff --git a/doc/fr/tutorial/tour_groups.rst b/doc/fr/tutorial/tour_groups.rst
 a [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.random_element()           # sortie aléatoire (random) (1,5,3)(2,4) sage: print latex(G)
• ## doc/ru/tutorial/interfaces.rst

diff --git a/doc/ru/tutorial/interfaces.rst b/doc/ru/tutorial/interfaces.rst
 a sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.group_id()     # requires optional database_gap package [120, 34] sage: n = G.order(); n
• ## doc/ru/tutorial/tour_groups.rst

diff --git a/doc/ru/tutorial/tour_groups.rst b/doc/ru/tutorial/tour_groups.rst
 a [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.random_element()           # random output (1,5,3)(2,4) sage: print latex(G)
• ## sage/algebras/group_algebra_new.py

diff --git a/sage/algebras/group_algebra_new.py b/sage/algebras/group_algebra_new.py
 a sage: a * b  # a is automatically converted to an element of B 7*() + 5*(3,4) + 3*(2,3) + 9*(2,3,4) + 3*(1,2) + 6*(1,2)(3,4) + 3*(1,2,3) + (1,2,3,4) + 9*(1,3,2) + 3*(1,3,4) sage: parent(a * b) Group algebra of group "SymmetricGroup(4)" over base ring Rational Field Group algebra of group "Symmetric group of order 4! as a permutation group" over base ring Rational Field sage: G = GL(3, GF(7)) sage: ZG = GroupAlgebra(G)
• ## sage/categories/finite_groups.py

diff --git a/sage/categories/finite_groups.py b/sage/categories/finite_groups.py
 a sage: A = AlternatingGroup(4) sage: A.semigroup_generators() Family ((1,2,3), (2,3,4)) Family ((2,3,4), (1,2,3)) """ return self.group_generators()
• ## sage/categories/g_sets.py

diff --git a/sage/categories/g_sets.py b/sage/categories/g_sets.py
 a sage: S = SymmetricGroup(3) sage: GSets(S) Category of G-sets for SymmetricGroup(3) Category of G-sets for Symmetric group of order 3! as a permutation group TODO: should this derive from Category_over_base? """ EXAMPLES:: sage: GSets(SymmetricGroup(8)) # indirect doctests Category of G-sets for SymmetricGroup(8) Category of G-sets for Symmetric group of order 8! as a permutation group """ return "G-sets for %s"%self.__G EXAMPLES:: sage: GSets.an_instance() # indirect doctest Category of G-sets for SymmetricGroup(8) 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)
• ## sage/categories/groupoid.py

diff --git a/sage/categories/groupoid.py b/sage/categories/groupoid.py
 a sage: S8 = SymmetricGroup(8) sage: Groupoid(S8) Groupoid with underlying set SymmetricGroup(8) Groupoid with underlying set Symmetric group of order 8! as a permutation group """ return "Groupoid with underlying set %s"%self.__G EXAMPLES:: sage: Groupoid.an_instance() # indirect doctest Groupoid with underlying set SymmetricGroup(8) 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)
• ## sage/categories/groups.py

diff --git a/sage/categories/groups.py b/sage/categories/groups.py
 a sage: A = AlternatingGroup(4) sage: A.group_generators() Family ((1,2,3), (2,3,4)) Family ((2,3,4), (1,2,3)) """ return Family(self.gens())
• ## sage/categories/homset.py

diff --git a/sage/categories/homset.py b/sage/categories/homset.py
 a Category of vector spaces over Rational Field sage: G = AlternatingGroup(3) sage: Hom(G, G) Set of Morphisms from AlternatingGroup(3) to AlternatingGroup(3) in Category of finite permutation groups Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite permutation groups sage: Hom(ZZ, QQ, Sets()) Set of Morphisms from Integer Ring to Rational Field in Category of sets sage: G = AlternatingGroup(3) sage: S = End(G); S Set of Morphisms from AlternatingGroup(3) to AlternatingGroup(3) in Category of finite permutation groups Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite permutation groups sage: from sage.categories.homset import is_Endset sage: is_Endset(S) True sage: phi = Hom(SymmetricGroup(5), SymmetricGroup(6)).natural_map() sage: phi Coercion morphism: From: SymmetricGroup(5) To:   SymmetricGroup(6) From: Symmetric group of order 5! as a permutation group To:   Symmetric group of order 6! as a permutation group sage: H(phi) Composite map: From: SymmetricGroup(4) To:   SymmetricGroup(7) From: Symmetric group of order 4! as a permutation group To:   Symmetric group of order 7! as a permutation group Defn:   Composite map: From: SymmetricGroup(4) To:   SymmetricGroup(6) From: Symmetric group of order 4! as a permutation group To:   Symmetric group of order 6! as a permutation group Defn:   Call morphism: From: SymmetricGroup(4) To:   SymmetricGroup(5) From: Symmetric group of order 4! as a permutation group To:   Symmetric group of order 5! as a permutation group then Coercion morphism: From: SymmetricGroup(5) To:   SymmetricGroup(6) From: Symmetric group of order 5! as a permutation group To:   Symmetric group of order 6! as a permutation group then Call morphism: From: SymmetricGroup(6) To:   SymmetricGroup(7) From: Symmetric group of order 6! as a permutation group To:   Symmetric group of order 7! as a permutation group sage: H = Hom(ZZ, ZZ, Sets()) sage: f = H( lambda x: x + 1 )
• ## sage/categories/hopf_algebras_with_basis.py

diff --git a/sage/categories/hopf_algebras_with_basis.py b/sage/categories/hopf_algebras_with_basis.py
 a An other group can be specified as optional argument:: sage: HopfAlgebrasWithBasis(QQ).example(SymmetricGroup(4)) An example of Hopf algebra with basis: the group algebra of the SymmetricGroup(4) over Rational Field An example of Hopf algebra with basis: the group algebra of the Symmetric group of order 4! as a permutation group over Rational Field """ from sage.categories.examples.hopf_algebras_with_basis import MyGroupAlgebra from sage.groups.perm_gps.permgroup_named import DihedralGroup
• ## sage/categories/map.pyx

diff --git a/sage/categories/map.pyx b/sage/categories/map.pyx
 a sage: Map(QQ['x'], SymmetricGroup(6)) Generic map: From: Univariate Polynomial Ring in x over Rational Field To:   SymmetricGroup(6) To:   Symmetric group of order 6! as a permutation group """ if codomain is not None: if PY_TYPE_CHECK(parent, type):
• ## sage/categories/pushout.py

diff --git a/sage/categories/pushout.py b/sage/categories/pushout.py
 a rank = 10 def __init__(self, gens): def __init__(self, gens, domain): """ EXAMPLES:: sage: from sage.categories.pushout import PermutationGroupFunctor sage: PF = PermutationGroupFunctor([PermutationGroupElement([(1,2)])]); PF sage: PF = PermutationGroupFunctor([PermutationGroupElement([(1,2)])], [1,2]); PF PermutationGroupFunctor[(1,2)] """ Functor.__init__(self, Groups(), Groups()) self._gens = gens self._domain = domain def __repr__(self): """ Permutation Group with generators [(1,2)] """ from sage.groups.perm_gps.permgroup import PermutationGroup return PermutationGroup([g for g in (R.gens() + self.gens()) if not g.is_one()]) return PermutationGroup([g for g in (R.gens() + self.gens()) if not g.is_one()], domain=self._domain) def gens(self): """ """ if self.__class__ != other.__class__: return None return PermutationGroupFunctor(self.gens() + other.gens()) from sage.sets.all import FiniteEnumeratedSet new_domain = set(self._domain).union(set(other._domain)) new_domain = FiniteEnumeratedSet(sorted(new_domain)) return PermutationGroupFunctor(self.gens() + other.gens(), new_domain) class BlackBoxConstructionFunctor(ConstructionFunctor): """
• ## sage/combinat/permutation.py

diff --git a/sage/combinat/permutation.py b/sage/combinat/permutation.py
 a cycles.append(tuple(cycle)) return cycles cycle_tuples = to_cycles def _to_cycles_orig(self, singletons=True): r""" Returns the permutation p as a list of disjoint cycles. p = range(1,n+1) for cycle in cycles: if not cycle: continue first = cycle[0] for i in range(len(cycle)-1): p[cycle[i]-1] = cycle[i+1]
• ## sage/combinat/species/cycle_species.py

diff --git a/sage/combinat/species/cycle_species.py b/sage/combinat/species/cycle_species.py
 a sage: [a.transport(perm) for perm in a.automorphism_group()] [(1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4)] """ from sage.groups.all import SymmetricGroup from sage.groups.all import SymmetricGroup, PermutationGroup S = SymmetricGroup(len(self._labels)) p = self.permutation_group_element() return S.centralizer(p) return PermutationGroup(S.centralizer(p).gens()) @accept_size @cached_function
• ## sage/combinat/species/permutation_species.py

diff --git a/sage/combinat/species/permutation_species.py b/sage/combinat/species/permutation_species.py
 a ['a', 'c', 'b', 'd'], ['a', 'c', 'b', 'd']] """ from sage.groups.all import SymmetricGroup from sage.groups.all import SymmetricGroup, PermutationGroup S = SymmetricGroup(len(self._labels)) p = self.permutation_group_element() return S.centralizer(p) return PermutationGroup(S.centralizer(p).gens()) @accept_size @cached_function
• ## sage/groups/abelian_gps/abelian_group.py

diff --git a/sage/groups/abelian_gps/abelian_group.py b/sage/groups/abelian_gps/abelian_group.py
 a sage: G = AbelianGroup(2,[2,3]); G Multiplicative Abelian Group isomorphic to C2 x C3 sage: G.permutation_group() Permutation Group with generators [(1,4)(2,5)(3,6), (1,2,3)(4,5,6)] Permutation Group with generators [(1,2,3)(4,5,6), (1,4)(2,5)(3,6)] """ from sage.groups.perm_gps.permgroup import PermutationGroup s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()
• ## sage/groups/abelian_gps/abelian_group_element.py

diff --git a/sage/groups/abelian_gps/abelian_group_element.py b/sage/groups/abelian_gps/abelian_group_element.py
 a Multiplicative Abelian Group isomorphic to C2 x C3 x C4 sage: a,b,c=G.gens() sage: Gp = G.permutation_group(); Gp Permutation Group with generators [(1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24), (1,5,9)(2,6,10)(3,7,11)(4,8,12)(13,17,21)(14,18,22)(15,19,23)(16,20,24), (1,3,2,4)(5,7,6,8)(9,11,10,12)(13,15,14,16)(17,19,18,20)(21,23,22,24)] Permutation Group with generators [(1,3,2,4)(5,7,6,8)(9,11,10,12)(13,15,14,16)(17,19,18,20)(21,23,22,24), (1,5,9)(2,6,10)(3,7,11)(4,8,12)(13,17,21)(14,18,22)(15,19,23)(16,20,24), (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24)] sage: a.as_permutation() (1,13)(2,14)(3,15)(4,16)(5,17)(6,18)(7,19)(8,20)(9,21)(10,22)(11,23)(12,24) sage: ap = a.as_permutation(); ap
• ## sage/groups/class_function.py

diff --git a/sage/groups/class_function.py b/sage/groups/class_function.py
 a Character of Symmetric group of order 5! as a permutation group sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: chi.restrict(H) Character of Subgroup of SymmetricGroup(5) generated by [(4,5), (1,2), (1,2,3)] Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)] sage: chi.restrict(H).values() [3, -3, -3, -1, 0, 0] """ sage: G = SymmetricGroup(5) sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: xi = H.trivial_character(); xi Character of Subgroup of SymmetricGroup(5) generated by [(4,5), (1,2), (1,2,3)] Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)] sage: xi.induct(G) Character of Symmetric group of order 5! as a permutation group sage: xi.induct(G).values()
• ## sage/groups/perm_gps/permgroup.py

diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
 a from sage.rings.all import QQ, Integer from sage.interfaces.all import is_ExpectElement from sage.interfaces.gap import gap, GapElement from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.groups.perm_gps.permgroup_element import PermutationGroupElement, standardize_generator from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.misc.cachefunc import cached_method from sage.groups.class_function import ClassFunction from sage.misc.package import is_package_installed from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.categories.all import FiniteEnumeratedSets def load_hap(): """ srcs = map(G, srcs) return srcs def PermutationGroup(gens=None, gap_group=None, canonicalize=True): def PermutationGroup(gens=None, gap_group=None, domain=None, canonicalize=True, category=None): """ Return the permutation group associated to x (typically a list of generators). return gens._permgroup_() if gens is not None and not isinstance(gens, (tuple, list, GapElement)): raise TypeError, "gens must be a tuple, list, or GapElement" return PermutationGroup_generic(gens=gens, gap_group=gap_group, canonicalize=canonicalize) return PermutationGroup_generic(gens=gens, gap_group=gap_group, domain=domain, canonicalize=canonicalize, category=category) class PermutationGroup_generic(group.Group): sage: G Permutation Group with generators [(3,4), (1,2,3)(4,5)] sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] sage: G.group_id()          # optional - database_gap [120, 34] sage: n = G.order(); n sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: TestSuite(G).run() """ def __init__(self, gens=None, gap_group=None, canonicalize=True): def __init__(self, gens=None, gap_group=None, canonicalize=True, domain=None, category=None): r""" INPUT: sage: A4.__init__([[(1,2,3)],[(2,3,4)]]); A4 Permutation Group with generators [(2,3,4), (1,2,3)] sage: A4.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(2,3,4), (1,2,3)]) generated by [()] sage: A4.category() Category of finite permutation groups sage: TestSuite(A4).run() sage: TestSuite(PermutationGroup([])).run() """ from sage.categories.finite_permutation_groups import FinitePermutationGroups super(PermutationGroup_generic, self).__init__(category = FinitePermutationGroups()) super(PermutationGroup_generic, self).__init__(category = FinitePermutationGroups().or_subcategory(category)) if (gens is None and gap_group is None): raise ValueError, "you must specify gens or gap_group" #Handle the case where only the GAP group is specified. if gens is None: from sage.interfaces.gap import gap self._gap_string = gap_group if isinstance(gap_group, str) else str(gap_group) self._gens = self._gens_from_gap() self._deg = gap(gap_group).LargestMovedPoint() self._set = range(1, self._deg+1) else: gens = [self._element_class()(x, check=False).list() for x in gens] self._deg = max([0]+[max(g) for g in gens]) self._set = range(1, self._deg+1) if not gens:  # length 0 gens = [()] gens = [self._element_class()(x, self, check=False) for x in gens] if canonicalize: gens = sorted(set(gens)) self._gens = gens self._gap_string = 'Group(%s)'%gens if isinstance(gap_group, str): gap_group = gap(gap_group) gens = [gen for gen in gap_group.GeneratorsOfGroup()] if domain is None: gens = [standardize_generator(x) for x in gens] domain = set() for x in gens: for cycle in x: domain = domain.union(cycle) domain = sorted(domain) #Here we need to check if all of the points are integers #to make the domain contain all integers up to the max. #This is needed for backward compatibility if all(isinstance(p, (Integer, int, long)) for p in domain): domain = range(1, max([1] + domain)+1) if domain not in FiniteEnumeratedSets(): domain = FiniteEnumeratedSet(domain) self._domain = domain self._deg = len(self._domain) self._domain_to_gap = dict((key, i+1) for i, key in enumerate(self._domain)) self._domain_from_gap = dict((i+1, key) for i, key in enumerate(self._domain)) if not gens:  # length 0 gens = [()] gens = [self._element_class()(x, self, check=False) for x in gens] if canonicalize: gens = sorted(set(gens)) self._gens = gens def construction(self): """ (1,2,3) sage: p.parent() Permutation Group with generators [(1,2), (1,3)] sage: p.parent().domain() {1, 2, 3} Note that this will merge permutation groups with different domains:: sage: g1 = PermutationGroupElement([(1,2),(3,4,5)]) sage: g2 = PermutationGroup([('a','b')], domain=['a', 'b']).gens()[0] sage: g2 ('a','b') sage: p = g1*g2; p (1,2)(3,4,5)('a','b') """ gens = self.gens() if len(gens) == 1 and gens[0].is_one(): return None else: from sage.categories.pushout import PermutationGroupFunctor return (PermutationGroupFunctor(gens), PermutationGroup([])) def _gens_from_gap(self): return (PermutationGroupFunctor(gens, self.domain()), PermutationGroup([])) @cached_method def _has_natural_domain(self): """ Returns the generators of the group by asking GAP for them. Returns True if the underlying domain is of the form (1,...,n) EXAMPLES:: sage: S = SymmetricGroup(3) sage: S._gap_string 'SymmetricGroup(3)' sage: S._gens_from_gap() [(1,2,3), (1,2)] sage: SymmetricGroup(3)._has_natural_domain() True sage: SymmetricGroup((1,2,3))._has_natural_domain() True sage: SymmetricGroup((1,3))._has_natural_domain() False sage: SymmetricGroup((3,2,1))._has_natural_domain() False """ try: gens = self._gap_().GeneratorsOfGroup() except TypeError, s: raise RuntimeError, "(It might be necessary to install the database_gap optional Sage package, if you haven't already.)\n%s"%s gens = [self._element_class()(gens[n], self, check=False) for n in range(1, int(gens.Length())+1)] if gens == []: gens = [()] return gens domain = self.domain() natural_domain = FiniteEnumeratedSet(range(1, len(domain)+1)) return domain == natural_domain def _gap_init_(self): r""" sage: A4 = PermutationGroup([[(1,2,3)],[(2,3,4)]]); A4 Permutation Group with generators [(2,3,4), (1,2,3)] sage: A4._gap_init_() 'Group([(2,3,4), (1,2,3)])' 'Group([PermList([1, 3, 4, 2]), PermList([2, 3, 1, 4])])' """ return self._gap_string return 'Group([%s])'%(', '.join([g._gap_init_() for g in self.gens()])) def _magma_init_(self, magma): r""" Returns a string showing how to declare / initialize self in Magma. EXAMPLES: We explicitly construct the alternating group on four Permutation Group with generators [(2,3,4), (1,2,3)] sage: A4._magma_init_(magma) 'PermutationGroup<4 | (2,3,4), (1,2,3)>' sage: S = SymmetricGroup(['a', 'b', 'c']) sage: S._magma_init_(magma) 'PermutationGroup<3 | (1,2,3), (1,2)>' """ g = str(self.gens())[1:-1] g = ', '.join([g._gap_cycle_string() for g in self.gens()]) return 'PermutationGroup<%s | %s>'%(self.degree(), g) def __cmp__(self, right): True sage: H3 < H1 # since H3 is a subgroup of H1 True """ if not isinstance(right, PermutationGroup_generic): if (not isinstance(right, PermutationGroup_generic) or self.domain() != right.domain()): return -1 if self is right: return 0 sage: G([(1,2)]) Traceback (most recent call last): ... TypeError: permutation (1, 2) not in Permutation Group with generators [(1,2,3,4)] TypeError: permutation [(1, 2)] not in Permutation Group with generators [(1,2,3,4)] """ try: if x.parent() is self: x_parent = x.parent() if x_parent is self: return x elif (x_parent.degree() <= self.degree() and (self.__class__ == SymmetricGroup or x._gap_() in self._gap_())): return self._element_class()(x.list(), self, check = False) compatible_domains = all(point in self._domain_to_gap for point in x_parent.domain()) if  compatible_domains and (self.__class__ == SymmetricGroup or x._gap_() in self._gap_()): return self._element_class()(x.cycle_tuples(), self, check=False) raise TypeError, "no implicit coercion of element into permutation group" @cached_method sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]]) sage: G.list() [(), (3,4), (2,3), (2,3,4), (2,4,3), (2,4), (1,2), (1,2)(3,4), (1,2,3), (1,2,3,4), (1,2,4,3), (1,2,4), (1,3,2), (1,3,4,2), (1,3), (1,3,4), (1,3)(2,4), (1,3,2,4), (1,4,3,2), (1,4,2), (1,4,3), (1,4), (1,4,2,3), (1,4)(2,3)] sage: G = PermutationGroup([[('a','b')]], domain=('a', 'b')); G Permutation Group with generators [('a','b')] sage: G.list() [(), ('a','b')] """ X = self._gap_().Elements() n = X.Length() L = [self._element_class()(X[i], self, check = False) for i in range(1,n+1)] return L return list(self.__iter__()) def __contains__(self, item): """ True sage: h in H False sage: G = PermutationGroup([[('a','b')]], domain=('a', 'b')) sage: [('a', 'b')] in G True """ try: item = self(item, check=True) sage: G = PermutationGroup([[(1,2,3)], [(1,2)]]) sage: [a for a in G] [(), (2,3), (1,2), (1,2,3), (1,3,2), (1,3)] TODO: this currently returns an iterator over the elements of self.list(). This should be made into a real iterator. """ return iter(self.list()) for g in self._gap_().Elements(): yield self._element_class()(g, self, check=False) def gens(self): """ sage: G = PermutationGroup([R,L,U,F,B,D]) sage: len(G.gens_small()) 2 The output may be unpredictable, due to the use of randomized algorithms in GAP. Note that both the following answers are equally valid. :: sage: G = PermutationGroup([[('a','b')], [('b', 'c')], [('a', 'c')]]) sage: G.gens_small() # random [('b','c'), ('a','c','b')] ## (on 64-bit Linux) [('a','b'), ('a','c','b')] ## (on Solaris) sage: len(G.gens_small()) == 2 True """ gens = self._gap_().SmallGeneratingSet() return [self._element_class()(x, self, check=False) for x in gens] (1,2,3)(4,5) sage: e*g (1,2,3)(4,5) sage: S = SymmetricGroup(['a','b','c']) sage: S.identity() () """ return self._element_class()([], self, check=True) :: sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G = PermutationGroup([[('a','b','c'),('d','e')]]) sage: G.largest_moved_point() 'e' .. warning:: The name of this function is not good; this function should be deprecated in term of degree:: sage: P = PermutationGroup([[1,2,3,4]]) sage: P.largest_moved_point() 4 sage: P.cardinality() 1 """ try: return self._domain_from_gap[Integer(self._gap_().LargestMovedPoint())] except KeyError: return self.degree() def degree(self): """ Returns the degree of this permutation group. EXAMPLES:: sage: S = SymmetricGroup(['a','b','c']) sage: S.degree() 3 sage: G = PermutationGroup([(1,3),(4,5)]) sage: G.degree() 5 TODO: the name of this function is not good; this function should be deprecated in term of degree:: sage: P = PermutationGroup([[1,2,3,4]]) sage: P.largest_moved_point() Note that you can explicitly specify the domain to get a permutation group of smaller degree:: sage: G = PermutationGroup([(1,3),(4,5)], domain=[1,3,4,5]) sage: G.degree() 4 sage: P.cardinality() 1 """ # This seems unndeeded since __init__ systematically sets # self._deg This is actually needed because constructing the # __init__ of PermutationGroupElement sometimes calls this # group before is initialized. try: return self._deg except AttributeError: n = Integer(self._gap_().LargestMovedPoint()) self._deg = n return n degree = largest_moved_point def set(self): return Integer(len(self._domain)) def domain(self): r""" Returns the underlying set that this permutation group acts on.  By default, the set is {1, ..., n} where n is the largest moved point by the group. on. EXAMPLES:: sage: P = PermutationGroup([(1,2),(3,5)]) sage: P.set() (1, 2, 3, 4, 5) sage: P.domain() {1, 2, 3, 4, 5} sage: S = SymmetricGroup(['a', 'b', 'c']) sage: S.domain() {'a', 'b', 'c'} """ return tuple(self._set) domain = set def _set_gap(self): return self._domain def _domain_gap(self, domain=None): """ Returns a GAP string representation of the underlying set that this group acts on.  See also :meth:set. that this group acts on.  See also :meth:domain. EXAMPLES:: sage: P = PermutationGroup([(1,2),(3,5)]) sage: P._set_gap() sage: P._domain_gap() '[1, 2, 3, 4, 5]' """ return repr(list(self.set())) if domain is None: return repr(range(1, self.degree()+1)) else: try: return repr([self._domain_to_gap[point] for point in domain]) except KeyError: raise ValueError, "domain must be a subdomain of self.domain()" @cached_method def smallest_moved_point(self): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]]) sage: G.smallest_moved_point() 1 Note that this function uses the ordering from the domain:: sage: S = SymmetricGroup(['a','b','c']) sage: S.smallest_moved_point() 'a' """ return Integer(self._gap_().SmallestMovedPoint()) return self._domain_from_gap[Integer(self._gap_().SmallestMovedPoint())] @cached_method def orbits(self): """ Returns the orbits of [1,2,...,degree] under the group action. Returns the orbits of the elements of the domain under the group action. EXAMPLES:: sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]]) sage: G.orbits() [[1, 2, 3, 4, 10], [5], [6], [7], [8], [9]] sage: G = PermutationGroup([ [('c','d')], [('a','c')],[('b',)]]) sage: G.orbits() [['a', 'c', 'd'], ['b']] The answer is cached:: - Nathan Dunfield """ return self._gap_().Orbits(self._set_gap()).sage() return [[self._domain_from_gap[x] for x in orbit] for orbit in self._gap_().Orbits(self._domain_gap()).sage()] @cached_method def orbit(self, integer): def orbit(self, point): """ Return the orbit of the given integer under the group action. Return the orbit of the given point under the group action. EXAMPLES:: sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]]) sage: G.orbit(3) [3, 4, 10, 1, 2] """ return self._gap_().Orbit(integer).sage() sage: G = PermutationGroup([ [('c','d')], [('a','c')] ]) sage: G.orbit('a') ['a', 'c', 'd'] """ point = self._domain_to_gap[point] return [self._domain_from_gap[x] for x in self._gap_().Orbit(point).sage()] def transversals(self, integer): def transversals(self, point): """ If G is a permutation group acting on the set X = \{1, 2, ...., n\} and H is the stabilizer subgroup of , a right sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]]) sage: G.transversals(1) [(), (1,2)(3,4), (1,3,2,10,4), (1,4,2,10,3), (1,10,4,3,2)] sage: G = PermutationGroup([ [('c','d')], [('a','c')] ]) sage: G.transversals('a') [(), ('a','c','d'), ('a','d','c')] """ trans = [] for i in self.orbit(integer): trans.append(self(gap.RepresentativeAction(self._gap_(),integer,i))) return trans def stabilizer(self, position): G = self._gap_() return [self(G.RepresentativeAction(self._domain_to_gap[point], self._domain_to_gap[i])) for i in self.orbit(point)] def stabilizer(self, point): """ Return the subgroup of self which stabilize the given position. self and its stabilizers must have same degree. sage: G = PermutationGroup([ [(3,4)], [(1,3)] ]) sage: G.stabilizer(1) Permutation Group with generators [(3,4)] Subgroup of (Permutation Group with generators [(3,4), (1,3)]) generated by [(3,4)] sage: G.stabilizer(3) Permutation Group with generators [(1,4)] Subgroup of (Permutation Group with generators [(3,4), (1,3)]) generated by [(1,4)] sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]]) sage: G.stabilizer(10) Permutation Group with generators [(1,2)(3,4), (2,3,4)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3,4), (1,2)(3,4)] sage: G.stabilizer(1) Permutation Group with generators [(2,3)(4,10), (2,10,4)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3)(4,10), (2,10,4)] sage: G = PermutationGroup([[(2,3,4)],[(6,7)]]) sage: G.stabilizer(1) Permutation Group with generators [(6,7), (2,3,4)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)] sage: G.stabilizer(2) Permutation Group with generators [(6,7)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)] sage: G.stabilizer(3) Permutation Group with generators [(6,7)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)] sage: G.stabilizer(4) Permutation Group with generators [(6,7)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)] sage: G.stabilizer(5) Permutation Group with generators [(6,7), (2,3,4)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)] sage: G.stabilizer(6) Permutation Group with generators [(2,3,4)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(2,3,4)] sage: G.stabilizer(7) Permutation Group with generators [(2,3,4)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(2,3,4)] sage: G.stabilizer(8) Permutation Group with generators [(6,7), (2,3,4)] Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)] """ return PermutationGroup(gap_group=gap.Stabilizer(self, position)) def strong_generating_system(self, base_of_group = None): try: position = self._domain_to_gap[point] except KeyError: return self.subgroup(gens=self.gens()) return self.subgroup(gap_group=gap.Stabilizer(self, point)) def strong_generating_system(self, base_of_group=None): """ Return a Strong Generating System of self according the given base for the right action of self on itself. [[(), (1,2)(3,4), (1,3)(2,4), (1,4)(2,3)], [(), (2,3,4), (2,4,3)], [(), (3,4)], [()]] sage: G = PermutationGroup([[(1,2,3)],[(4,5,7)],[(1,4,6)]]) sage: G.strong_generating_system() [[(), (1,2,3), (1,4,6), (1,3,2), (1,5,7,4,6), (1,6,4), (1,7,5,4,6)], [(), (2,6,3), (2,3,6), (2,5,6,3)(4,7), (2,7,5,6,3), (2,4,5,6,3)], [(), (3,6)(5,7), (3,5,6), (3,7,4,5,6), (3,4,7,5,6)], [(), (4,5)(6,7), (4,7)(5,6), (4,6)(5,7)], [(), (5,6,7), (5,7,6)], [()], [()]] [[(), (1,2,3), (1,4,6), (1,3,2), (1,5,7,4,6), (1,6,4), (1,7,5,4,6)], [(), (2,6,3), (2,5,7,6,3), (2,3,6), (2,7,5,6,3), (2,4,7,6,3)], [(), (3,6,7), (3,5,6), (3,7,6), (3,4,7,5,6)], [(), (4,5)(6,7), (4,7)(5,6), (4,6)(5,7)], [(), (5,7,6), (5,6,7)], [()], [()]] sage: G = PermutationGroup([[(1,2,3)],[(2,3,4)],[(3,4,5)]]) sage: G.strong_generating_system([5,4,3,2,1]) [[(), (1,5,3,4,2), (1,5,4,3,2), (1,5)(2,3), (1,5,2)], [(), (1,3)(2,4), (1,2)(3,4), (1,4)(2,3)], [(), (1,3,2), (1,2,3)], [()], [()]] sgs = [] stab = self if base_of_group is None: base_of_group = self.set() base_of_group = self.domain() for j in base_of_group: sgs.append(stab.transversals(j)) stab = stab.stabilizer(j) \langle (2,3,4), (1,2,3) \rangle sage: A4._latex_() '\\langle (2,3,4), (1,2,3) \\rangle' sage: S = SymmetricGroup(['a','b','c']) sage: latex(S) \langle (\verb|a|,\verb|b|,\verb|c|), (\verb|a|,\verb|b|) \rangle """ return '\\langle ' + \ ', '.join([x._latex_() for x in self.gens()]) + ' \\rangle' sage: G = PermutationGroup([[(1,2,3,4)]]) sage: G.center() Permutation Group with generators [(1,2,3,4)] Subgroup of (Permutation Group with generators [(1,2,3,4)]) generated by [(1,2,3,4)] sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]]) sage: G.center() Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(1,2), (1,2,3,4)]) generated by [()] """ return PermutationGroup(gap_group=self._gap_().Center()) return self.subgroup(gap_group=self._gap_().Center()) def socle(self): r""" Returns the socle of self. The socle of a group $G$ is the subgroup generated by all minimal normal subgroups. EXAMPLES:: sage: G=SymmetricGroup(4) sage: G.socle() Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2)(3,4), (1,4)(2,3)] sage: G.socle().socle() Subgroup of (Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2)(3,4), (1,4)(2,3)]) generated by [(1,3)(2,4), (1,4)(2,3)] """ return self.subgroup(gap_group=self._gap_().Socle()) def frattini_subgroup(self): r""" Returns the Frattini subgroup of self. The Frattini subgroup of a group $G$ is the intersection of all maximal subgroups of $G$. EXAMPLES:: sage: G=PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.frattini_subgroup() Subgroup of (Permutation Group with generators [(2,4), (1,2,3,4)]) generated by [(1,3)(2,4)] sage: G=SymmetricGroup(4) sage: G.frattini_subgroup() Subgroup of (Symmetric group of order 4! as a permutation group) generated by [()] """ return self.subgroup(gap_group=self._gap_().FrattiniSubgroup()) def fitting_subgroup(self): r""" Returns the Fitting subgroup of self. The Fitting subgroup of a group $G$ is the largest nilpotent normal subgroup of $G$. EXAMPLES:: sage: G=PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.fitting_subgroup() Subgroup of (Permutation Group with generators [(2,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)] sage: G=PermutationGroup([[(1,2,3,4)],[(1,2)]]) sage: G.fitting_subgroup() Subgroup of (Permutation Group with generators [(1,2), (1,2,3,4)]) generated by [(1,2)(3,4), (1,3)(2,4)] """ return self.subgroup(gap_group=self._gap_().FittingSubgroup()) def solvable_radical(self): r""" Returns the solvable radical of self. The solvable radical (or just radical) of a group $G$ is the largest solvable normal subgroup of $G$. EXAMPLES:: sage: G=SymmetricGroup(4) sage: G.solvable_radical() Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2), (1,2,3,4)] sage: G=SymmetricGroup(5) sage: G.solvable_radical() Subgroup of (Symmetric group of order 5! as a permutation group) generated by [()] """ return self.subgroup(gap_group=self._gap_().RadicalGroup()) def intersection(self, other): r""" sage: G = DihedralGroup(6) sage: a = PermutationGroupElement("(1,2,3,4)") sage: G.conjugate(a) Permutation Group with generators [(1,5,6,2,3,4), (1,4)(2,6)(3,5)] Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)] The element performing the conjugation can be specified in several ways.  :: sage: G = DihedralGroup(6) sage: strng = "(1,2,3,4)" sage: G.conjugate(strng) Permutation Group with generators [(1,5,6,2,3,4), (1,4)(2,6)(3,5)] Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)] sage: G = DihedralGroup(6) sage: lst = [2,3,4,1] sage: G.conjugate(lst) Permutation Group with generators [(1,5,6,2,3,4), (1,4)(2,6)(3,5)] Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)] sage: G = DihedralGroup(6) sage: cycles = [(1,2,3,4)] sage: G.conjugate(cycles) Permutation Group with generators [(1,5,6,2,3,4), (1,4)(2,6)(3,5)] Permutation Group with generators [(1,4)(2,6)(3,5), (1,5,6,2,3,4)] Conjugation is a group automorphism, so conjugate groups will be isomorphic. :: INPUT: -  self, other - permutation groups OUTPUT: -  D - a direct product of the inputs, returned as a permutation group as well -  pr2 - the projection of D onto other (giving a splitting 1 - self - D - other - 1) EXAMPLES:: sage: G = CyclicPermutationGroup(4) sage: D = G.direct_product(G,False) sage: D Permutation Group with generators [(1,2,3,4), (5,6,7,8)] Permutation Group with generators [(5,6,7,8), (1,2,3,4)] sage: D,iota1,iota2,pr1,pr2 = G.direct_product(G) sage: D; iota1; iota2; pr1; pr2 Permutation Group with generators [(1,2,3,4), (5,6,7,8)] Permutation Group with generators [(5,6,7,8), (1,2,3,4)] Permutation group morphism: From: Cyclic group of order 4 as a permutation group To:   Permutation Group with generators [(1,2,3,4), (5,6,7,8)] To:   Permutation Group with generators [(5,6,7,8), (1,2,3,4)] Defn: Embedding( Group( [ (1,2,3,4), (5,6,7,8) ] ), 1 ) Permutation group morphism: From: Cyclic group of order 4 as a permutation group To:   Permutation Group with generators [(1,2,3,4), (5,6,7,8)] To:   Permutation Group with generators [(5,6,7,8), (1,2,3,4)] Defn: Embedding( Group( [ (1,2,3,4), (5,6,7,8) ] ), 2 ) Permutation group morphism: From: Permutation Group with generators [(1,2,3,4), (5,6,7,8)] From: Permutation Group with generators [(5,6,7,8), (1,2,3,4)] To:   Cyclic group of order 4 as a permutation group Defn: Projection( Group( [ (1,2,3,4), (5,6,7,8) ] ), 1 ) Permutation group morphism: From: Permutation Group with generators [(1,2,3,4), (5,6,7,8)] From: Permutation Group with generators [(5,6,7,8), (1,2,3,4)] To:   Cyclic group of order 4 as a permutation group Defn: Projection( Group( [ (1,2,3,4), (5,6,7,8) ] ), 2 ) sage: g=D([(1,3),(2,4)]); g (1,4,3,2) (1,3)(2,4) """ G = self._gap_().DirectProduct(other._gap_()) G = self._gap_().DirectProduct(other) D = PermutationGroup(gap_group=G) if not maps: return D pr2 = PermutationGroupMorphism_from_gap(D, other, G.Projection(2)) return D, iota1, iota2, pr1, pr2 def subgroup(self, gens): def subgroup(self, gens=None, gap_group=None, domain=None, category=None, canonicalize=True, check=True): """ Wraps the PermutationGroup_subgroup constructor. The argument gens is a list of elements of self. sage: G = PermutationGroup([(1,2,3),(3,4,5)]) sage: g = G((1,2,3)) sage: G.subgroup([g]) Subgroup of Permutation Group with generators [(3,4,5), (1,2,3)] generated by [(1,2,3)] Subgroup of (Permutation Group with generators [(3,4,5), (1,2,3)]) generated by [(1,2,3)] """ return PermutationGroup_subgroup(self, gens) return PermutationGroup_subgroup(self, gens=gens, gap_group=gap_group, domain=None, category=category, canonicalize=canonicalize, check=check) def quotient(self, N): """ # This is currently done using the right regular representation # FIXME: GAP certainly knows of a better way! phi = Q.RegularActionHomomorphism() return PermutationGroup(gap_group = phi.Image()) return PermutationGroup(gap_group=phi.Image()) def quotient_group(self, N): """ sage: G = SymmetricGroup(5) sage: G.conjugacy_classes_representatives() [(), (1,2), (1,2)(3,4), (1,2,3), (1,2,3)(4,5), (1,2,3,4), (1,2,3,4,5)] :: sage: S = SymmetricGroup(['a','b','c']) sage: S.conjugacy_classes_representatives() [(), ('a','b'), ('a','b','c')] AUTHORS: - David Joyner and William Stein (2006-01-04) sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: cl = G.conjugacy_classes_subgroups() sage: cl [Permutation Group with generators [()], Permutation Group with generators [(1,2)(3,4)], Permutation Group with generators [(1,3)(2,4)], Permutation Group with generators [(2,4)], Permutation Group with generators [(1,4)(2,3), (1,2)(3,4)], Permutation Group with generators [(1,3)(2,4), (2,4)], Permutation Group with generators [(1,3)(2,4), (1,2,3,4)], Permutation Group with generators [(1,3)(2,4), (1,2)(3,4), (1,2,3,4)]] [Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [()], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4), (1,4)(2,3)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4), (1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4), (1,2,3,4), (1,3)(2,4)]] :: sage: G = SymmetricGroup(3) sage: G.conjugacy_classes_subgroups() [Permutation Group with generators [()], Permutation Group with generators [(2,3)], Permutation Group with generators [(1,2,3)], Permutation Group with generators [(1,3,2), (1,2)]] [Subgroup of (Symmetric group of order 3! as a permutation group) generated by [()], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3)], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2,3)], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2), (1,3,2)]] AUTHORS: - David Joyner (2006-10) """ cl = self._gap_().ConjugacyClassesSubgroups() return [PermutationGroup(gap_group=sub.Representative()) for sub in cl] return [self.subgroup(gap_group=sub.Representative()) for sub in cl] def subgroups(self): r""" 30030 = 2\cdot 3\cdot 5\cdot 7\cdot 11\cdot 13 takes about twice as long. For faster results, which still exhibit the structure of the possible subgroups, use :meth:conjugacy_classes_subgroups. For faster results, which still exhibit the structure of the possible subgroups, use :meth:conjugacy_classes_subgroups. EXAMPLES:: Permutation Group with generators [(1,2)], Permutation Group with generators [(1,3)], Permutation Group with generators [(1,2,3)], Permutation Group with generators [(1,3,2), (1,2)]] Permutation Group with generators [(1,2), (1,3,2)]] sage: G = CyclicPermutationGroup(14) sage: G.subgroups() sage: A.cosets(S) Traceback (most recent call last): ... ValueError: Subgroup of SymmetricGroup(3) generated by [(1,2)] is not a subgroup of AlternatingGroup(3) ValueError: Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2)] is not a subgroup of Alternating group of order 3!/2 as a permutation group AUTHOR: sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: g = G([(1,3)]) sage: G.normalizer(g) Permutation Group with generators [(2,4), (1,3)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)] sage: g = G([(1,2,3,4)]) sage: G.normalizer(g) Permutation Group with generators [(2,4), (1,2,3,4), (1,3)(2,4)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)(2,4)] sage: H = G.subgroup([G([(1,2,3,4)])]) sage: G.normalizer(H) Permutation Group with generators [(2,4), (1,2,3,4), (1,3)(2,4)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)(2,4)] """ N = self._gap_().Normalizer(g) return PermutationGroup(N.GeneratorsOfGroup()) return self.subgroup(gap_group=self._gap_().Normalizer(g)) def centralizer(self, g): """ sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: g = G([(1,3)]) sage: G.centralizer(g) Permutation Group with generators [(2,4), (1,3)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)] sage: g = G([(1,2,3,4)]) sage: G.centralizer(g) Permutation Group with generators [(1,2,3,4)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)] sage: H = G.subgroup([G([(1,2,3,4)])]) sage: G.centralizer(H) Permutation Group with generators [(1,2,3,4)] Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)] """ N = self._gap_().Centralizer(g) return PermutationGroup(N.GeneratorsOfGroup()) return self.subgroup(gap_group=self._gap_().Centralizer(g)) def isomorphism_type_info_simple_group(self): """ """ if not(self.is_subgroup(other)): raise TypeError("%s must be a subgroup of %s"%(self, other)) return other._gap_().IsNormal(self._gap_()).bool() return other._gap_().IsNormal(self).bool() def is_perfect(self): """ sage: G.is_subgroup(H) True """ G = other gens = self.gens() for i in range(len(gens)): x = gens[i] if not (x in G): return False return True return all((x in other) for x in self.gens()) def is_supersolvable(self): """ """ return self._gap_().IsSupersolvableGroup().bool() def is_transitive(self): def non_fixed_points(self): r""" Returns the list of points not fixed by self, i.e., the subset of self.domain() moved by some element of self. EXAMPLES:: sage: G = PermutationGroup([[(3,4,5)],[(7,10)]]) sage: G.non_fixed_points() [3, 4, 5, 7, 10] sage: G = PermutationGroup([[(2,3,6)],[(9,)]]) # note: 9 is fixed sage: G.non_fixed_points() [2, 3, 6] """ Return True if self is a transitive group, i.e., if the action of self on [1..n] is transitive. pnts = set() for gens in self.gens(): for cycles in gens.cycle_tuples(): for thispnt in cycles: if thispnt not in pnts: pnts.add(thispnt) return sorted(pnts) def fixed_points(self): r""" Returns the list of points fixed by self, i.e., the subset of .domain() not moved by any element of self. EXAMPLES:: sage: G=PermutationGroup([(1,2,3)]) sage: G.fixed_points() [] sage: G=PermutationGroup([(1,2,3),(5,6)]) sage: G.fixed_points() [4] sage: G=PermutationGroup([[(1,4,7)],[(4,3),(6,7)]]) sage: G.fixed_points() [2, 5] """ non_fixed_points = self.non_fixed_points() return [i for i in self.domain() if i not in non_fixed_points] def is_transitive(self, domain=None): """ Returns True if self acts transitively on domain. A group $G$ acts transitively on set $S$ if for all $x,y\in S$ there is some $g\in G$ such that $x^g=y$. EXAMPLES:: sage: G = SymmetricGroup(5) sage: G.is_transitive() False :: sage: G = PermutationGroup([[(1,2,3,4,5)],[(1,2)]]) #S_5 on [1..5] sage: G.is_transitive([1,4,5]) True sage: G.is_transitive([2..6]) False sage: G.is_transitive(G.non_fixed_points()) True sage: H = PermutationGroup([[(1,2,3)],[(4,5,6)]]) sage: H.is_transitive(H.non_fixed_points()) False Note that this differs from the definition in GAP, where IsTransitive returns whether the group is transitive on the set of points moved by the group. sage: gap(G).IsTransitive() true """ return self._gap_().IsTransitive(self._set_gap()).bool() #If the domain is not a subset of self.domain(), then the #action isn't transitive. try: domain = self._domain_gap(domain) except ValueError: return False return self._gap_().IsTransitive(domain).bool() def is_primitive(self, domain=None): r""" Returns True if self acts primitively on domain. A group $G$ acts primitively on a set $S$ if 1. $G$ acts transitively on $S$ and 2. the action induces no non-trivial block system on $S$. INPUT: - domain (optional) EXAMPLES: By default, test for primitivity of self on its domain. sage: G = PermutationGroup([[(1,2,3,4)],[(1,2)]]) sage: G.is_primitive() True sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.is_primitive() False You can specify a domain on which to test primitivity:: sage: G = PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.is_primitive([1..4]) False sage: G.is_primitive([1,2,3]) True sage: G = PermutationGroup([[(3,4,5,6)],[(3,4)]]) #S_4 on [3..6] sage: G.is_primitive(G.non_fixed_points()) True """ #If the domain is not a subset of self.domain(), then the #action isn't primitive. try: domain = self._domain_gap(domain) except ValueError: return False return self._gap_().IsPrimitive(domain).bool() def is_semi_regular(self, domain=None): r""" Returns True if self acts semi-regularly on domain. A group $G$ acts semi-regularly on a set $S$ if the point stabilizers of $S$ in $G$ are trivial. domain is optional and may take several forms. See examples. EXAMPLES:: sage: G = PermutationGroup([[(1,2,3,4)]]) sage: G.is_semi_regular() True sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]]) sage: G.is_semi_regular() False You can pass in a domain to test semi-regularity:: sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]]) sage: G.is_semi_regular([1..4]) True sage: G.is_semi_regular(G.non_fixed_points()) False """ try: domain = self._domain_gap(domain) except ValueError: return False return self._gap_().IsSemiRegular(domain).bool() def is_regular(self, domain=None): r""" Returns True if self acts regularly on domain. A group $G$ acts regularly on a set $S$ if 1. $G$ acts transitively on $S$ and 2. $G$ acts semi-regularly on $S$. EXAMPLES:: sage: G = PermutationGroup([[(1,2,3,4)]]) sage: G.is_regular() True sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]]) sage: G.is_regular() False You can pass in a domain on which to test regularity:: sage: G = PermutationGroup([[(1,2,3,4)],[(5,6)]]) sage: G.is_regular([1..4]) True sage: G.is_regular(G.non_fixed_points()) False """ try: domain = self._domain_gap(domain) except ValueError: return False return self._gap_().IsRegular(domain).bool() def normalizes(self, other): r""" Returns True if the group other is normalized by self. In the last example, G and H are disjoint, so each normalizes the other. """ return self._gap_().IsNormal(other._gap_()).bool() return self._gap_().IsNormal(other).bool() ############## Series ###################### sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]]) sage: CS = G.composition_series() sage: CS[3] Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(1,2), (1,2,3)(4,5)]) generated by [()] """ current_randstate().set_seed_gap() CS = self._gap_().CompositionSeries() return [PermutationGroup(gap_group=group) for group in CS] return [self.subgroup(gap_group=group) for group in CS] def derived_series(self): """ """ current_randstate().set_seed_gap() DS = self._gap_().DerivedSeries() return [PermutationGroup(gap_group=group) for group in DS] return [self.subgroup(gap_group=group) for group in DS] def lower_central_series(self): """ """ current_randstate().set_seed_gap() LCS = self._gap_().LowerCentralSeriesOfGroup() return [PermutationGroup(gap_group=group) for group in LCS] return [self.subgroup(gap_group=group) for group in LCS] def molien_series(self): r""" True """ NS = self._gap_().NormalSubgroups() return [PermutationGroup(gap_group=group) for group in NS] return [self.subgroup(gap_group=group) for group in NS] def poincare_series(self, p=2, n=10): """ sage: G = PermutationGroup(['(1,2,3)', '(2,3)']) sage: G.sylow_subgroup(2) Permutation Group with generators [(2,3)] Subgroup of (Permutation Group with generators [(2,3), (1,2,3)]) generated by [(2,3)] sage: G.sylow_subgroup(5) Permutation Group with generators [()] Subgroup of (Permutation Group with generators [(2,3), (1,2,3)]) generated by [()] """ return PermutationGroup(gap_group=self._gap_().SylowSubgroup(p)) return self.subgroup(gap_group=self._gap_().SylowSubgroup(p)) def upper_central_series(self): """ sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.upper_central_series() [Permutation Group with generators [()]] [Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()]] """ current_randstate().set_seed_gap() UCS = self._gap_().UpperCentralSeriesOfGroup() return [PermutationGroup(gap_group=group) for group in UCS] return [self.subgroup(gap_group=group) for group in UCS] class PermutationGroup_subgroup(PermutationGroup_generic): """ sage: G = CyclicPermutationGroup(4) sage: gens = G.gens() sage: H = DihedralGroup(4) sage: PermutationGroup_subgroup(H,list(gens)) Subgroup of Dihedral group of order 8 as a permutation group generated by [(1,2,3,4)] sage: K=PermutationGroup_subgroup(H,list(gens)) sage: H.subgroup(gens) Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] sage: K = H.subgroup(gens) sage: K.list() [(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)] sage: K.ambient_group() sage: K.gens() [(1,2,3,4)] """ def __init__(self, ambient, gens, from_group = False, check=True, canonicalize=True): def __init__(self, ambient, gens=None, gap_group=None, domain=None, category=None, canonicalize=True, check=True): r""" Initialization method for the PermutationGroup_subgroup class. sage: H = CyclicPermutationGroup(4) sage: gens = H.gens(); gens [(1,2,3,4)] sage: S = PermutationGroup_subgroup(G,gens) sage: S = G.subgroup(gens) sage: S Subgroup of Dihedral group of order 8 as a permutation group generated by [(1,2,3,4)] Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] sage: S.list() [(), (1,2,3,4), (1,3)(2,4), (1,4,3,2)] sage: S.ambient_group() """ if not isinstance(ambient, PermutationGroup_generic): raise TypeError, "ambient (=%s) must be perm group."%ambient if not isinstance(gens, list): raise TypeError, "gens (=%s) must be a list"%gens self.__ambient_group = ambient self._gens = gens cmd = 'Group(%s)'%gens cmd = cmd.replace("'","")  # get rid of quotes self._gap_string = cmd G = ambient if domain is None: domain = ambient.domain() if category is None: category = ambient.category() PermutationGroup_generic.__init__(self, gens=gens, gap_group=gap_group, domain=domain, category=category, canonicalize=canonicalize) self._ambient_group = ambient if check: for g in gens: if g not in G: for g in self.gens(): if g not in ambient: raise TypeError, "each generator must be in the ambient group" self.__ambient_group = G PermutationGroup_generic.__init__(self, gens, canonicalize=canonicalize) def __cmp__(self, other): r""" Compare self and other. First, self and other are compared as permutation groups, see :method:sage.groups.perm_gps.permgroup.PermutationGroup_generic.__cmp__. Second, if both are equal, the ambient groups are compared, where (if necessary) other is considered a subgroup of itself. First, self and other are compared as permutation groups, see :method:PermutationGroup_generic.__cmp__. Second, if both are equal, the ambient groups are compared, where (if necessary) other is considered a subgroup of itself. EXAMPLES:: sage: G Symmetric group of order 6! as a permutation group sage: G3 Subgroup of SymmetricGroup(6) generated by [(1,2), (1,2,3,4,5,6)] Subgroup of (Symmetric group of order 6! as a permutation group) generated by [(1,2), (1,2,3,4,5,6)] sage: G is G3 False sage: G == G3 # as permutation groups sage: gens = H.gens() sage: S = PermutationGroup_subgroup(G, list(gens)) sage: S Subgroup of Dihedral group of order 8 as a permutation group generated by [(1,2,3,4)] Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] sage: S._repr_() 'Subgroup of Dihedral group of order 8 as a permutation group generated by [(1,2,3,4)]' 'Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]' """ s = "Subgroup of %s generated by %s"%(self.ambient_group(), self.gens()) s = "Subgroup of (%s) generated by %s"%(self.ambient_group(), self.gens()) return s def _latex_(self): sage: gens = H.gens() sage: S = PermutationGroup_subgroup(G, list(gens)) sage: latex(S) Subgroup of Dihedral group of order 8 as a permutation group generated by [(1,2,3,4)] Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] sage: S._latex_() 'Subgroup of Dihedral group of order 8 as a permutation group generated by [(1,2,3,4)]' 'Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]' """ return self._repr_() sage: S.ambient_group() == G True """ return self.__ambient_group def gens(self): return self._ambient_group def is_normal(self, other=None): """ Return the generators for this subgroup. Return True if this group is a normal subgroup of other.  If other is not specified, then it is assumed to be the ambient group. EXAMPLES: An example involving the dihedral group on four elements, D_8:: EXAMPLES:: sage: G = DihedralGroup(4) sage: H = CyclicPermutationGroup(4) sage: gens = H.gens() sage: S = PermutationGroup_subgroup(G, list(gens)) sage: S.gens() [(1,2,3,4)] sage: S.gens() == list(H.gens()) True sage: S = SymmetricGroup(['a','b','c']) sage: H = S.subgroup([('a', 'b', 'c')]); H Subgroup of (Symmetric group of order 3! as a permutation group) generated by [('a','b','c')] sage: H.is_normal() True """ return self._gens if other is None: other = self.ambient_group() return PermutationGroup_generic.is_normal(self, other)
• ## sage/groups/perm_gps/permgroup_element.pxd

diff --git a/sage/groups/perm_gps/permgroup_element.pxd b/sage/groups/perm_gps/permgroup_element.pxd
 a cdef Element _gap_element cdef __tuple cdef PermutationGroupElement _new_c(self) cpdef _gap_list(self) cpdef list(self) cdef public __custom_name
• ## sage/groups/perm_gps/permgroup_element.pyx

diff --git a/sage/groups/perm_gps/permgroup_element.pyx b/sage/groups/perm_gps/permgroup_element.pyx
 a from sage.rings.all      import ZZ, Integer, is_MPolynomial, is_Polynomial from sage.matrix.all     import MatrixSpace from sage.interfaces.all import gap, is_GapElement, is_ExpectElement from sage.sets.finite_enumerated_set import FiniteEnumeratedSet import sage.structure.coerce as coerce import operator from sage.rings.integer import Integer from sage.rings.fast_arith cimport arith_llong cdef arith_llong arith = arith_llong() cdef extern from *: #import permgroup_named def make_permgroup_element(G, x): G._deg = len(x) """ Returns a PermutationGroupElement given the permutation group G and the permutation x in list notation. This is function is used when unpickling old (pre-domain) versions of permutation groups and their elements.  This now does a bit of processing and calls :func:make_permgroup_element_v2 which is used in unpickling the current PermutationGroupElements. EXAMPLES:: sage: from sage.groups.perm_gps.permgroup_element import make_permgroup_element sage: S = SymmetricGroup(3) sage: make_permgroup_element(S, [1,3,2]) (2,3) """ domain = FiniteEnumeratedSet(range(1, len(x)+1)) return make_permgroup_element_v2(G, x, domain) def make_permgroup_element_v2(G, x, domain): """ Returns a PermutationGroupElement given the permutation group G, the permutation x in list notation, and the domain domain of the permutation group. This is function is used when unpickling permutation groups and their elements. EXAMPLES:: sage: from sage.groups.perm_gps.permgroup_element import make_permgroup_element_v2 sage: S = SymmetricGroup(3) sage: make_permgroup_element_v2(S, [1,3,2], S.domain()) (2,3) """ # Note that it has to be in-sync with the __init__ method of # PermutationGroup_generic since the elements have to be created # before the PermutationGroup_generic is initialized.  The # constructor for PermutationGroupElement requires that # G._domain_to_gap be set. G._domain = domain G._deg = len(domain) G._domain_to_gap = dict([(key, i+1) for i, key in enumerate(domain)]) G._domain_from_gap = dict([(i+1, key) for i, key in enumerate(domain)]) return G(x, check=False) def is_PermutationGroupElement(x): """ Returns True if x is a PermutationGroupElement. EXAMPLES:: sage: p = PermutationGroupElement([(1,2),(3,4,5)]) sage: from sage.groups.perm_gps.permgroup_element import is_PermutationGroupElement sage: is_PermutationGroupElement(p) True """ return isinstance(x, PermutationGroupElement) def gap_format(x): """ Put a permutation in Gap format, as a string. """ if isinstance(x, list) and not isinstance(x[0], tuple): return gap.eval('PermList(%s)' % x) x = str(x).replace(' ','').replace('\n','') return x.replace('),(',')(').replace('[','').replace(']','').replace(',)',')') def string_to_tuples(g): """ EXAMPLES:: g = '[' + g + ']' return sage_eval(g, preparse=False) def standardize_generator(g, convert_dict=None): """ Standardizes the input for permutation group elements to a list of tuples.  This was factored out of the PermutationGroupElement.__init__ since PermutationGroup_generic.__init__ needs to do the same computation in order to compute the domain of a group when it's not explicitly specified. INPUT: - g - a list, tuple, string, GapElement, PermuationGroupElement - convert_dict - (optional) a dictionary used to convert the points to a number compatible with GAP. OUTPUT: The permutation in as a list of cycles. EXAMPLES:: sage: from sage.groups.perm_gps.permgroup_element import standardize_generator sage: standardize_generator('(1,2)') [(1, 2)] sage: p = PermutationGroupElement([(1,2)]) sage: standardize_generator(p) [(1, 2)] sage: standardize_generator(p._gap_()) [(1, 2)] sage: standardize_generator((1,2)) [(1, 2)] sage: standardize_generator([(1,2)]) [(1, 2)] :: sage: d = {'a': 1, 'b': 2} sage: p = SymmetricGroup(['a', 'b']).gen(0); p ('a','b') sage: standardize_generator(p, convert_dict=d) [(1, 2)] sage: standardize_generator(p._gap_(), convert_dict=d) [(1, 2)] sage: standardize_generator(('a','b'), convert_dict=d) [(1, 2)] sage: standardize_generator([('a','b')], convert_dict=d) [(1, 2)] """ from sage.interfaces.gap import GapElement from sage.combinat.permutation import Permutation from sage.libs.pari.gen import gen if isinstance(g, gen): g = list(g) needs_conversion = True if isinstance(g, GapElement): g = str(g) needs_conversion = False if isinstance(g, PermutationGroupElement): g = g.cycle_tuples() if isinstance(g, str): g = string_to_tuples(g) if isinstance(g, tuple) and (len(g) == 0 or not isinstance(g[0], tuple)): g = [g] #Get the permutation in list notation if PyList_CheckExact(g) and (len(g) == 0 or not PY_TYPE_CHECK(g[0], tuple)): if convert_dict is not None and needs_conversion: g = [convert_dict[x] for x in g] #FIXME: Currently, we need to verify that g defines an actual #permutation since the constructor Permutation does not #perform this check.  When it does, we should remove this code. #See #8392 if set(g) != set(range(1, len(g)+1)): raise ValueError, "Invalid permutation vector: %s"%g return Permutation(g).cycle_tuples() else: if convert_dict is not None and needs_conversion: g = [tuple([convert_dict[x] for x in cycle])for cycle in g] return g cdef class PermutationGroupElement(MultiplicativeGroupElement): """ sage: PermutationGroupElement([()]) () """ from sage.interfaces.gap import GapElement from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.perm_gps.permgroup import PermutationGroup_generic from sage.combinat.permutation import from_cycles #Convert GAP elements to strings if isinstance(g, GapElement): g = str(g) elif isinstance(g, PermutationGroupElement): g = g.list() #Convert all the string to tuples if isinstance(g, str): g = string_to_tuples(g) convert_dict = parent._domain_to_gap if parent is not None else None try: v = standardize_generator(g, convert_dict) except KeyError: raise ValueError, "Invalid permutation vector: %s" % g if isinstance(g, tuple) and (len(g) == 0 or not isinstance(g[0], tuple)): g = [g] #Get the permutation in list notation if PyList_CheckExact(g) and (len(g) == 0 or not PY_TYPE_CHECK(g[0], tuple)): v = g if len(g) != 0 else [1] self.__gap = 'PermList(%s)'%v else: from sage.combinat.permutation import Permutation v = Permutation(g)._list self.__gap = str(g)[1:-1].replace('), (',')(').replace(',)',')').strip(',') degree = max([1] + [max(cycle+(1,)) for cycle in v]) v = from_cycles(degree, v) self.__gap = 'PermList(%s)'%v if parent is None: parent = SymmetricGroup(max(len(v),1)) parent = SymmetricGroup(len(v)) if check and parent.__class__ != SymmetricGroup: if not (parent is None or isinstance(parent, PermutationGroup_generic)): raise TypeError, 'parent must be a permutation group' if parent is not None: P = parent._gap_() if not P.parent()(self.__gap) in P: raise TypeError, 'permutation %s not in %s'%(self.__gap, parent) raise TypeError, 'permutation %s not in %s'%(g, parent) Element.__init__(self, parent) sage_free(self.perm) def __reduce__(self): return make_permgroup_element, (self._parent, self.list()) """ Returns a function and its arguments needed to create this permutation group element.  This is used in pickling. EXAMPLES:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]); g (1,2,3)(4,5) sage: func, args = g.__reduce__() sage: func(*args) (1,2,3)(4,5) """ return make_permgroup_element_v2, (self._parent, self.list(), self._parent.domain()) cdef PermutationGroupElement _new_c(self): cdef PermutationGroupElement other = PY_NEW_SAME_TYPE(self) other.perm = sage_malloc(sizeof(int) * other.n) return other def _gap_(self, G=None): if self._gap_element is None or \ (G is not None and self._gap_element._parent is not G): if G is None: import sage.interfaces.gap G = sage.interfaces.gap.gap self._gap_element = G("PermList(%s)" % self.list()) def _gap_(self, gap=None): """ Returns EXAMPLES:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]); g (1,2,3)(4,5) sage: a = g._gap_(); a (1,2,3)(4,5) sage: g._gap_() is g._gap_() True Note that only one GapElement is cached: sage: gap2 = Gap() sage: b = g._gap_(gap2) sage: c = g._gap_() sage: a is c False """ if (self._gap_element is None or (gap is not None and self._gap_element._parent is not gap)): if gap is None: from sage.interfaces.gap import gap self._gap_element = gap(self._gap_init_()) return self._gap_element def _gap_init_(self): """ Returns a GAP string representation for this PermutationGroupElement. EXAMPLES:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]) sage: g._gap_init_() 'PermList([2, 3, 1, 5, 4])' """ return 'PermList(%s)'%self._gap_list() def _repr_(self): """ Return string representation of this permutation. EXAMPLES: We create the permutation (1,2,3)(4,5) and print it. :: EXAMPLES: We create the permutation (1,2,3)(4,5) and print it. :: sage: g = PermutationGroupElement([(1,2,3),(4,5)]) sage: g._repr_() '(1,2,3)(4,5)' sage: g (1,2,3)(4,5) """ cycles = self.cycle_tuples() if len(cycles) == 0: return '()' return ''.join([str(c) for c in cycles]).replace(', ',',') return self.cycle_string() def _latex_(self): return str(self) r""" Returns a latex representation of this permutation. EXAMPLES:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]) sage: latex(g) (1,2,3)(4,5) sage: S = SymmetricGroup(['a', 'b']) sage: latex(S.gens()) \left[(\verb|a|,\verb|b|)\right] """ from sage.misc.latex import latex return "".join(["(" + ",".join([latex(x) for x in cycle])+")" for cycle in self.cycle_tuples()]) def __getitem__(self, i): """ sage: g(x) Traceback (most recent call last): ... ValueError: Must be an integer, list, tuple or string. ValueError: Must be in the domain or a list, tuple or string. sage: g(3/2) Traceback (most recent call last): ... ValueError: Must be an integer, list, tuple or string. ValueError: Must be in the domain or a list, tuple or string. """ to_gap = self._parent._domain_to_gap from_gap = self._parent._domain_from_gap cdef int j if isinstance(i,(list,tuple,str)): try: i = to_gap[i] except (KeyError, TypeError): # We currently have to include this to maintain the # current behavior where if you pass in an integer which # is not in the domain of the permutation group, then that # integer itself will be returned. if isinstance(i, (long, int, Integer)): return i if not isinstance(i,(list,tuple,str)): raise ValueError, "Must be in the domain or a list, tuple or string." permuted = [i[self.perm[j]] for j from 0 <= j < self.n] if PY_TYPE_CHECK(i, tuple): permuted = tuple(permuted) permuted += i[self.n:] return permuted else: if not isinstance(i, (int, Integer)): raise ValueError("Must be an integer, list, tuple or string.") j = i if 1 <= j <= self.n: return self.perm[j-1]+1 return from_gap[self.perm[j-1]+1] else: return i return from_gap[i] cpdef _act_on_(self, x, bint self_on_left): """ return left(tuple(sigma_x)) cpdef MonoidElement _mul_(left, MonoidElement _right): """ EXAMPLES:: sage: S = SymmetricGroup(['a', 'b']) sage: s = S([('a', 'b')]); s ('a','b') sage: s*s () """ cdef PermutationGroupElement prod = left._new_c() cdef PermutationGroupElement right = _right cdef int i for i from 0 <= i < self.n: inv.perm[self.perm[i]] = i return inv cpdef _gap_list(self): """ Returns this permutation in list notation compatible with the GAP numbering. EXAMPLES:: sage: S = SymmetricGroup(3) sage: s = S.gen(0); s (1,2,3) sage: s._gap_list() [2, 3, 1] :: sage: S = SymmetricGroup(['a', 'b', 'c']) sage: s = S.gen(0); s ('a','b','c') sage: s._gap_list() [2, 3, 1] """ cdef int i return [self.perm[i]+1 for i from 0 <= i < self.n] def _gap_cycle_string(self): """ Returns a cycle string for this permutation compatible with the GAP numbering. EXAMPLES:: sage: S = SymmetricGroup(3) sage: s = S.gen(0); s (1,2,3) sage: s._gap_cycle_string() '(1,2,3)' :: sage: S = SymmetricGroup(['a', 'b', 'c']) sage: s = S.gen(0); s ('a','b','c') sage: s._gap_cycle_string() '(1,2,3)' """ from sage.combinat.permutation import Permutation return Permutation(self._gap_list()).cycle_string() cpdef list(self): """ Returns list of the images of the integers from 1 to n under this (1,2) sage: x.list() [2, 1, 3, 4] TESTS:: sage: S = SymmetricGroup(0) sage: x = S.one(); x () sage: x.list() [] """ cdef int i return [self.perm[i]+1 for i from 0 <= i < self.n] #We need to do this to handle the case of SymmetricGroup(0) #where the domain is (), but the permutation group element has #an underlying representation of [1].  The 1 doesn't #correspond to anything in the domain if len(self._parent._domain) == 0: return [] else: from_gap = self._parent._domain_from_gap return [from_gap[self.perm[i]+1] for i from 0 <= i < self.n] def __hash__(self): """ 1592966088          # 32-bit 2865702456085625800 # 64-bit """ return hash(self.tuple()) return hash(tuple(self._gap_list())) def tuple(self): """ Return tuple of images of integers under self. Return tuple of images of the domain under self. EXAMPLES:: sage: s = G([2,1,5,3,4]) sage: s.tuple() (2, 1, 5, 3, 4) sage: S = SymmetricGroup(['a', 'b']) sage: S.gen().tuple() ('b', 'a') """ if self.__tuple is None: self.__tuple = tuple(self.list()) sage: x.dict() {1: 2, 2: 1, 3: 3, 4: 4} """ from_gap = self._parent._domain_from_gap cdef int i u = {} for i from 0 <= i < self.n: u[i+1] = self.perm[i]+1 u[i+1] = from_gap[self.perm[i]+1] return u def order(self): def orbit(self, n, bint sorted=True): """ Returns the orbit of the integer n under this group element, as a sorted list of integers. element, as a sorted list. EXAMPLES:: [1, 2, 3] sage: g.orbit(10) [10] :: sage: s = SymmetricGroup(['a', 'b']).gen(0); s ('a','b') sage: s.orbit('a') ['a', 'b'] """ to_gap = self._parent._domain_to_gap from_gap = self._parent._domain_from_gap try: n = to_gap[n] except KeyError: return [n] cdef int i = n cdef int start = i if 1 <= i <= self.n: L = [i] L = [from_gap[i]] i = self.perm[i-1]+1 while i != start: PyList_Append(L,i) PyList_Append(L,from_gap[i]) i = self.perm[i-1]+1 if sorted: L.sort() return L else: return [n] return from_gap[n] def cycles(self): """ sage_free(seen) return L def cycle_tuples(self): def cycle_tuples(self, singletons=False): """ Return self as a list of disjoint cycles, represented as tuples rather than permutation group elements. INPUT: - singletons - boolean (default: False) whether or not consider the cycle that correspond to fixed point EXAMPLES:: sage: p = PermutationGroupElement('(2,6)(4,5,1)') sage: p.cycle_tuples() [(1, 4, 5), (2, 6)] sage: p.cycle_tuples(singletons=True) [(1, 4, 5), (2, 6), (3,)] EXAMPLES:: sage: S = SymmetricGroup(4) sage: S.gen(0).cycle_tuples() [(1, 2, 3, 4)] :: sage: S = SymmetricGroup(['a','b','c','d']) sage: S.gen(0).cycle_tuples() [('a', 'b', 'c', 'd')] sage: S([('a', 'b'), ('c', 'd')]).cycle_tuples() [('a', 'b'), ('c', 'd')] """ from_gap = self._parent._domain_from_gap L = [] cdef int i, k cdef bint* seen = sage_malloc(sizeof(bint) * self.n) for i from 0 <= i < self.n: seen[i] = 0 for i from 0 <= i < self.n: if seen[i] or self.perm[i] == i: if seen[i]: continue cycle = [i+1] k = self.perm[i] while k != i: PyList_Append(cycle, k+1) seen[k] = 1 k = self.perm[k] PyList_Append(L, tuple(cycle)) if self.perm[i] == i: if singletons: PyList_Append(L, (from_gap[i+1],)) # it is not necessary to put seen[i] to 1 as we will never # see i again else: continue else: cycle = [from_gap[i+1]] k = self.perm[i] while k != i: PyList_Append(cycle, from_gap[k+1]) seen[k] = 1 k = self.perm[k] PyList_Append(L, tuple(cycle)) sage_free(seen) return L def cycle_string(self, singletons=False): """ Return string representation of this permutation. EXAMPLES:: sage: g = PermutationGroupElement([(1,2,3),(4,5)]) sage: g.cycle_string() '(1,2,3)(4,5)' sage: g = PermutationGroupElement([3,2,1]) sage: g.cycle_string(singletons=True) '(1,3)(2)' """ cycles = self.cycle_tuples(singletons) if len(cycles) == 0: return '()' return ''.join([repr(c) for c in cycles]).replace(', ',',').replace(',)',')') def has_descent(self, i, side = "right", positive = False): """ INPUT: True sage: S._test_has_descent() """ to_gap = self._parent._domain_to_gap from_gap = self._parent._domain_from_gap if side == "right": self = ~self try: if not self.parent()._has_natural_set(): set = self.parent()._set pos = set.index(i) i1  = set[pos+1] res = set.index(self(i)) > set.index(self(i1)) return res is not positive except AttributeError: pass return (self(i) > self(i+1)) is not positive i1 = from_gap[to_gap[i]+1] except KeyError: return False return (to_gap[self(i)] > to_gap[self(i1)]) is not positive def matrix(self): """ entries[i, self.perm[i]] = 1 return M(entries) def word_problem(g, words, display=True): def word_problem(self, words, display=True): """ G and H are permutation groups, g in G, H is a subgroup of G generated by a list (words) of elements of G. If g is in H, return EXAMPLE:: sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]], canonicalize=False) sage: g1 = G.gens()[0] sage: g2 = G.gens()[1] sage: g1, g2 = G.gens() sage: h = g1^2*g2*g1 sage: h.word_problem([g1,g2], False) ('x1^2*x2^-1*x1', '(1,2,3)(4,5)^2*(3,4)^-1*(1,2,3)(4,5)') [['(1,2,3)(4,5)', 2], ['(3,4)', -1], ['(1,2,3)(4,5)', 1]] ('x1^2*x2^-1*x1', '(1,2,3)(4,5)^2*(3,4)^-1*(1,2,3)(4,5)') """ if not self._parent._has_natural_domain(): raise NotImplementedError import copy from sage.groups.perm_gps.permgroup import PermutationGroup from sage.interfaces.all import gap G = gap(words[0].parent()) g = words[0].parent()(g) gensH = gap(words) H = gensH.Group() hom = G.EpimorphismFromFreeGroup() ans = hom.PreImagesRepresentative(gap(g)) g = words[0].parent()(self) H = gap.Group(words) ans = G.EpimorphismFromFreeGroup().PreImagesRepresentative(g) l1 = str(ans) l2 = copy.copy(l1)
• ## sage/groups/perm_gps/permgroup_morphism.py

diff --git a/sage/groups/perm_gps/permgroup_morphism.py b/sage/groups/perm_gps/permgroup_morphism.py
 a sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, map(H, G.gens())) sage: phi.image(G) Permutation Group with generators [(1,2,3,4)] Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] sage: phi.kernel() Permutation Group with generators [()] Subgroup of (Cyclic group of order 4 as a permutation group) generated by [()] sage: phi.image(g) (1,2,3,4) sage: phi(g) sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, [1]) sage: phi.kernel() Permutation Group with generators [(1,2,3,4)] Subgroup of (Cyclic group of order 4 as a permutation group) generated by [(1,2,3,4)] :: sage: G.is_isomorphic(pr1.kernel()) True """ return PermutationGroup(gap_group=self._gap_().Kernel()) return self.domain().subgroup(gap_group=self._gap_().Kernel()) def image(self, J): """ sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, map(H, G.gens())) sage: phi.image(G) Permutation Group with generators [(1,2,3,4)] Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] sage: phi.image(g) (1,2,3,4) sage: H = D[0] sage: pr1 = D[3] sage: pr1.image(G) Permutation Group with generators [(3,7,5)(4,8,6), (1,2,6)(3,4,8)] Subgroup of (The projective special linear group of degree 2 over Finite Field of size 7) generated by [(3,7,5)(4,8,6), (1,2,6)(3,4,8)] sage: G.is_isomorphic(pr1.image(G)) True """ H = self.codomain() if J in self.domain(): J = PermutationGroup([J]) G = self._gap_().Image(J) return PermutationGroup(gap_group=G).gens()[0] return H.subgroup(gap_group=G).gens()[0] else: G = self._gap_().Image(J) return PermutationGroup(gap_group=G) return H.subgroup(gap_group=G) def __call__(self, g): """ sage: H = G.subgroup([G([(1,2,3,4)])]) sage: PermutationGroupMorphism_from_gap(H, G, gap.Identity) Permutation group morphism: From: Subgroup of Permutation Group with generators [(1,2)(3,4), (1,2,3,4)] generated by [(1,2,3,4)] From: Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)] To:   Permutation Group with generators [(1,2)(3,4), (1,2,3,4)] Defn: Identity """
• ## sage/groups/perm_gps/permgroup_named.py

diff --git a/sage/groups/perm_gps/permgroup_named.py b/sage/groups/perm_gps/permgroup_named.py
 a -- PSp(2n,q), projective symplectic linear group of $2n\times 2n$ matrices over the finite field GF(q) -- PSU(n,q), projective special unitary group of $n\times n$ matrices having -- PSU(n,q), projective special unitary group of $n \times n$ matrices having coefficients in the finite field $GF(q^2)$ that respect a fixed nondegenerate sesquilinear form, of determinant 1. from sage.groups.abelian_gps.abelian_group import AbelianGroup from sage.misc.functional import is_even from sage.misc.cachefunc import cached_method from sage.misc.misc import deprecated_function_alias from sage.groups.perm_gps.permgroup import PermutationGroup_generic from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.categories.enumerated_sets import EnumeratedSets from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.family import Family class PermutationGroup_unique(UniqueRepresentation, PermutationGroup_generic): @staticmethod def __classcall__(cls, *args, **kwds): """ This makes sure that domain is a FiniteEnumeratedSet before it gets passed on to the __init__ method. EXAMPLES:: sage: SymmetricGroup(['a','b']).domain() #indirect doctest {'a', 'b'} """ domain = kwds.pop('domain', None) if domain is not None: if domain not in FiniteEnumeratedSets(): domain = FiniteEnumeratedSet(domain) kwds['domain'] = domain return super(PermutationGroup_unique, cls).__classcall__(cls, *args, **kwds) def __eq__(self, other): """ Overrides the default equality testing provided by UniqueRepresentation by forcing a call to :meth:.__cmp__. """ Overrides the default equality testing provided by UniqueRepresentation by forcing a call to :meth:.__cmp__. EXAMPLES:: EXAMPLES:: sage: G = SymmetricGroup(6) sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))]) sage: G == G3 True """ return self.__cmp__(other) == 0 sage: G = SymmetricGroup(6) sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))]) sage: G == G3 True """ return self.__cmp__(other) == 0 class PermutationGroup_symalt(PermutationGroup_unique): """ @staticmethod def __classcall__(cls, n): def __classcall__(cls, domain): """ Normalizes the input of the constructor into a set sage: SymmetricGroup(-1) Traceback (most recent call last): ... ValueError: n (=-1) must be an integer >= 0 or a list ValueError: domain (=-1) must be an integer >= 0 or a list """ if not isinstance(n, (tuple,list)): try: n = Integer(n) except TypeError: raise ValueError, "n (=%s) must be an integer >= 0 or a list (but n has type %s)"%(n,type(n)) else: if n < 0: raise ValueError, "n (=%s) must be an integer >= 0 or a list"%n n = range(1, n+1) if domain not in FiniteEnumeratedSets(): if not isinstance(domain, (tuple, list)): try: domain = Integer(domain) except TypeError: raise ValueError, "domain (=%s) must be an integer >= 0 or a finite set (but domain has type %s)"%(domain,type(domain)) if domain < 0: raise ValueError, "domain (=%s) must be an integer >= 0 or a list"%domain else: domain = range(1, domain+1) v = FiniteEnumeratedSet(domain) else: v = domain try: v = tuple(Integer(z) for z in n) except TypeError: raise ValueError, "each entry of list must be an integer" return super(PermutationGroup_symalt, cls).__classcall__(cls, domain=v) if v and min(v) < 1: # for SymmetricGroup(0), v is empty raise ValueError, "each element of list must be positive" return super(PermutationGroup_symalt, cls).__classcall__(cls, v) def set(self): """ Returns the list of positive integers on which this group acts. EXAMPLES: sage: SymmetricGroup(3).set() (1, 2, 3) sage: SymmetricGroup([2,3,4]).set() (2, 3, 4) sage: AlternatingGroup(3).set() (1, 2, 3) sage: AlternatingGroup([2,3,4]).set() (2, 3, 4) """ return self._set @cached_method def _has_natural_set(self): """ Returns true if the underlying set is of the form (1,...,n) EXAMPLES:: sage: SymmetricGroup(3)._has_natural_set() True sage: SymmetricGroup((1,2,3))._has_natural_set() True sage: SymmetricGroup((1,3))._has_natural_set() False sage: SymmetricGroup((3,2,1))._has_natural_set() False """ set = self.set() return set == tuple(range(1,len(set)+1)) def __str__(self): """ EXAMPLES: sage: S = SymmetricGroup([2,3,7]); S Symmetric group of order 3! as a permutation group sage: str(S) 'SymmetricGroup((2, 3, 7))' sage: S = SymmetricGroup(5); S Symmetric group of order 5! as a permutation group sage: str(S) 'SymmetricGroup(5)' sage: A = AlternatingGroup([2,3,7]); A Alternating group of order 3!/2 as a permutation group sage: str(A) 'AlternatingGroup((2, 3, 7))' """ set = self._set if self._has_natural_set(): set = len(set) return "%s(%s)"%(self._gap_name, set) set = deprecated_function_alias(PermutationGroup_generic.domain, 'Sage Version 4.7.1') class SymmetricGroup(PermutationGroup_symalt): def __init__(self, _set): def __init__(self, domain=None): """ The full symmetric group of order $n!$, as a permutation group. If n is a list or tuple of positive integers then it returns the sage: G = SymmetricGroup([1,2,4,5]) sage: G Symmetric group of order 4! as a permutation group sage: G.set() (1, 2, 4, 5) sage: G.domain() {1, 2, 4, 5} sage: G = SymmetricGroup(4) sage: G Symmetric group of order 4! as a permutation group sage: G.set() (1, 2, 3, 4) sage: G.domain() {1, 2, 3, 4} sage: G.category() Join of Category of finite permutation groups and Category of finite weyl groups sage: TestSuite(G).run() from sage.categories.finite_weyl_groups import FiniteWeylGroups from sage.categories.finite_permutation_groups import FinitePermutationGroups from sage.categories.category import Category #Note that we skip the call to the superclass initializer in order to #avoid infinite recursion since SymmetricGroup is called by #PermutationGroupElement super(PermutationGroup_generic,self).__init__(category = Category.join([FinitePermutationGroups(), FiniteWeylGroups()])) self._set = _set self._deg = max(self._set+(0,))  # _set cat be empty n = len(self._set) super(PermutationGroup_generic, self).__init__(category = Category.join([FinitePermutationGroups(), FiniteWeylGroups()])) self._domain = domain self._deg = len(self._domain) self._domain_to_gap = dict((key, i+1) for i, key in enumerate(self._domain)) self._domain_from_gap = dict((i+1, key) for i, key in enumerate(self._domain)) #Create the generators for the symmetric group gens = [ tuple(self._set) ] if n > 2: gens.append( tuple(self._set[:2]) ) gens = [ tuple(self._domain) ] if len(self._domain) > 2: gens.append( tuple(self._domain[:2]) ) self._gens = [PermutationGroupElement(g, self, check=False) for g in gens] self._gap_string = '%s(%s)'%(self._gap_name, n) def _gap_init_(self, gap=None): """ Returns the string used to create this group in GAP. EXAMPLES:: sage: S = SymmetricGroup(3) sage: S._gap_init_() 'SymmetricGroup(3)' sage: S = SymmetricGroup(['a', 'b', 'c']) sage: S._gap_init_() 'SymmetricGroup(3)' """ return 'SymmetricGroup(%s)'%self.degree() @cached_method def index_set(self): sage: S8 = SymmetricGroup(8) sage: S8.index_set() (1, 2, 3, 4, 5, 6, 7) [1, 2, 3, 4, 5, 6, 7] sage: S = SymmetricGroup([3,1,4,5]) sage: S.index_set() (3, 1, 4) [3, 1, 4] """ return self.set()[:-1] return self.domain()[:-1] def __cmp__(self, x): """ True """ if isinstance(x, SymmetricGroup): return cmp((self._deg, self._set), (x._deg, x._set)) return cmp((self._deg, self._domain), (x._deg, x._domain)) else: return PermutationGroup_generic.__cmp__(self, x) sage: A = SymmetricGroup([2,3,7]); A Symmetric group of order 3! as a permutation group """ return "Symmetric group of order %s! as a permutation group"%len(self._set) _gap_name = 'SymmetricGroup' return "Symmetric group of order %s! as a permutation group"%self.degree() def simple_reflection(self, i): """ sage: A.simple_reflections() Finite family {2: (2,3), 3: (3,7)} """ return self([(i, self._set[self._set.index(i)+1])], check=False) return self([(i, self._domain[self._domain.index(i)+1])], check=False) def major_index(self, parameter=None): r""" return q_factorial(self.degree(), parameter) class AlternatingGroup(PermutationGroup_symalt): def __init__(self, _set): def __init__(self, domain=None): """ The alternating group of order $n!/2$, as a permutation group. sage: G = AlternatingGroup([1,2,4,5]) sage: G Alternating group of order 4!/2 as a permutation group sage: G.set() (1, 2, 4, 5) sage: G.domain() {1, 2, 4, 5} sage: G.category() Category of finite permutation groups sage: TestSuite(G).run() """ n = len(_set) #Create the generators for the symmetric group if n == 1: gens = [ [] ] else: gens = [ tuple(_set) ] if n > 2: gens.append( tuple(_set[:2]) ) PermutationGroup_symalt.__init__(self, gap_group='%s(%s)'%(self._gap_name,n)) self._set = _set self._deg = max(_set) PermutationGroup_symalt.__init__(self, gap_group='AlternatingGroup(%s)'%len(domain), domain=domain) def _repr_(self): """ sage: A = AlternatingGroup([2,3,7]); A Alternating group of order 3!/2 as a permutation group """ return "Alternating group of order %s!/2 as a permutation group" % len(self._set) return "Alternating group of order %s!/2 as a permutation group"%self.degree() _gap_name = 'AlternatingGroup' def _gap_init_(self, gap=None): """ Returns the string used to create this group in GAP. EXAMPLES:: sage: A = AlternatingGroup(3) sage: A._gap_init_() 'AlternatingGroup(3)' sage: A = AlternatingGroup(['a', 'b', 'c']) sage: A._gap_init_() 'AlternatingGroup(3)' """ return 'AlternatingGroup(%s)'%(self.degree()) class CyclicPermutationGroup(PermutationGroup_unique): def __init__(self, n): """ n = self.order() a = list(factor(n)) invs = [x[0]**x[1] for x in a] G = AbelianGroup(len(a),invs) G = AbelianGroup(len(a), invs) return G class DiCyclicGroup(PermutationGroup_unique): a = [tuple(range(1, halfr+1)), tuple(range(halfr+1, r+1))] # With an odd part, a cycle of length m will give the right order for a if m > 1: a.append( tuple(range(r+1,r+m+1)) ) a.append( tuple(range(r+1, r+m+1)) ) # Representation of  x # Four-cycles that will conjugate the generator  a  properly for i in range(0, fourthr)] # With an odd part, transpositions will conjugate the m-cycle to create inverse if m > 1: x += [(r+i+1,r+m-i) for i in range(0, (m-1)//2)] x += [(r+i+1, r+m-i) for i in range(0, (m-1)//2)] PermutationGroup_generic.__init__(self, gens=[a,x]) PermutationGroup_generic.__init__(self, gens=[a, x]) def _repr_(self): r""" self._d = d self._n = n self._set = range(1, d+1) self._domain = range(1, d+1) def _repr_(self): """ sage: [TransitiveGroups(i).cardinality() for i in range(11)] # requires optional database_gap [1, 1, 1, 2, 5, 5, 16, 7, 50, 34, 45] .. warning:: The database_gap contains all transitive groups up to degree 30:: .. warning:: sage: TransitiveGroups(31).cardinality()                     # requires optional database_gap Traceback (most recent call last): ... NotImplementedError: Only the transitive groups of order less than 30 are available in GAP's database The database_gap contains all transitive groups up to degree 30:: sage: TransitiveGroups(31).cardinality()                     # requires optional database_gap Traceback (most recent call last): ... NotImplementedError: Only the transitive groups of order less than 30 are available in GAP's database TESTS:: Category of finite permutation groups sage: TestSuite(G).run() """ from sage.groups.perm_gps.permgroup import PermutationGroup_generic id = 'Group([()])' if n == 1 else 'PGL(%s,%s)'%(n,q) PermutationGroup_generic.__init__(self, gap_group=id) self._q = q class SuzukiGroup(PermutationGroup_unique): def __init__(self, q, name='a'): r""" The Suzuki group over GF(q), $^2 B_2(2^{2k+1}) = Sz(2^{2k+1})$. A wrapper for the GAP function SuzukiGroup. The Suzuki group over GF(q), $^2 B_2(2^{2k+1}) = Sz(2^{2k+1})$. A wrapper for the GAP function SuzukiGroup. INPUT: q -- 2^n, an odd power of 2; the size of the ground finite field GF(q) OUTPUT: A Suzuki group. - A Suzuki group. EXAMPLES: EXAMPLES:: sage: SuzukiGroup(8) Permutation Group with generators [(1,28,10,44)(3,50,11,42)(4,43,53,64)(5,9,39,52)(6,36,63,13)(7,51,60,57)(8,33,37,16)(12,24,55,29)(14,30,48,47)(15,19,61,54)(17,59,22,62)(18,23,34,31)(20,38,49,25)(21,26,45,58)(27,32,41,65)(35,46,40,56), (1,2)(3,10)(4,42)(5,18)(6,50)(7,26)(8,58)(9,34)(12,28)(13,45)(14,44)(15,23)(16,31)(17,21)(19,39)(20,38)(22,25)(24,61)(27,60)(29,65)(30,55)(32,33)(35,52)(36,49)(37,59)(40,54)(41,62)(43,53)(46,48)(47,56)(51,63)(57,64)] Permutation Group with generators [(1,2)(3,10)(4,42)(5,18)(6,50)(7,26)(8,58)(9,34)(12,28)(13,45)(14,44)(15,23)(16,31)(17,21)(19,39)(20,38)(22,25)(24,61)(27,60)(29,65)(30,55)(32,33)(35,52)(36,49)(37,59)(40,54)(41,62)(43,53)(46,48)(47,56)(51,63)(57,64), (1,28,10,44)(3,50,11,42)(4,43,53,64)(5,9,39,52)(6,36,63,13)(7,51,60,57)(8,33,37,16)(12,24,55,29)(14,30,48,47)(15,19,61,54)(17,59,22,62)(18,23,34,31)(20,38,49,25)(21,26,45,58)(27,32,41,65)(35,46,40,56)] sage: print SuzukiGroup(8) The Suzuki group over Finite Field in a of size 2^3 Finite Field in alpha of size 2^5 REFERENCES: http://en.wikipedia.org/wiki/Group_of_Lie_type\#Suzuki-Ree_groups -  http://en.wikipedia.org/wiki/Group_of_Lie_type\#Suzuki-Ree_groups """ q = Integer(q) from sage.rings.arith import valuation
• ## sage/rings/number_field/galois_group.py

diff --git a/sage/rings/number_field/galois_group.py b/sage/rings/number_field/galois_group.py
 a sage: G.subgroup([ G(1), G([(1,5,2),(3,4,6)]), G([(1,2,5),(3,6,4)])]) Subgroup [(), (1,5,2)(3,4,6), (1,2,5)(3,6,4)] of Galois group of Number Field in b with defining polynomial x^6 - 14*x^4 + 20*x^3 + 49*x^2 - 140*x + 307 """ if len(elts) == self.order(): return self else: return GaloisGroup_subgroup(self, elts) if len(elts) == self.order(): return self else: return GaloisGroup_subgroup(self, elts) # Proper number theory starts here. All the functions below make no sense # unless the field is Galois. sage: GaloisGroup_subgroup( G, [ G(1), G([(1,5,2),(3,4,6)]), G([(1,2,5),(3,6,4)])]) Subgroup [(), (1,5,2)(3,4,6), (1,2,5)(3,6,4)] of Galois group of Number Field in b with defining polynomial x^6 - 14*x^4 + 20*x^3 + 49*x^2 - 140*x + 307 """ #XXX: This should be fixed so that this can use GaloisGroup_v2.__init__ PermutationGroup_generic.__init__(self, elts, canonicalize = True) self._ambient = ambient self._number_field = ambient.number_field() self._galois_closure=ambient._galois_closure self._galois_closure = ambient._galois_closure self._pari_data = ambient._pari_data self._pari_gc = ambient._pari_gc self._gc_map = ambient._gc_map self._elts = elts def fixed_field(self): return min(w) def __cmp__(self, other): r"""Compare self to other. For some bizarre reason, if you just let it 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. sage: K. = 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,2)(3,4)(5,6), (1,3)(2,6)(4,5), (1,5)(2,4)(3,6)] [(1,3)(2,6)(4,5), (1,2)(3,4)(5,6), (1,5)(2,4)(3,6)] """ return cmp(self.list(), other.list()) return PermutationGroupElement.__cmp__(self, other)
• ## sage/rings/number_field/number_field.py

diff --git a/sage/rings/number_field/number_field.py b/sage/rings/number_field/number_field.py
 a sage: z = CyclotomicField(3).an_element(); z zeta3 sage: c = K.character([1,z,z**2]); c Character of Subgroup of AlternatingGroup(4) generated by [(2,3,4)] Character of Subgroup of (Alternating group of order 4!/2 as a permutation group) generated by [(2,3,4)] sage: c(g^2); z^2 -zeta3 - 1 -zeta3 - 1
• ## sage/sets/finite_enumerated_set.py

diff --git a/sage/sets/finite_enumerated_set.py b/sage/sets/finite_enumerated_set.py
 a """ return Integer(len(self._elements)) def index(self, x): """ Returns the index of x in this finite enumerated set. EXAMPLES:: sage: S = FiniteEnumeratedSet(['a','b','c']) sage: S.index('b') 1 """ return self._elements.index(x) def _element_constructor_(self, el): """ TESTS::
• ## sage/structure/parent.pyx

diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
 a sage: S3.register_embedding(phi) sage: S3.coerce_embedding() Generic morphism: From: AlternatingGroup(3) From: Alternating group of order 3!/2 as a permutation group To:   Special Linear Group of degree 3 over Rational Field sage: S3.coerce_embedding()(p) [0 0 1]
• ## sage/structure/parent_gens.pyx

diff --git a/sage/structure/parent_gens.pyx b/sage/structure/parent_gens.pyx
 a if d.has_key('_element_constructor'): return parent.Parent.__setstate__(self, d) try: self.__dict__ = d self.__dict__.update(d) self._generator_orders = d['_generator_orders'] except (AttributeError,KeyError): pass