Path: blob/master/sage/groups/abelian_gps/abelian_group.py
4100 views
r"""1Multiplicative Abelian Groups23AUTHORS:45- William Stein, David Joyner (2008-12): added (user requested) is_cyclic,6fixed elementary_divisors.78- David Joyner (2006-03): (based on free abelian monoids by David9Kohel)1011- David Joyner (2006-05) several significant bug fixes1213- David Joyner (2006-08) trivial changes to docs, added random, fixed14bug in how invariants are recorded1516- David Joyner (2006-10) added dual_group method1718- David Joyner (2008-02) fixed serious bug in word_problem1920- David Joyner (2008-03) fixed bug in trivial group case2122- David Loeffler (2009-05) added subgroups method232425TODO:2627- additive abelian groups should also be supported2829Background on invariant factors and the Smith normal form30(according to section 4.1 of [C1]): An abelian group is a31group A for which there exists an exact sequence32`\ZZ^k \rightarrow \ZZ^\ell \rightarrow A \rightarrow 1`,33for some positive integers34`k,\ell` with `k\leq \ell`. For example, a finite abelian group has a35decomposition3637.. math::3839A = \langle a_1\rangle \times \dots \times \langle a_\ell\rangle ,4041where `ord(a_i)=p_i^{c_i}`, for some primes `p_i` and some42positive integers `c_i`, `i=1,...,\ell`. GAP calls the43list (ordered by size) of the `p_i^{c_i}` the *abelian invariants*.44In Sage they will be called *invariants*.45In this situation, `k=\ell` and `\phi: \ZZ^\ell \rightarrow A` is the map46`\phi(x_1,...,x_\ell) = a_1^{x_1}...a_\ell^{x_\ell}`,47for `(x_1,...,x_\ell)\in \ZZ^\ell`. The matrix of relations48`M:\ZZ^k \rightarrow \ZZ^\ell` is the matrix49whose rows generate the kernel of `\phi` as a `\ZZ`-module.50In other words, `M=(M_{ij})` is a `\ell\times \ell`51diagonal matrix with `M_{ii}=p_i^{c_i}`. Consider now the52subgroup `B\subset A` generated by53`b_1 = a_1^{f_{1,1}}...a_\ell^{f_{\ell,1}}`, ...,54`b_m = a_1^{f_{1,m}}...a_\ell^{f_{\ell,m}}`.55The kernel of the map `\phi_B: \ZZ^m \rightarrow B` defined by56`\phi_B(y_1,...,y_m) = b_1^{y_1}...b_m^{y_m}`,57for `(y_1,...,y_m)\in \ZZ^m`, is the kernel of the matrix5859.. math::6061F=62\left(63\begin{array}{cccc}64f_{11} & f_{12} & \dots & f_{1m}\\65f_{21} & f_{22} & \dots & f_{2m}\\66\vdots & & \ddots & \vdots \\67f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m}68\end{array}69\right),7071regarded as a map72`\ZZ^m\rightarrow (\ZZ/p_1^{c_1}\ZZ)\times ...\times (\ZZ/p_\ell^{c_\ell}\ZZ)`.73In particular, `B\cong \ZZ^m/ker(F)`. If `B=A` then the74Smith normal form (SNF) of a generator matrix of75`ker(F)` and the SNF of `M` are the same. The diagonal entries `s_i` of the76SNF `S = diag[s_1,s_2,s_3, ... s_r,0,0,...0]`,77are called *determinantal divisors* of `F`.78where `r` is the rank. The {\it invariant factors} of A are:7980.. math::8182s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}.83848586Sage supports multiplicative abelian groups on any prescribed finite87number `n \geq 0` of generators. Use the ``AbelianGroup`` function88to create an abelian group, and the ``gen`` and ``gens``89functions to obtain the corresponding generators. You can print the90generators as arbitrary strings using the optional ``names``91argument to the ``AbelianGroup`` function.9293EXAMPLE 1:9495We create an abelian group in zero or more variables; the syntax T(1)96creates the identity element even in the rank zero case.9798::99100sage: T = AbelianGroup(0,[])101sage: T102Trivial Abelian Group103sage: T.gens()104()105sage: T(1)1061107108EXAMPLE 2: An abelian group uses a multiplicative representation of109elements, but the underlying representation is lists of integer110exponents.111112::113114sage: F = AbelianGroup(5,[3,4,5,5,7],names = list("abcde"))115sage: F116Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7117sage: (a,b,c,d,e) = F.gens()118sage: a*b^2*e*d119a*b^2*d*e120sage: x = b^2*e*d*a^7121sage: x122a*b^2*d*e123sage: x.list()124[1, 2, 0, 1, 1]125126REFERENCES:127128- [C1] H. Cohen Advanced topics in computational number theory,129Springer, 2000.130131- [C2] ----, A course in computational algebraic number theory,132Springer, 1996.133134- [R] J. Rotman, An introduction to the theory of135groups, 4th ed, Springer, 1995.136137.. warning::138139Many basic properties for infinite abelian groups are not140implemented.141"""142143##########################################################################144# Copyright (C) 2006 David Joyner and William Stein145#146# Distributed under the terms of the GNU General Public License (GPL):147#148# http://www.gnu.org/licenses/149##########################################################################150151# TODO: change the "invariants" terminology everywhere to elementary_divisors152153154155from sage.rings.integer import Integer156157from sage.rings.infinity import infinity158from sage.rings.arith import divisors, gcd159from abelian_group_element import AbelianGroupElement160from sage.misc.misc import prod161from sage.misc.mrange import mrange, cartesian_product_iterator162import sage.groups.group as group163from sage.rings.integer_ring import IntegerRing164from sage.rings.arith import lcm165ZZ = IntegerRing()166167# TODO: this uses perm groups - the AbelianGroupElement instance method168# uses a different implementation.169170171def word_problem(words, g, verbose = False):172r"""173G and H are abelian, g in G, H is a subgroup of G generated by a174list (words) of elements of G. If g is in H, return the expression175for g as a word in the elements of (words).176177The 'word problem' for a finite abelian group G boils down to the178following matrix-vector analog of the Chinese remainder theorem.179180Problem: Fix integers `1<n_1\leq n_2\leq ...\leq n_k`181(indeed, these `n_i` will all be prime powers), fix a182generating set `g_i=(a_{i1},...,a_{ik})` (with183`a_{ij}\in \mathrm{Z}/n_j\mathrm{Z}`), for `1\leq i\leq \ell`,184for the group `G`, and let `d = (d_1,...,d_k)` be185an element of the direct product186`\mathrm{Z}/n_1\mathrm{Z} \times ...\times \mathrm{Z}/n_k\mathrm{Z}`. Find, if they187exist, integers `c_1,...,c_\ell` such that188`c_1g_1+...+c_\ell g_\ell = d`. In other words, solve189the equation `cA=d` for `c\in \mathrm{Z}^\ell`, where190`A` is the matrix whose rows are the `g_i`'s. Of191course, it suffices to restrict the `c_i`'s to the range192`0\leq c_i\leq N-1`, where `N` denotes the least193common multiple of the integers `n_1,...,n_k`.194195This function does not solve this directly, as perhaps it should.196Rather (for both speed and as a model for a similar function valid197for more general groups), it pushes it over to GAP, which has optimized198(non-deterministic) algorithms for the word problem. Essentially,199this function is a wrapper for the GAP function 'Factorization'.200201EXAMPLE::202203sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G204Multiplicative Abelian Group isomorphic to C2 x C3 x C4205sage: w = word_problem([a*b,a*c], b*c); w #random206[[a*b, 1], [a*c, 1]]207sage: prod([x^i for x,i in w]) == b*c208True209sage: w = word_problem([a*c,c],a); w #random210[[a*c, 1], [c, -1]]211sage: prod([x^i for x,i in w]) == a212True213sage: word_problem([a*c,c],a,verbose=True) #random214a = (a*c)^1*(c)^-1215[[a*c, 1], [c, -1]]216217::218219sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8])220sage: b1 = a^3*b*c*d^2*e^5221sage: b2 = a^2*b*c^2*d^3*e^3222sage: b3 = a^7*b^3*c^5*d^4*e^4223sage: b4 = a^3*b^2*c^2*d^3*e^5224sage: b5 = a^2*b^4*c^2*d^4*e^5225sage: w = word_problem([b1,b2,b3,b4,b5],e); w #random226[[a^3*b*c*d^2*e^5, 1], [a^2*b*c^2*d^3*e^3, 1], [a^3*b^3*d^4*e^4, 3], [a^2*b^4*c^2*d^4*e^5, 1]]227sage: prod([x^i for x,i in w]) == e228True229sage: word_problem([a,b,c,d,e],e)230[[e, 1]]231sage: word_problem([a,b,c,d,e],b)232[[b, 1]]233234.. warning::2352361. Might have unpleasant effect when the word problem237cannot be solved.2382392. Uses permutation groups, so may be slow when group is large.240The instance method word_problem of the class241AbelianGroupElement is implemented differently (wrapping242GAP's 'EpimorphismFromFreeGroup' and243'PreImagesRepresentative') and may be faster.244245"""246from sage.interfaces.all import gap247G = g.parent()248invs = G.invariants()249gap.eval("l:=One(Rationals)")250s1 = 'A:=AbelianGroup(%s)'%invs251gap.eval(s1)252s2 = 'phi:=IsomorphismPermGroup(A)'253gap.eval(s2)254s3 = "gens := GeneratorsOfGroup(A)"255gap.eval(s3)256L = g.list()257gap.eval("L1:="+str(L))258s4 = "L2:=List([l..%s], i->gens[i]^L1[i]);"%len(L)259gap.eval(s4)260gap.eval("g:=Product(L2); gensH:=[]")261for w in words:262L = w.list()263gap.eval("L1:="+str(L))264s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);"%len(L)265gap.eval(s4)266gap.eval("w:=Product(L2)")267gap.eval("gensH:=Concatenation(gensH,[w])")268s5 = 'H:=Group(gensH)'269gap.eval(s5)270gap.eval("x:=Factorization(H,g)")271l3 = eval(gap.eval("L3:=ExtRepOfObj(x)"))272nn = gap.eval("n:=Int(Length(L3)/2)")273LL = eval(gap.eval("L4:=List([l..n],i->L3[2*i])"))274if verbose:275#print gap.eval("x"), l3, nn, LL276v = '*'.join(['(%s)^%s'%(words[l3[2*i]-1], LL[i]) for i in range(len(LL))])277print '%s = %s'%(g, v)278return [[words[l3[2*i]-1],LL[i]] for i in range(len(LL))]279280281def AbelianGroup(n, invfac=None, names="f"):282r"""283Create the multiplicative abelian group in `n` generators284with given invariants (which need not be prime powers).285286INPUT:287288289- ``n`` - integer290291- ``invfac`` - (the"invariant factors") a list of292non-negative integers in the form [a0, a1,...,a(n-1)], typically293written in increasing order. This list is padded with zeros if it294has length less than n.295296- ``names`` - (optional) names of generators297298Alternatively, you can also give input in the following form:299300``AbelianGroup(invfac, names="f")``,301302where names must be explicitly named.303304305OUTPUT: Abelian group with generators and invariant type. The306default name for generator A.i is fi, as in GAP.307308EXAMPLES::309310sage: F = AbelianGroup(5, [5,5,7,8,9], names='abcde')311sage: F(1)3121313sage: (a, b, c, d, e) = F.gens()314sage: mul([ a, b, a, c, b, d, c, d ], F(1))315a^2*b^2*c^2*d^2316sage: d * b**2 * c**3317b^2*c^3*d318sage: F = AbelianGroup(3,[2]*3); F319Multiplicative Abelian Group isomorphic to C2 x C2 x C2320sage: H = AbelianGroup([2,3], names="xy"); H321Multiplicative Abelian Group isomorphic to C2 x C3322sage: AbelianGroup(5)323Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z324sage: AbelianGroup(5).order()325+Infinity326327Notice how `0`'s are padded on.328329::330331sage: AbelianGroup(5, [2,3,4])332Multiplicative Abelian Group isomorphic to Z x Z x C2 x C3 x C4333334The invariant list can't be longer than the number of generators.335336::337338sage: AbelianGroup(2, [2,3,4])339Traceback (most recent call last):340...341ValueError: invfac (=[2, 3, 4]) must have length n (=2)342"""343if invfac is None:344if isinstance(n, (list, tuple)):345invfac = n346n = len(n)347else:348invfac = []349if len(invfac) < n:350invfac = [0] * (n - len(invfac)) + invfac351elif len(invfac) > n:352raise ValueError, "invfac (=%s) must have length n (=%s)"%(invfac, n)353M = AbelianGroup_class(n, invfac, names)354return M355356def is_AbelianGroup(x):357"""358Return True if `x` is an abelian group.359360EXAMPLES::361362sage: from sage.groups.abelian_gps.abelian_group import is_AbelianGroup363sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F364Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9365sage: is_AbelianGroup(F)366True367sage: is_AbelianGroup(AbelianGroup(7, [3]*7))368True369"""370return isinstance(x, AbelianGroup_class)371372373class AbelianGroup_class(group.AbelianGroup):374"""375Abelian group on `n` generators. The invariant factors376`[a_1,a_2,...,a_k]` need not be prime powers.377divisors will be).378379EXAMPLES::380381sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F382Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9383sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F384Multiplicative Abelian Group isomorphic to C2 x C4 x C12 x C24 x C120385sage: F.elementary_divisors()386[2, 4, 12, 24, 120]387388The entry 1 in the list of invariants is ignored::389390sage: F = AbelianGroup(3,[1,2,3],names='a')391sage: F.invariants()392[2, 3]393sage: F.gens()394(a0, a1)395sage: F.ngens()3962397sage: (F.0).order()3982399sage: (F.1).order()4003401sage: AbelianGroup(1, [1], names='e')402Multiplicative Abelian Group isomorphic to C1403sage: AbelianGroup(1, [1], names='e').gens()404(e,)405sage: AbelianGroup(1, [1], names='e').list()406[1]407sage: AbelianGroup(3, [2, 1, 2], names=list('abc')).list()408[1, b, a, a*b]409410sage: F.category()411Category of groups412413"""414def __init__(self, n, invfac, names="f"):415#invfac.sort()416n = Integer(n)417# if necessary, remove 1 from invfac first418if n != 1:419while True:420try:421i = invfac.index(1)422except ValueError:423break424else:425del invfac[i]426n = n-1427428if n < 0:429raise ValueError, "n (=%s) must be nonnegative."%n430431self.__invariants = invfac432433# *now* define ngens434self.__ngens = len(self.__invariants)435self._assign_names(names[:n])436from sage.categories.groups import Groups437group.Group.__init__(self, category = Groups()) # should be CommutativeGroups()438439def __call__(self, x):440"""441Create an element of this abelian group from `x`.442443EXAMPLES::444445sage: F = AbelianGroup(10, [2]*10)446sage: F(F.2)447f2448sage: F(1)4491450"""451if isinstance(x, AbelianGroupElement) and x.parent() is self:452return x453return AbelianGroupElement(self, x)454455def __contains__(self, x):456"""457Return True if `x` is an element of this abelian group.458459EXAMPLES::460461sage: F = AbelianGroup(10,[2]*10)462sage: F.2 * F.3 in F463True464"""465return isinstance(x, AbelianGroupElement) and x.parent() == self466467def __eq__(self, right):468"""469Compare self and right.470471The ordering is the ordering induced by that on the invariant472factors lists.473474EXAMPLES::475476sage: G1 = AbelianGroup([2,3,4,5])477sage: G2 = AbelianGroup([2,3,4,5,1])478sage: G1 < G2479False480sage: G1 > G2481False482sage: G1 == G2483True484"""485if not is_AbelianGroup(right):486return False487if set(self.variable_names()) != set(right.variable_names()):488return False489svars = list(self.variable_names())490sinvs = self.invariants()491rvars = list(right.variable_names())492rinvs = right.invariants()493for i in xrange(len(svars)):494if rinvs[rvars.index(svars[i])] != sinvs[i]:495return False496return True497498def __ne__(self, right):499return not self == right500501def __ge__(self, right):502for a in right.gens():503if a not in self:504return False505return True506507def __lt__(self, right):508"""509EXAMPLE::510511sage: G.<a, b> = AbelianGroup(2)512sage: H.<c> = AbelianGroup(1)513sage: H < G514False515"""516return self <= right and self != right517518def __gt__(self, right):519return self >= right and self != right520521def __le__(self, right):522for a in self.gens():523if a not in right:524return False525return True526527def __nonzero__(self):528"""529Returns True if this group is nontrivial.530531EXAMPLES::532533sage: T = AbelianGroup([2, 3])534sage: bool(T) # indirect doctest535True536sage: bool(AbelianGroup([]))537False538"""539return len(self.invariants()) != 0540541def dual_group(self):542"""543Returns the dual group.544545EXAMPLES:546"""547from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup548return DualAbelianGroup(self)549550def elementary_divisors(self):551r"""552This returns the elementary divisors of the group, using Pari.553554.. note::555556Here is another algorithm for computing the elementary divisors557`d_1, d_2, d_3, \ldots`, of a finite abelian group (where `d_1 | d_2 | d_3 | \ldots`558are composed of prime powers dividing the invariants of the group559in a way described below). Just factor the invariants `a_i` that560define the abelian group. Then the biggest `d_i` is the product561of the maximum prime powers dividing some `a_j`. In other words, the562largest `d_i` is the product of `p^v`, where `v = max(ord_p(a_j) \mathrm{ for all } j`).563Now divide out all those `p^v`'s into the list of invariants `a_i`,564and get a new list of "smaller invariants"". Repeat the above procedure565on these ""smaller invariants"" to compute `d_{i-1}`, and so on.566(Thanks to Robert Miller for communicating this algorithm.)567568EXAMPLES::569570sage: G = AbelianGroup(2,[2,3])571sage: G.elementary_divisors()572[6]573sage: G = AbelianGroup(1, [6])574sage: G.elementary_divisors()575[6]576sage: G = AbelianGroup(2,[2,6])577sage: G578Multiplicative Abelian Group isomorphic to C2 x C6579sage: G.invariants()580[2, 6]581sage: G.elementary_divisors()582[2, 6]583sage: J = AbelianGroup([1,3,5,12])584sage: J.elementary_divisors()585[3, 60]586sage: G = AbelianGroup(2,[0,6])587sage: G.elementary_divisors()588[6, 0]589sage: AbelianGroup([3,4,5]).elementary_divisors()590[60]591"""592from sage.matrix.constructor import diagonal_matrix593ed = diagonal_matrix(ZZ, self.invariants()).elementary_divisors()594return [d for d in ed if d!=1]595596def exponent(self):597"""598Return the exponent of this abelian group.599600EXAMPLES::601602sage: G = AbelianGroup([2,3,7]); G603Multiplicative Abelian Group isomorphic to C2 x C3 x C7604sage: G.exponent()60542606sage: G = AbelianGroup([2,4,6]); G607Multiplicative Abelian Group isomorphic to C2 x C4 x C6608sage: G.exponent()60912610"""611try:612return self.__exponent613except AttributeError:614self.__exponent = e = lcm(self.invariants())615return e616617618def identity(self):619r"""620Return the identity element of this group.621622EXAMPLES::623624sage: G = AbelianGroup([2,2])625sage: e = G.identity()626sage: e6271628sage: g = G.gen(0)629sage: g*e630f0631sage: e*g632f0633"""634return self(1)635636637def _group_notation(self, eldv):638v = []639for x in eldv:640if x:641v.append("C%s"%x)642else:643v.append("Z")644return ' x '.join(v)645646def _latex_(self):647r"""648Return latex representation of this group.649650EXAMPLES::651652sage: F = AbelianGroup(10, [2]*10)653sage: F._latex_()654'$\\mathrm{AbelianGroup}( 10, [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] )$'655"""656s = "$\mathrm{AbelianGroup}( %s, %s )$"%(len(self.invariants()), self.invariants())657return s658659def _gap_init_(self):660r"""661Return string that defines corresponding abelian group in GAP.662663EXAMPLES::664665sage: G = AbelianGroup([2,3,9])666sage: G._gap_init_()667'AbelianGroup([2, 3, 9])'668sage: gap(G)669Group( [ f1, f2, f3 ] )670671Only works for finite groups.672673::674675sage: G = AbelianGroup(3,[0,3,4],names="abc"); G676Multiplicative Abelian Group isomorphic to Z x C3 x C4677sage: G._gap_init_()678Traceback (most recent call last):679...680TypeError: abelian groups in GAP are finite, but self is infinite681"""682# TODO: Use the package polycyclic has AbelianPcpGroup, which can handle683# the infinite case but it is a GAP package not GPL'd.684# Use this when the group is infinite...685if (False and prod(self.invariants())==0): # if False for now...686return 'AbelianPcpGroup(%s)'%self.invariants()687if not self.is_finite():688raise TypeError, "abelian groups in GAP are finite, but self is infinite"689return 'AbelianGroup(%s)'%self.invariants()690691def gen(self, i=0):692"""693The `i`-th generator of the abelian group.694695EXAMPLES::696697sage: F = AbelianGroup(5,[],names='a')698sage: F.0699a0700sage: F.2701a2702sage: F.invariants()703[0, 0, 0, 0, 0]704"""705n = self.__ngens706if i < 0 or i >= n:707raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)708x = [0]*int(n)709x[int(i)] = 1710return AbelianGroupElement(self, x)711712def invariants(self):713"""714Return a copy of the list of invariants of this group.715716It is safe to modify the returned list.717718EXAMPLES::719720sage: J = AbelianGroup([2,3])721sage: J.invariants()722[2, 3]723sage: v = J.invariants(); v724[2, 3]725sage: v[0] = 5726sage: J.invariants()727[2, 3]728sage: J.invariants() is J.invariants()729False730"""731return list(self.__invariants)732733def is_cyclic(self):734"""735Return True if the group is a cyclic group.736737EXAMPLES::738739sage: J = AbelianGroup([2,3])740sage: J.invariants()741[2, 3]742sage: J.elementary_divisors()743[6]744sage: J.is_cyclic()745True746sage: G = AbelianGroup([6])747sage: G.invariants()748[6]749sage: G.is_cyclic()750True751sage: H = AbelianGroup([2,2])752sage: H.invariants()753[2, 2]754sage: H.is_cyclic()755False756sage: H = AbelianGroup([2,4])757sage: H.elementary_divisors()758[2, 4]759sage: H.is_cyclic()760False761sage: H.permutation_group().is_cyclic()762False763sage: T = AbelianGroup([])764sage: T.is_cyclic()765True766sage: T = AbelianGroup(1,[0]); T767Multiplicative Abelian Group isomorphic to Z768sage: T.is_cyclic()769True770sage: B = AbelianGroup([3,4,5])771sage: B.is_cyclic()772True773"""774return len(self.elementary_divisors()) <= 1775776def ngens(self):777"""778The number of free generators of the abelian group.779780EXAMPLES::781782sage: F = AbelianGroup(10000)783sage: F.ngens()78410000785"""786return self.__ngens787788def order(self):789"""790Return the order of this group.791792EXAMPLES::793794sage: G = AbelianGroup(2,[2,3])795sage: G.order()7966797sage: G = AbelianGroup(3,[2,3,0])798sage: G.order()799+Infinity800"""801try:802return self.__len803except AttributeError:804from sage.rings.all import infinity, Integer805if len(self.invariants()) < self.ngens():806self.__len = infinity807else:808self.__len = Integer(prod(self.invariants()))809if self.__len == 0:810self.__len = infinity811return self.__len812813def permutation_group(self):814r"""815Return the permutation group isomorphic to this abelian group.816817If the invariants are `q_1, \ldots, q_n` then the818generators of the permutation will be of order819`q_1, \ldots, q_n`, respectively.820821EXAMPLES::822823sage: G = AbelianGroup(2,[2,3]); G824Multiplicative Abelian Group isomorphic to C2 x C3825sage: G.permutation_group()826Permutation Group with generators [(1,2,3)(4,5,6), (1,4)(2,5)(3,6)]827"""828from sage.groups.perm_gps.permgroup import PermutationGroup829s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()830return PermutationGroup(gap_group=s)831832833def is_commutative(self):834"""835Return True since this group is commutative.836837EXAMPLES::838839sage: G = AbelianGroup([2,3,9, 0])840sage: G.is_commutative()841True842sage: G.is_abelian()843True844"""845return True846847def random_element(self):848"""849Return a random element of this group. (Renamed random to850random_element.)851852EXAMPLES::853854sage: G = AbelianGroup([2,3,9])855sage: G.random_element()856f0*f1^2*f2857"""858from sage.misc.prandom import randint859if self.order() is infinity:860NotImplementedError, "The group must be finite"861gens = self.gens()862g = gens[0]**0863for i in range(len(gens)):864g = g*gens[i]**(randint(1,gens[i].order()))865return g866867868def _repr_(self):869eldv = self.invariants()870if len(eldv) == 0:871return "Trivial Abelian Group"872g = self._group_notation(eldv)873return "Multiplicative Abelian Group isomorphic to " + g874875876def subgroup(self, gensH, names="f"):877"""878Create a subgroup of this group. The "big" group must be defined879using "named" generators.880881INPUT:882883884- ``gensH`` - list of elements which are products of885the generators of the ambient abelian group G = self886887888EXAMPLES::889890sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G891Multiplicative Abelian Group isomorphic to C2 x C3 x C4892sage: H = G.subgroup([a*b,a]); H893Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of894Multiplicative Abelian Group isomorphic to C2 x C3 x C4895generated by [a*b, a]896sage: H < G897True898sage: F = G.subgroup([a,b^2])899sage: F900Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of901Multiplicative Abelian Group isomorphic to C2 x C3 x C4902generated by [a, b^2]903sage: F.gens()904[a, b^2]905sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))906sage: a,b,c,d,e = F.gens()907sage: F.subgroup([a,b])908Multiplicative Abelian Group isomorphic to Z x Z, which is909the subgroup of Multiplicative Abelian Group isomorphic to910Z x Z x C30 x C64 x C729 generated by [a, b]911sage: F.subgroup([c,e])912Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x913C729, which is the subgroup of Multiplicative Abelian914Group isomorphic to Z x Z x C30 x C64 x C729 generated by915[c, e]916"""917if not isinstance(gensH, (list, tuple)):918raise TypeError, "gensH = (%s) must be a list or tuple"%(gensH)919920G = self921for i in range(len(gensH)):922if not(gensH[i] in G):923raise TypeError, "Subgroup generators must belong to the given group."924return AbelianGroup_subgroup(self, gensH, names)925926def list(self):927"""928Return list of all elements of this group.929930EXAMPLES::931932sage: G = AbelianGroup([2,3], names = "ab")933sage: G.list()934[1, b, b^2, a, a*b, a*b^2]935936::937938sage: G = AbelianGroup([]); G939Trivial Abelian Group940sage: G.list()941[1]942"""943try:944return list(self.__list)945except AttributeError:946pass947if not(self.is_finite()):948raise NotImplementedError, "Group must be finite"949self.__list = list(self.__iter__())950return list(self.__list)951952def __iter__(self):953"""954Return an iterator over the elements of this group.955956EXAMPLES::957958sage: G = AbelianGroup([2,3], names = "ab")959sage: [a for a in G]960[1, b, b^2, a, a*b, a*b^2]961sage: L = list(G); L962[1, b, b^2, a, a*b, a*b^2]963964The returned list is a reference; mutating it does not allow the965user to (accidentally?) alter the computed generators::966967sage: L[0] = 0968sage: list(G)969[1, b, b^2, a, a*b, a*b^2]970sage: G = AbelianGroup([1], names="a")971sage: list(G)972[1]973sage: G = AbelianGroup([])974sage: G.list()975[1]976sage: list(G)977[1]978"""979invs = self.invariants()980for t in mrange(invs):981yield AbelianGroupElement(self, t)982983984def subgroups(self, check=False):985r"""986Compute all the subgroups of this abelian group (which must be finite).987988TODO: This is *many orders of magnitude* slower than Magma.989990INPUT:991992- check: if True, performs the same computation in GAP and checks that993the number of subgroups generated is the same. (I don't know how to994convert GAP's output back into Sage, so we don't actually compare the995subgroups).996997ALGORITHM:998999If the group is cyclic, the problem is easy. Otherwise, write it as1000a direct product A x B, where B is cyclic. Compute the subgroups of1001A (by recursion).10021003Now, for every subgroup C of A x B, let G be its *projection onto*1004A and H its *intersection with* B. Then there is a well-defined1005homomorphism f: G -> B/H that sends a in G to the class mod H of b,1006where (a,b) is any element of C lifting a; and every subgroup C1007arises from a unique triple (G, H, f).10081009EXAMPLES::10101011sage: AbelianGroup([2,3]).subgroups()1012[Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of1013Multiplicative Abelian Group isomorphic to C2 x C31014generated by [f0*f1^2],1015Multiplicative Abelian Group isomorphic to C2, which is the subgroup of1016Multiplicative Abelian Group isomorphic to C2 x C31017generated by [f0],1018Multiplicative Abelian Group isomorphic to C3, which is the subgroup of1019Multiplicative Abelian Group isomorphic to C2 x C31020generated by [f1],1021Trivial Abelian Group, which is the subgroup of1022Multiplicative Abelian Group isomorphic to C2 x C31023generated by []]10241025sage: len(AbelianGroup([2,4,8]).subgroups())10268110271028"""1029if not self.is_finite(): raise ValueError, "Group must be finite"1030from sage.misc.misc import verbose10311032v = self.invariants()103310341035if len(v) <= 1:1036if v == [] or v[0] == 1:1037return [self]1038else:1039return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1]] + [self.subgroup([])]10401041A = AbelianGroup(v[:-1])1042x = v[-1]10431044Wsubs = A.subgroups()10451046subgps = []1047for G in Wsubs:1048verbose("G = subgp generated by %s" % G.gens())1049verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work1050for H in divisors(x):1051# H = the subgroup of *index* H.1052its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))]1053for f in cartesian_product_iterator(its):1054verbose("using hom from G to C_%s sending gens to %s" % (H,f))1055new_sub = []1056for a in xrange(len(G.gens())):1057new_sub.append(G.gen(a).list() + [f[a]])1058if H != x:1059new_sub.append([0]*A.ngens() + [H])1060subgps.append(self.subgroup_reduced(new_sub))10611062if check:1063from sage.interfaces.all import gap1064verbose("Running Gap cross-check")1065t = ZZ(gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v))1066if t != len(subgps):1067raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % (v, t, len(subgps))1068verbose("Gap check OK for %s: %s" % (v, t))1069return subgps10701071def subgroup_reduced(self,elts, verbose=False):1072r"""1073Given a list of lists of integers (corresponding to elements of self),1074find a set of independent generators for the subgroup generated by1075these elements, and return the subgroup with these as generators,1076forgetting the original generators.10771078This is used by the ``subgroups`` routine.10791080An error will be raised if the elements given are not linearly1081independent over QQ.10821083EXAMPLE::10841085sage: G = AbelianGroup([4,4])1086sage: G.subgroup( [ G([1,0]), G([1,2]) ])1087Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of1088Multiplicative Abelian Group isomorphic to C4 x C41089generated by [f0, f0*f1^2]1090sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])1091Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of1092Multiplicative Abelian Group isomorphic to C4 x C41093generated by [f1^2, f0]1094"""1095from sage.matrix.constructor import matrix1096d = self.ngens()1097X = ZZ**d1098try:1099elt_lattice = X.submodule_with_basis(elts)1100except ValueError, e:1101# can't happen?1102print "Vectors not LI: ", elts1103raise e1104rel_lattice = X.span([X.gen(i) * self.invariants()[i] for i in xrange(d)])1105isect = elt_lattice.intersection(rel_lattice)1106mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)1107D,U,V = mat.smith_form()1108new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i,i]) for i in xrange(U.ncols())]1109return self.subgroup([self([x[0][i] % self.invariants()[i] for i in xrange(d)]) for x in new_basis if x[1] != 1])11101111class AbelianGroup_subgroup(AbelianGroup_class):1112"""1113Subgroup subclass of AbelianGroup_class, so instance methods are1114inherited.11151116TODO:11171118- There should be a way to coerce an element of a subgroup1119into the ambient group.1120"""1121def __init__(self, ambient, gens, names="f"):1122"""1123EXAMPLES::11241125sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))1126sage: a,b,c,d,e = F.gens()1127sage: F.subgroup([a^3,b])1128Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of1129Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C7291130generated by [a^3, b]11311132::11331134sage: F.subgroup([c])1135Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of1136Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C7291137generated by [c]11381139::11401141sage: F.subgroup([a,c])1142Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x1143Z, which is the subgroup of Multiplicative Abelian Group1144isomorphic to Z x Z x C30 x C64 x C729 generated by [a, c]11451146::11471148sage: F.subgroup([a,b*c])1149Multiplicative Abelian Group isomorphic to Z x Z, which is1150the subgroup of Multiplicative Abelian Group isomorphic to1151Z x Z x C30 x C64 x C729 generated by [a, b*c]11521153::11541155sage: F.subgroup([b*c,d])1156Multiplicative Abelian Group isomorphic to C64 x Z, which1157is the subgroup of Multiplicative Abelian Group isomorphic1158to Z x Z x C30 x C64 x C729 generated by [b*c, d]11591160::11611162sage: F.subgroup([a*b,c^6,d],names = list("xyz"))1163Multiplicative Abelian Group isomorphic to C5 x C64 x Z,1164which is the subgroup of Multiplicative Abelian Group1165isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,1166c^6, d]11671168::11691170sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H1171Multiplicative Abelian Group isomorphic to C5 x C64 x Z,1172which is the subgroup of Multiplicative Abelian Group1173isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,1174c^6, d]11751176::11771178sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G1179Multiplicative Abelian Group isomorphic to C5 x C64 x Z,1180which is the subgroup of Multiplicative Abelian Group1181isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,1182c^6, d]1183sage: x,y,z = G.gens()1184sage: x.order()1185+Infinity1186sage: y.order()118751188sage: z.order()1189641190sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde")1191sage: a,b,c,d,e = A.gens()1192sage: A.subgroup([a,b])1193Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of1194Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C81195generated by [a, b]1196sage: A.subgroup([a,b,c,d^2,e])1197Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of1198Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C81199generated by [a, b, c, d^2, e]1200sage: A.subgroup([a,b,c,d^2,e^2])1201Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of1202Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C81203generated by [a, b, c, d^2, e^2]1204sage: B = A.subgroup([a^3,b,c,d,e^2]); B1205Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of1206Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C81207generated by [b, c, d, e^2]1208sage: B.invariants()1209[4, 5, 5, 7]1210sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd")1211sage: a,b,c,d = A.gens()1212sage: B = A.subgroup([a^3,b,c,d])1213sage: B.invariants()1214[1009, 2003, 3001, 4001]1215sage: A.order()1216242664732100271217sage: B.order()1218242664732100271219sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd")1220sage: a,b,c,d = A.gens()1221sage: B = A.subgroup([a^3,b,c,d]); B1222Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x1223C2003 x C3001 x C4001, which is the subgroup of1224Multiplicative Abelian Group isomorphic to C1008 x C2003 x1225C3001 x C4001 generated by [a^3, b, c, d]12261227Infinite groups can also be handled::12281229sage: G = AbelianGroup([3,4,0], names = "abc")1230sage: a,b,c = G.gens()1231sage: F = G.subgroup([a,b^2,c]); F1232Multiplicative Abelian Group isomorphic to C2 x C3 x Z,1233which is the subgroup of Multiplicative Abelian Group1234isomorphic to C3 x C4 x Z generated by [a, b^2, c]12351236::12371238sage: F.invariants()1239[2, 3, 0]1240sage: F.gens()1241[a, b^2, c]1242sage: F.order()1243+Infinity1244"""1245from sage.interfaces.all import gap1246if not isinstance(ambient, AbelianGroup_class):1247raise TypeError, "ambient (=%s) must be an abelian group."%ambient1248if not isinstance(gens, list):1249raise TypeError, "gens (=%s) must be a list"%gens12501251self.__ambient_group = ambient1252Hgens = [x for x in gens if x != ambient(1)] ## in case someone puts 1 in the list of generators1253self.__gens = Hgens1254m = len(gens)1255ell = len(ambient.gens())1256ambient_invs = ambient.invariants()1257invsf = [x for x in ambient_invs if x > 0] ## fixes the problem with1258invs0 = [x for x in ambient_invs if x == 0] ## the infinite parts1259Ggens = list(ambient.variable_names())1260if invs0!=[]:1261Gfgens = [x for x in ambient.variable_names() if1262ambient_invs[Ggens.index(x)] != 0]1263Ggens0 = [x for x in ambient.variable_names() if1264ambient_invs[Ggens.index(x)] == 0]1265## ^^ only look at "finite" names1266Gf = AbelianGroup_class(len(invsf), invsf, names = Gfgens)1267s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_()1268gap.eval(s1)1269Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0]1270# computes the gens of H which do not occur ^^ in the infinite part of G1271Hgens0 = [x for x in Hgens if not(x in Hgensf)]1272# the "infinite" generators of H1273for i in range(len(Gfgens)):1274cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i]1275gap.eval(cmd)1276if invs0==[]:1277Hgensf = Hgens1278Hgens0 = [] # added for consistency1279G = ambient1280s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()1281gap.eval(s1)1282for i in range(len(Ggens)):1283cmd = '%s := gens[%s]'%(Ggens[i], i+1)1284#print i," \n",cmd1285gap.eval(cmd)1286s2 = "gensH:=%s"%Hgensf #### remove from this the ones <--> 0 invar1287gap.eval(s2)1288s3 = 'H:=Subgroup(G,gensH)'1289gap.eval(s3)1290# a GAP command which returns the "invariants" of the1291# subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)),1292# works if G is the subgroup declared as a AbelianPcpGroup1293self.__abinvs = eval(gap.eval("AbelianInvariants(H)"))1294invs = self.__abinvs1295#print s3, invs1296if Hgens0 != []:1297for x in Hgens0:1298invs.append(0)1299#print Hgensf, invs, invs01300AbelianGroup_class.__init__(self, len(invs), invs, names)13011302def __contains__(self, x):1303"""1304Return True if `x` is an element of this subgroup.13051306EXAMPLES::13071308sage: G.<a,b> = AbelianGroup(2)1309sage: A = G.subgroup([a])1310sage: a in G1311True1312sage: a in A1313True1314"""1315if not isinstance(x, AbelianGroupElement):1316return False1317if x.parent() is self:1318return True1319elif x in self.ambient_group():1320amb_inv = self.ambient_group().invariants()1321for a in xrange(len(amb_inv)):1322if amb_inv[a] == 0 and x.list()[a] != 0:1323for g in self.__gens:1324if g.list()[a] == 0:1325continue1326if abs(x.list()[a]%g.list()[a]) < abs(x.list()[a]):1327if g.list()[a]*x.list()[a] < 0:1328x *= g**(x.list()[a]/g.list()[a])1329else:1330x *= g**((-1)*(x.list()[a]/g.list()[a]))1331if x.list()[a] == 0:1332break1333elif x.list()[a] != 0:1334for g in self.__gens:1335if g.list()[a] == 0:1336continue1337if abs(x.list()[a]%g.list()[a])%abs(amb_inv[a]) < x.list()[a]%abs(amb_inv[a]):1338x *= g**((-1)*(x.list()[a]/g.list()[a]))1339if x.list()[a] == 0:1340break1341return x == x.parent()(1)13421343def ambient_group(self):1344"""1345Return the ambient group related to self.1346"""1347return self.__ambient_group13481349def __eq__(self, right):1350"""1351::13521353sage: G = AbelianGroup(3, [2,3,4], names="abc"); G1354Multiplicative Abelian Group isomorphic to C2 x C3 x C41355sage: a,b,c = G.gens()1356sage: F=G.subgroup([a,b^2]); F1357Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of1358Multiplicative Abelian Group isomorphic to C2 x C3 x C41359generated by [a, b^2]1360sage: F<G1361True13621363::13641365sage: A = AbelianGroup(1, [6])1366sage: A.subgroup(list(A.gens())) == A1367True13681369::13701371sage: G.<a,b> = AbelianGroup(2)1372sage: A = G.subgroup([a])1373sage: B = G.subgroup([b])1374sage: A == B1375False1376"""1377if not is_AbelianGroup(right):1378return -11379return self <= right and right <= self13801381def _repr_(self):1382return '%s, which is the subgroup of\n%s\ngenerated by %s'%(1383AbelianGroup_class._repr_(self),1384self.ambient_group(),1385self.gens())13861387def invs(self):1388"""1389Return the invariants for this subgroup.1390"""1391G = self.ambient_group()1392invsG = G.invariants()1393Hgap = self._gap_init_()139413951396def gens(self):1397"""1398Return the generators for this subgroup.1399"""1400return self.__gens14011402def gen(self, n):1403"""1404Return the nth generator of this subgroup.14051406EXAMPLE::14071408sage: G.<a,b> = AbelianGroup(2)1409sage: A = G.subgroup([a])1410sage: A.gen(0)1411a1412"""1413return self.__gens[n]1414141514161417