Path: blob/master/src/sage/groups/abelian_gps/abelian_group.py
8815 views
r"""1Multiplicative Abelian Groups23This module lets you compute with finitely generated Abelian groups of the form45.. math::67G = \ZZ^r \oplus \ZZ_{k_1} \oplus \cdots \oplus \ZZ_{k_t}89It is customary to denote the infinite cyclic group `\ZZ` as having10order `0`, so the data defining the Abelian group can be written as an11integer vector1213.. math::1415\vec{k} = (0, \dots, 0, k_1, \dots, k_t)1617where there are `r` zeroes and `t` non-zero values. To construct this18Abelian group in Sage, you can either specify all entries of `\vec{k}`19or only the non-zero entries together with the total number of20generators::2122sage: AbelianGroup([0,0,0,2,3])23Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C324sage: AbelianGroup(5, [2,3])25Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C32627It is also legal to specify `1` as the order. The corresponding28generator will be the neutral element, but it will still take up an29index in the labelling of the generators::3031sage: G = AbelianGroup([2,1,3], names='g')32sage: G.gens()33(g0, 1, g2)3435Note that this presentation is not unique, for example `\ZZ_6 = \ZZ_236\times \ZZ_3`. The orders of the generators37`\vec{k}=(0,\dots,0,k_1,\dots, k_t)` has previously been called38invariants in Sage, even though they are not necessarily the (unique)39invariant factors of the group. You should now use40:meth:`~AbelianGroup_class.gens_orders` instead::4142sage: J = AbelianGroup([2,0,3,2,4]); J43Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C444sage: J.gens_orders() # use this instead45(2, 0, 3, 2, 4)46sage: J.invariants() # deprecated47(2, 0, 3, 2, 4)48sage: J.elementary_divisors() # these are the "invariant factors"49(2, 2, 12, 0)50sage: for i in range(J.ngens()):51... print i, J.gen(i), J.gen(i).order() # or use this form520 f0 2531 f1 +Infinity542 f2 3553 f3 2564 f4 45758Background on invariant factors and the Smith normal form59(according to section 4.1 of [C1]): An abelian group is a60group A for which there exists an exact sequence61`\ZZ^k \rightarrow \ZZ^\ell \rightarrow A \rightarrow 1`,62for some positive integers63`k,\ell` with `k\leq \ell`. For example, a finite abelian group has a64decomposition6566.. math::6768A = \langle a_1\rangle \times \dots \times \langle a_\ell\rangle ,6970where `ord(a_i)=p_i^{c_i}`, for some primes `p_i` and some71positive integers `c_i`, `i=1,...,\ell`. GAP calls the72list (ordered by size) of the `p_i^{c_i}` the *abelian invariants*.73In Sage they will be called *invariants*.74In this situation, `k=\ell` and `\phi: \ZZ^\ell \rightarrow A` is the map75`\phi(x_1,...,x_\ell) = a_1^{x_1}...a_\ell^{x_\ell}`,76for `(x_1,...,x_\ell)\in \ZZ^\ell`. The matrix of relations77`M:\ZZ^k \rightarrow \ZZ^\ell` is the matrix78whose rows generate the kernel of `\phi` as a `\ZZ`-module.79In other words, `M=(M_{ij})` is a `\ell\times \ell`80diagonal matrix with `M_{ii}=p_i^{c_i}`. Consider now the81subgroup `B\subset A` generated by82`b_1 = a_1^{f_{1,1}}...a_\ell^{f_{\ell,1}}`, ...,83`b_m = a_1^{f_{1,m}}...a_\ell^{f_{\ell,m}}`.84The kernel of the map `\phi_B: \ZZ^m \rightarrow B` defined by85`\phi_B(y_1,...,y_m) = b_1^{y_1}...b_m^{y_m}`,86for `(y_1,...,y_m)\in \ZZ^m`, is the kernel of the matrix8788.. math::8990F=91\left(92\begin{array}{cccc}93f_{11} & f_{12} & \dots & f_{1m}\\94f_{21} & f_{22} & \dots & f_{2m}\\95\vdots & & \ddots & \vdots \\96f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m}97\end{array}98\right),99100regarded as a map101`\ZZ^m\rightarrow (\ZZ/p_1^{c_1}\ZZ)\times ...\times (\ZZ/p_\ell^{c_\ell}\ZZ)`.102In particular, `B\cong \ZZ^m/ker(F)`. If `B=A` then the103Smith normal form (SNF) of a generator matrix of104`ker(F)` and the SNF of `M` are the same. The diagonal entries `s_i` of the105SNF `S = diag[s_1,s_2,s_3, ... s_r,0,0,...0]`,106are called *determinantal divisors* of `F`.107where `r` is the rank. The {\it invariant factors} of A are:108109.. math::110111s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}.112113Sage supports multiplicative abelian groups on any prescribed finite114number `n \geq 0` of generators. Use the :func:`AbelianGroup`115function to create an abelian group, and the116:meth:`~AbelianGroup_class.gen` and :meth:`~AbelianGroup_class.gens`117methods to obtain the corresponding generators. You can print the118generators as arbitrary strings using the optional ``names`` argument119to the :func:`AbelianGroup` function.120121EXAMPLE 1:122123We create an abelian group in zero or more variables; the syntax T(1)124creates the identity element even in the rank zero case::125126sage: T = AbelianGroup(0,[])127sage: T128Trivial Abelian group129sage: T.gens()130()131sage: T(1)1321133134EXAMPLE 2:135136An Abelian group uses a multiplicative representation of elements, but137the underlying representation is lists of integer exponents::138139sage: F = AbelianGroup(5,[3,4,5,5,7],names = list("abcde"))140sage: F141Multiplicative Abelian group isomorphic to C3 x C4 x C5 x C5 x C7142sage: (a,b,c,d,e) = F.gens()143sage: a*b^2*e*d144a*b^2*d*e145sage: x = b^2*e*d*a^7146sage: x147a*b^2*d*e148sage: x.list()149[1, 2, 0, 1, 1]150151REFERENCES:152153- [C1] H. Cohen Advanced topics in computational number theory,154Springer, 2000.155156- [C2] ----, A course in computational algebraic number theory,157Springer, 1996.158159- [R] J. Rotman, An introduction to the theory of160groups, 4th ed, Springer, 1995.161162.. warning::163164Many basic properties for infinite abelian groups are not165implemented.166167168AUTHORS:169170- William Stein, David Joyner (2008-12): added (user requested) is_cyclic,171fixed elementary_divisors.172173- David Joyner (2006-03): (based on free abelian monoids by David174Kohel)175176- David Joyner (2006-05) several significant bug fixes177178- David Joyner (2006-08) trivial changes to docs, added random, fixed179bug in how invariants are recorded180181- David Joyner (2006-10) added dual_group method182183- David Joyner (2008-02) fixed serious bug in word_problem184185- David Joyner (2008-03) fixed bug in trivial group case186187- David Loeffler (2009-05) added subgroups method188189- Volker Braun (2012-11) port to new Parent base. Use tuples for190immutables. Rename invariants to gens_orders.191"""192193##########################################################################194# Copyright (C) 2006 William Stein <[email protected]>195# Copyright (C) 2006 David Joyner <[email protected]>196# Copyright (C) 2012 Volker Braun <[email protected]>197#198# Distributed under the terms of the GNU General Public License (GPL):199#200# http://www.gnu.org/licenses/201##########################################################################202203204from sage.rings.integer import Integer205from sage.rings.integer_ring import ZZ206from sage.structure.unique_representation import UniqueRepresentation207from sage.rings.infinity import infinity208from sage.rings.arith import divisors, gcd209from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement210from sage.misc.cachefunc import cached_method211from sage.misc.misc import prod212from sage.misc.mrange import mrange, cartesian_product_iterator213from sage.rings.arith import lcm214from sage.groups.group import AbelianGroup as AbelianGroupBase215216217# TODO: this uses perm groups - the AbelianGroupElement instance method218# uses a different implementation.219def word_problem(words, g, verbose = False):220r"""221G and H are abelian, g in G, H is a subgroup of G generated by a222list (words) of elements of G. If g is in H, return the expression223for g as a word in the elements of (words).224225The 'word problem' for a finite abelian group G boils down to the226following matrix-vector analog of the Chinese remainder theorem.227228Problem: Fix integers `1<n_1\leq n_2\leq ...\leq n_k`229(indeed, these `n_i` will all be prime powers), fix a230generating set `g_i=(a_{i1},...,a_{ik})` (with231`a_{ij}\in \mathrm{Z}/n_j\mathrm{Z}`), for `1\leq i\leq \ell`,232for the group `G`, and let `d = (d_1,...,d_k)` be233an element of the direct product234`\mathrm{Z}/n_1\mathrm{Z} \times ...\times \mathrm{Z}/n_k\mathrm{Z}`. Find, if they235exist, integers `c_1,...,c_\ell` such that236`c_1g_1+...+c_\ell g_\ell = d`. In other words, solve237the equation `cA=d` for `c\in \mathrm{Z}^\ell`, where238`A` is the matrix whose rows are the `g_i`'s. Of239course, it suffices to restrict the `c_i`'s to the range240`0\leq c_i\leq N-1`, where `N` denotes the least241common multiple of the integers `n_1,...,n_k`.242243This function does not solve this directly, as perhaps it should.244Rather (for both speed and as a model for a similar function valid245for more general groups), it pushes it over to GAP, which has optimized246(non-deterministic) algorithms for the word problem. Essentially,247this function is a wrapper for the GAP function 'Factorization'.248249EXAMPLE::250251sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G252Multiplicative Abelian group isomorphic to C2 x C3 x C4253sage: w = word_problem([a*b,a*c], b*c); w #random254[[a*b, 1], [a*c, 1]]255sage: prod([x^i for x,i in w]) == b*c256True257sage: w = word_problem([a*c,c],a); w #random258[[a*c, 1], [c, -1]]259sage: prod([x^i for x,i in w]) == a260True261sage: word_problem([a*c,c],a,verbose=True) #random262a = (a*c)^1*(c)^-1263[[a*c, 1], [c, -1]]264265::266267sage: A.<a,b,c,d,e> = AbelianGroup(5,[4, 5, 5, 7, 8])268sage: b1 = a^3*b*c*d^2*e^5269sage: b2 = a^2*b*c^2*d^3*e^3270sage: b3 = a^7*b^3*c^5*d^4*e^4271sage: b4 = a^3*b^2*c^2*d^3*e^5272sage: b5 = a^2*b^4*c^2*d^4*e^5273sage: w = word_problem([b1,b2,b3,b4,b5],e); w #random274[[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]]275sage: prod([x^i for x,i in w]) == e276True277sage: word_problem([a,b,c,d,e],e)278[[e, 1]]279sage: word_problem([a,b,c,d,e],b)280[[b, 1]]281282.. warning::2832841. Might have unpleasant effect when the word problem285cannot be solved.2862872. Uses permutation groups, so may be slow when group is large.288The instance method word_problem of the class289AbelianGroupElement is implemented differently (wrapping290GAP's 'EpimorphismFromFreeGroup' and291'PreImagesRepresentative') and may be faster.292"""293from sage.interfaces.all import gap294G = g.parent()295invs = map(str, G.gens_orders())296gap.eval("l:=One(Rationals)")297s1 = 'A:=AbelianGroup([' + ','.join(invs) + '])'298gap.eval(s1)299s2 = 'phi:=IsomorphismPermGroup(A)'300gap.eval(s2)301s3 = "gens := GeneratorsOfGroup(A)"302gap.eval(s3)303L = g.list()304gap.eval("L1:="+str(L))305s4 = "L2:=List([l..%s], i->gens[i]^L1[i]);"%len(L)306gap.eval(s4)307gap.eval("g:=Product(L2); gensH:=[]")308for w in words:309L = w.list()310gap.eval("L1:="+str(L))311s4 = "L2:=List([1..%s], i->gens[i]^L1[i]);"%len(L)312gap.eval(s4)313gap.eval("w:=Product(L2)")314gap.eval("gensH:=Concatenation(gensH,[w])")315s5 = 'H:=Group(gensH)'316gap.eval(s5)317gap.eval("x:=Factorization(H,g)")318l3 = eval(gap.eval("L3:=ExtRepOfObj(x)"))319nn = gap.eval("n:=Int(Length(L3)/2)")320LL = eval(gap.eval("L4:=List([l..n],i->L3[2*i])"))321if verbose:322#print gap.eval("x"), l3, nn, LL323v = '*'.join(['(%s)^%s'%(words[l3[2*i]-1], LL[i]) for i in range(len(LL))])324print '%s = %s'%(g, v)325return [[words[l3[2*i]-1],LL[i]] for i in range(len(LL))]326327328def _normalize(n, gens_orders=None, names="f"):329"""330Helper function for :func:`AbelianGroup`. Beat some sense into the331arguments.332333This function is also used by some descendents of334:class:`AbelianGroup_class`.335336INPUT:337338See :func:`AbelianGroup`339340OUTPUT:341342Unique data for defining a :class:`AbelianGroup_class`. Raises an343exception if the input is invalid.344345EXAMPLES::346347sage: from sage.groups.abelian_gps.abelian_group import _normalize348sage: _normalize(5, [2,1,0], names='abc')349((0, 0, 2, 1, 0), 'abc')350sage: _normalize(5, (2.0, 1.0, 0/1), names=list('abc'))351((0, 0, 2, 1, 0), ('a', 'b', 'c'))352sage: _normalize([0,2,1,0], names='a')353((0, 2, 1, 0), 'a')354355TESTS::356357sage: _normalize(5, (2.0, 1.5, 0/1), names=list('abc'))358Traceback (most recent call last):359...360TypeError: Attempt to coerce non-integral RealNumber to Integer361sage: _normalize('1', '[2]', names='a')362Traceback (most recent call last):363...364TypeError: unable to convert x (=[) to an integer365sage: _normalize(3, 'str', names='a')366Traceback (most recent call last):367...368TypeError: unable to convert x (=s) to an integer369"""370if gens_orders is None:371if isinstance(n, (list, tuple)):372gens_orders = n373n = len(n)374else:375gens_orders = []376n = ZZ(n)377if len(gens_orders) < n:378gens_orders = [0] * (n - len(gens_orders)) + list(gens_orders)379gens_orders = tuple(ZZ(i) for i in gens_orders)380if len(gens_orders) > n:381raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')')382if isinstance(names, list):383names = tuple(names)384return (gens_orders, names)385386def AbelianGroup(n, gens_orders=None, names="f"):387r"""388Create the multiplicative abelian group in `n` generators389with given orders of generators (which need not be prime powers).390391INPUT:392393- ``n`` -- integer (optional). If not specified, will be derived394from ``gens_orders``.395396- ``gens_orders`` -- a list of non-negative integers in the form397`[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing398order. This list is padded with zeros if it has length less399than n. The orders of the commuting generators, with `0`400denoting an infinite cyclic factor.401402- ``names`` -- (optional) names of generators403404Alternatively, you can also give input in the form405``AbelianGroup(gens_orders, names="f")``, where the names keyword406argument must be explicitly named.407408OUTPUT:409410Abelian group with generators and invariant type. The default name411for generator ``A.i`` is ``fi``, as in GAP.412413EXAMPLES::414415sage: F = AbelianGroup(5, [5,5,7,8,9], names='abcde')416sage: F(1)4171418sage: (a, b, c, d, e) = F.gens()419sage: mul([ a, b, a, c, b, d, c, d ], F(1))420a^2*b^2*c^2*d^2421sage: d * b**2 * c**3422b^2*c^3*d423sage: F = AbelianGroup(3,[2]*3); F424Multiplicative Abelian group isomorphic to C2 x C2 x C2425sage: H = AbelianGroup([2,3], names="xy"); H426Multiplicative Abelian group isomorphic to C2 x C3427sage: AbelianGroup(5)428Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z429sage: AbelianGroup(5).order()430+Infinity431432Notice that `0`'s are prepended if necessary::433434sage: G = AbelianGroup(5, [2,3,4]); G435Multiplicative Abelian group isomorphic to Z x Z x C2 x C3 x C4436sage: G.gens_orders()437(0, 0, 2, 3, 4)438439The invariant list must not be longer than the number of generators::440441sage: AbelianGroup(2, [2,3,4])442Traceback (most recent call last):443...444ValueError: gens_orders (=(2, 3, 4)) must have length n (=2)445"""446gens_orders, names = _normalize(n, gens_orders, names)447M = AbelianGroup_class(gens_orders, names)448return M449450def is_AbelianGroup(x):451"""452Return True if ``x`` is an Abelian group.453454EXAMPLES::455456sage: from sage.groups.abelian_gps.abelian_group import is_AbelianGroup457sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F458Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9459sage: is_AbelianGroup(F)460True461sage: is_AbelianGroup(AbelianGroup(7, [3]*7))462True463"""464return isinstance(x, AbelianGroup_class)465466467class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase):468"""469The parent for Abelian groups with chosen generator orders.470471.. warning::472473You should use :func:`AbelianGroup` to construct Abelian474groups and not instantiate this class directly.475476INPUT:477478- ``generator_orders`` -- list of integers. The orders of the479(commuting) generators. Zero denotes an infinite cyclic480generator.481482- ``names`` -- names of the group generators (optional).483484EXAMPLES::485486sage: Z2xZ3 = AbelianGroup([2,3])487sage: Z6 = AbelianGroup([6])488sage: Z2xZ3 is Z2xZ3, Z6 is Z6489(True, True)490sage: Z2xZ3 is Z6491False492sage: Z2xZ3 == Z6493True494495sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F496Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9497sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F498Multiplicative Abelian group isomorphic to C2 x C4 x C12 x C24 x C120499sage: F.elementary_divisors()500(2, 4, 12, 24, 120)501502sage: F.category()503Category of groups504505TESTS::506507sage: AbelianGroup([]).gens_orders()508()509sage: AbelianGroup([1]).gens_orders()510(1,)511sage: AbelianGroup([1,1]).gens_orders()512(1, 1)513sage: AbelianGroup(0).gens_orders()514()515"""516Element = AbelianGroupElement517518def __init__(self, generator_orders, names):519"""520The Python constructor521522TESTS::523524sage: G = AbelianGroup([0,5,0,7],names = list("abcd")); G525Multiplicative Abelian group isomorphic to Z x C5 x Z x C7526sage: TestSuite(G).run()527"""528assert isinstance(names, (basestring, tuple))529assert isinstance(generator_orders, tuple)530assert all(isinstance(order,Integer) for order in generator_orders)531self._gens_orders = generator_orders532n = ZZ(len(generator_orders))533names = self.normalize_names(n, names)534self._assign_names(names)535AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()536537def is_isomorphic(left, right):538"""539Check whether ``left`` and ``right`` are isomorphic540541INPUT:542543- ``right`` -- anything.544545OUTPUT:546547Boolean. Whether ``left`` and ``right`` are isomorphic as abelian groups.548549EXAMPLES::550551sage: G1 = AbelianGroup([2,3,4,5])552sage: G2 = AbelianGroup([2,3,4,5,1])553sage: G1.is_isomorphic(G2)554True555sage: G1 == G2 # syntactic sugar556True557"""558if not is_AbelianGroup(right):559return False560return left.elementary_divisors() == right.elementary_divisors()561562__eq__ = is_isomorphic563564def __ne__(left, right):565"""566Check whether ``left`` and ``right`` are not isomorphic567568OUTPUT:569570Boolean.571572EXAMPLES::573574sage: G1 = AbelianGroup([2,3,4,5])575sage: G2 = AbelianGroup([2,3,4,5,1])576sage: G1 != G2577False578sage: G1.__ne__(G2)579False580"""581return not left.is_isomorphic(right)582583def is_subgroup(left, right):584"""585Test whether ``left`` is a subgroup of ``right``.586587EXAMPLES::588589sage: G = AbelianGroup([2,3,4,5])590sage: G.is_subgroup(G)591True592593sage: H = G.subgroup([G.1])594sage: H.is_subgroup(G)595True596597sage: G.<a, b> = AbelianGroup(2)598sage: H.<c> = AbelianGroup(1)599sage: H < G600False601"""602for l in left.gens():603if l not in right:604return False605return True606607__le__ = is_subgroup608609def __ge__(left, right):610"""611Test whether ``right`` is a subgroup of ``left``612613EXAMPLE::614615sage: G.<a, b> = AbelianGroup(2)616sage: H.<c> = AbelianGroup(1)617sage: G >= H618False619"""620return right.__le__(left)621622def __lt__(left, right):623"""624Test whether ``left`` is a strict subgroup of ``right``625626EXAMPLE::627628sage: G.<a, b> = AbelianGroup(2)629sage: H.<c> = AbelianGroup(1)630sage: H < G631False632"""633return left <= right and left != right634635def __gt__(left, right):636"""637Test whether ``right`` is a strict subgroup of ``left``638639EXAMPLE::640641sage: G.<a, b> = AbelianGroup(2)642sage: H.<c> = AbelianGroup(1)643sage: G > H644False645"""646return left >= right and left != right647648def is_trivial(self):649"""650Return whether the group is trivial651652A group is trivial if it has precisely one element.653654EXAMPLES::655656sage: AbelianGroup([2, 3]).is_trivial()657False658sage: AbelianGroup([1, 1]).is_trivial()659True660"""661return self.elementary_divisors() == ()662663def __nonzero__(self):664"""665Returns True if this group is nontrivial.666667EXAMPLES::668669sage: T = AbelianGroup([2, 3])670sage: bool(T) # indirect doctest671True672sage: bool(AbelianGroup([]))673False674sage: bool(AbelianGroup([1,1,1]))675False676"""677return not self.is_trivial()678679@cached_method680def dual_group(self, names="X", base_ring=None):681"""682Returns the dual group.683684INPUT:685686- ``names`` -- string or list of strings. The generator names687for the dual group.688689- ``base_ring`` -- the base ring. If ``None`` (default), then690a suitable cyclotomic field is picked automatically.691692OUTPUT:693694The695:class:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class696<dual abelian group>`697698EXAMPLES::699700sage: G = AbelianGroup([2])701sage: G.dual_group()702Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1703sage: G.dual_group().gens()704(X,)705sage: G.dual_group(names='Z').gens()706(Z,)707708sage: G.dual_group(base_ring=QQ)709Dual of Abelian Group isomorphic to Z/2Z over Rational Field710711712TESTS::713714sage: H = AbelianGroup(1)715sage: H.dual_group()716Traceback (most recent call last):717...718ValueError: the group must be finite719"""720from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup_class721if not self.is_finite():722raise ValueError('the group must be finite')723if base_ring is None:724from sage.rings.number_field.number_field import CyclotomicField725from sage.rings.arith import LCM726base_ring = CyclotomicField(LCM(self.gens_orders()))727return DualAbelianGroup_class(self, names=names, base_ring=base_ring)728729@cached_method730def elementary_divisors(self):731r"""732This returns the elementary divisors of the group, using Pari.733734.. note::735736Here is another algorithm for computing the elementary divisors737`d_1, d_2, d_3, \ldots`, of a finite abelian group (where `d_1 | d_2 | d_3 | \ldots`738are composed of prime powers dividing the invariants of the group739in a way described below). Just factor the invariants `a_i` that740define the abelian group. Then the biggest `d_i` is the product741of the maximum prime powers dividing some `a_j`. In other words, the742largest `d_i` is the product of `p^v`, where `v = max(ord_p(a_j) \mathrm{ for all } j`).743Now divide out all those `p^v`'s into the list of invariants `a_i`,744and get a new list of "smaller invariants"". Repeat the above procedure745on these ""smaller invariants"" to compute `d_{i-1}`, and so on.746(Thanks to Robert Miller for communicating this algorithm.)747748OUTPUT:749750A tuple of integers.751752EXAMPLES::753754sage: G = AbelianGroup(2,[2,3])755sage: G.elementary_divisors()756(6,)757sage: G = AbelianGroup(1, [6])758sage: G.elementary_divisors()759(6,)760sage: G = AbelianGroup(2,[2,6])761sage: G762Multiplicative Abelian group isomorphic to C2 x C6763sage: G.gens_orders()764(2, 6)765sage: G.elementary_divisors()766(2, 6)767sage: J = AbelianGroup([1,3,5,12])768sage: J.elementary_divisors()769(3, 60)770sage: G = AbelianGroup(2,[0,6])771sage: G.elementary_divisors()772(6, 0)773sage: AbelianGroup([3,4,5]).elementary_divisors()774(60,)775"""776from sage.matrix.constructor import diagonal_matrix777ed = diagonal_matrix(ZZ, self.gens_orders()).elementary_divisors()778return tuple(d for d in ed if d!=1)779780@cached_method781def exponent(self):782"""783Return the exponent of this abelian group.784785EXAMPLES::786787sage: G = AbelianGroup([2,3,7]); G788Multiplicative Abelian group isomorphic to C2 x C3 x C7789sage: G.exponent()79042791sage: G = AbelianGroup([2,4,6]); G792Multiplicative Abelian group isomorphic to C2 x C4 x C6793sage: G.exponent()79412795"""796return lcm(self.gens_orders())797798def identity(self):799r"""800Return the identity element of this group.801802EXAMPLES::803804sage: G = AbelianGroup([2,2])805sage: e = G.identity()806sage: e8071808sage: g = G.gen(0)809sage: g*e810f0811sage: e*g812f0813"""814return self(1)815816def _group_notation(self, eldv):817"""818Return abstract group notation for generator orders ``eldv``819820INPUT:821822- ``eldv`` -- iterable of integers.823824OUTPUT:825826String.827828EXAMPLES::829830sage: G = AbelianGroup([2,2])831sage: G._group_notation([0,1,2,3])832'Z x C1 x C2 x C3'833"""834v = []835for x in eldv:836if x:837v.append("C%s"%x)838else:839v.append("Z")840return ' x '.join(v)841842def _latex_(self):843r"""844Return latex representation of this group.845846EXAMPLES::847848sage: F = AbelianGroup(10, [2]*10)849sage: F._latex_()850'$\\mathrm{AbelianGroup}( 10, (2, 2, 2, 2, 2, 2, 2, 2, 2, 2) )$'851"""852s = "$\mathrm{AbelianGroup}( %s, %s )$"%(self.ngens(), self.gens_orders())853return s854855def _gap_init_(self):856r"""857Return string that defines corresponding abelian group in GAP.858859EXAMPLES::860861sage: G = AbelianGroup([2,3,9])862sage: G._gap_init_()863'AbelianGroup([2, 3, 9])'864sage: gap(G)865Group( [ f1, f2, f3 ] )866867Only works for finite groups::868869sage: G = AbelianGroup(3,[0,3,4],names="abc"); G870Multiplicative Abelian group isomorphic to Z x C3 x C4871sage: G._gap_init_()872Traceback (most recent call last):873...874TypeError: abelian groups in GAP are finite, but self is infinite875"""876# TODO: Use the package polycyclic has AbelianPcpGroup, which can handle877# the infinite case but it is a GAP package not GPL'd.878# Use this when the group is infinite...879# return 'AbelianPcpGroup(%s)'%list(self.invariants())880if not self.is_finite():881raise TypeError('abelian groups in GAP are finite, but self is infinite')882return 'AbelianGroup(%s)'%list(self.gens_orders())883884def gen(self, i=0):885"""886The `i`-th generator of the abelian group.887888EXAMPLES::889890sage: F = AbelianGroup(5,[],names='a')891sage: F.0892a0893sage: F.2894a2895sage: F.gens_orders()896(0, 0, 0, 0, 0)897898sage: G = AbelianGroup([2,1,3])899sage: G.gens()900(f0, 1, f2)901"""902n = self.ngens()903if i < 0 or i >= n:904raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)905x = [0]*n906if self._gens_orders[i] != 1:907x[i] = 1908return self.element_class(self, x)909910def gens(self):911"""912Return the generators of the group.913914OUTPUT:915916A tuple of group elements. The generators according to the917chosen :meth:`gens_orders`.918919EXAMPLES::920921sage: F = AbelianGroup(5,[3,2],names='abcde')922sage: F.gens()923(a, b, c, d, e)924sage: [ g.order() for g in F.gens() ]925[+Infinity, +Infinity, +Infinity, 3, 2]926"""927return tuple( self.gen(i) for i in range(self.ngens()) )928929def gens_orders(self):930"""931Return the orders of the cyclic factors that this group has932been defined with.933934Use :meth:`elementary_divisors` if you are looking for an935invariant of the group.936937OUTPUT:938939A tuple of integers.940941EXAMPLES::942943sage: Z2xZ3 = AbelianGroup([2,3])944sage: Z2xZ3.gens_orders()945(2, 3)946sage: Z2xZ3.elementary_divisors()947(6,)948949sage: Z6 = AbelianGroup([6])950sage: Z6.gens_orders()951(6,)952sage: Z6.elementary_divisors()953(6,)954955sage: Z2xZ3.is_isomorphic(Z6)956True957sage: Z2xZ3 is Z6958False959960TESTS::961962sage: F = AbelianGroup(3, [2], names='abc')963sage: map(type, F.gens_orders())964[<type 'sage.rings.integer.Integer'>,965<type 'sage.rings.integer.Integer'>,966<type 'sage.rings.integer.Integer'>]967"""968return self._gens_orders969970def invariants(self):971"""972Return the orders of the cyclic factors that this group has973been defined with.974975For historical reasons this has been called invariants in976Sage, even though they are not necessarily the invariant977factors of the group. Use :meth:`gens_orders` instead::978979sage: J = AbelianGroup([2,0,3,2,4]); J980Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4981sage: J.invariants() # deprecated982(2, 0, 3, 2, 4)983sage: J.gens_orders() # use this instead984(2, 0, 3, 2, 4)985sage: for i in range(J.ngens()):986... print i, J.gen(i), J.gen(i).order() # or use this9870 f0 29881 f1 +Infinity9892 f2 39903 f3 29914 f4 4992993Use :meth:`elementary_divisors` if you are looking for an994invariant of the group.995996OUTPUT:997998A tuple of integers. Zero means infinite cyclic factor.9991000EXAMPLES::10011002sage: J = AbelianGroup([2,3])1003sage: J.invariants()1004(2, 3)1005sage: J.elementary_divisors()1006(6,)10071008TESTS::10091010sage: F = AbelianGroup(3, [2], names='abc')1011sage: map(type, F.gens_orders())1012[<type 'sage.rings.integer.Integer'>,1013<type 'sage.rings.integer.Integer'>,1014<type 'sage.rings.integer.Integer'>]1015"""1016# TODO: deprecate1017return self.gens_orders()10181019def is_cyclic(self):1020"""1021Return True if the group is a cyclic group.10221023EXAMPLES::10241025sage: J = AbelianGroup([2,3])1026sage: J.gens_orders()1027(2, 3)1028sage: J.elementary_divisors()1029(6,)1030sage: J.is_cyclic()1031True1032sage: G = AbelianGroup([6])1033sage: G.gens_orders()1034(6,)1035sage: G.is_cyclic()1036True1037sage: H = AbelianGroup([2,2])1038sage: H.gens_orders()1039(2, 2)1040sage: H.is_cyclic()1041False1042sage: H = AbelianGroup([2,4])1043sage: H.elementary_divisors()1044(2, 4)1045sage: H.is_cyclic()1046False1047sage: H.permutation_group().is_cyclic()1048False1049sage: T = AbelianGroup([])1050sage: T.is_cyclic()1051True1052sage: T = AbelianGroup(1,[0]); T1053Multiplicative Abelian group isomorphic to Z1054sage: T.is_cyclic()1055True1056sage: B = AbelianGroup([3,4,5])1057sage: B.is_cyclic()1058True1059"""1060return len(self.elementary_divisors()) <= 110611062@cached_method1063def ngens(self):1064"""1065The number of free generators of the abelian group.10661067EXAMPLES::10681069sage: F = AbelianGroup(10000)1070sage: F.ngens()1071100001072"""1073return len(self.gens_orders())10741075@cached_method1076def order(self):1077"""1078Return the order of this group.10791080EXAMPLES::10811082sage: G = AbelianGroup(2,[2,3])1083sage: G.order()108461085sage: G = AbelianGroup(3,[2,3,0])1086sage: G.order()1087+Infinity1088"""1089from sage.rings.all import infinity1090length = prod(self.gens_orders())1091if length == 0:1092return infinity1093return length10941095def permutation_group(self):1096r"""1097Return the permutation group isomorphic to this abelian group.10981099If the invariants are `q_1, \ldots, q_n` then the1100generators of the permutation will be of order1101`q_1, \ldots, q_n`, respectively.11021103EXAMPLES::11041105sage: G = AbelianGroup(2,[2,3]); G1106Multiplicative Abelian group isomorphic to C2 x C31107sage: G.permutation_group()1108Permutation Group with generators [(3,4,5), (1,2)]1109"""1110from sage.groups.perm_gps.permgroup import PermutationGroup1111s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()1112return PermutationGroup(gap_group=s)11131114def is_commutative(self):1115"""1116Return True since this group is commutative.11171118EXAMPLES::11191120sage: G = AbelianGroup([2,3,9, 0])1121sage: G.is_commutative()1122True1123sage: G.is_abelian()1124True1125"""1126return True11271128def random_element(self):1129"""1130Return a random element of this group.11311132EXAMPLES::11331134sage: G = AbelianGroup([2,3,9])1135sage: G.random_element()1136f1^21137"""1138from sage.misc.prandom import randint1139result = self.one()1140for g in self.gens():1141order = g.order()1142if order not in ZZ:1143order = 42 # infinite order; randomly chosen maximum1144result *= g**(randint(0,order))1145return result11461147def _repr_(self):1148"""1149Return a string representation of ``self``.11501151EXAMPLES::11521153sage: G = AbelianGroup([2,3,9])1154sage: G._repr_()1155'Multiplicative Abelian group isomorphic to C2 x C3 x C9'1156"""1157eldv = self.gens_orders()1158if len(eldv) == 0:1159return "Trivial Abelian group"1160g = self._group_notation(eldv)1161return "Multiplicative Abelian group isomorphic to " + g11621163def subgroup(self, gensH, names="f"):1164"""1165Create a subgroup of this group. The "big" group must be defined1166using "named" generators.11671168INPUT:11691170- ``gensH`` -- list of elements which are products of the1171generators of the ambient abelian group G = self11721173EXAMPLES::11741175sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G1176Multiplicative Abelian group isomorphic to C2 x C3 x C41177sage: H = G.subgroup([a*b,a]); H1178Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a}1179sage: H < G1180True1181sage: F = G.subgroup([a,b^2])1182sage: F1183Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}1184sage: F.gens()1185(a, b^2)1186sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))1187sage: a,b,c,d,e = F.gens()1188sage: F.subgroup([a,b])1189Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b}1190sage: F.subgroup([c,e])1191Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729 generated by {c, e}1192"""1193G = self1194gensH = tuple(gensH)1195if isinstance(names, list):1196names = tuple(names)1197for h in gensH:1198if h not in G:1199raise TypeError('Subgroup generators must belong to the given group.')1200return AbelianGroup_subgroup(self, gensH, names)12011202@cached_method1203def list(self):1204"""1205Return tuple of all elements of this group.12061207EXAMPLES::12081209sage: G = AbelianGroup([2,3], names = "ab")1210sage: G.list()1211(1, b, b^2, a, a*b, a*b^2)12121213::12141215sage: G = AbelianGroup([]); G1216Trivial Abelian group1217sage: G.list()1218(1,)1219"""1220if not(self.is_finite()):1221raise NotImplementedError, "Group must be finite"1222return tuple(self.__iter__())12231224def __iter__(self):1225"""1226Return an iterator over the elements of this group.12271228EXAMPLES::12291230sage: G = AbelianGroup([2,3], names = "ab")1231sage: [a for a in G]1232[1, b, b^2, a, a*b, a*b^2]1233sage: L = list(G); L1234[1, b, b^2, a, a*b, a*b^2]12351236The returned list is a reference; mutating it does not allow the1237user to (accidentally?) alter the computed generators::12381239sage: L[0] = 01240sage: list(G)1241[1, b, b^2, a, a*b, a*b^2]1242sage: G = AbelianGroup([1], names="a")1243sage: list(G)1244[1]1245sage: G = AbelianGroup([])1246sage: G.list()1247(1,)1248sage: list(G)1249[1]1250"""1251invs = self.gens_orders()1252for t in mrange(invs):1253yield self(t)12541255def subgroups(self, check=False):1256r"""1257Compute all the subgroups of this abelian group (which must be finite).12581259TODO: This is *many orders of magnitude* slower than Magma.12601261INPUT:12621263- check: if True, performs the same computation in GAP and checks that1264the number of subgroups generated is the same. (I don't know how to1265convert GAP's output back into Sage, so we don't actually compare the1266subgroups).12671268ALGORITHM:12691270If the group is cyclic, the problem is easy. Otherwise, write it as1271a direct product A x B, where B is cyclic. Compute the subgroups of1272A (by recursion).12731274Now, for every subgroup C of A x B, let G be its *projection onto*1275A and H its *intersection with* B. Then there is a well-defined1276homomorphism f: G -> B/H that sends a in G to the class mod H of b,1277where (a,b) is any element of C lifting a; and every subgroup C1278arises from a unique triple (G, H, f).12791280EXAMPLES::12811282sage: AbelianGroup([2,3]).subgroups()1283[Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {f0*f1^2},1284Multiplicative Abelian subgroup isomorphic to C2 generated by {f0},1285Multiplicative Abelian subgroup isomorphic to C3 generated by {f1},1286Trivial Abelian subgroup]1287sage: len(AbelianGroup([2,4,8]).subgroups())12888112891290TESTS::12911292sage: AbelianGroup([]).subgroups()1293[Trivial Abelian group]1294"""1295if not self.is_finite(): raise ValueError, "Group must be finite"1296from sage.misc.misc import verbose12971298if self.is_trivial():1299return [self]1300if self.ngens() == 1:1301n = self.gen(0).order()1302return [ self.subgroup([self.gen(0)**i]) for i in divisors(n) ]13031304v = self.gens_orders()1305A = AbelianGroup(v[:-1])1306x = v[-1]13071308Wsubs = A.subgroups()13091310subgps = []1311for G in Wsubs:1312verbose("G = subgp generated by %s" % list(G.gens()))1313verbose("invariants are:", [t.order() for t in G.gens()])1314for H in divisors(x):1315# H = the subgroup of *index* H.1316its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))]1317for f in cartesian_product_iterator(its):1318verbose("using hom from G to C_%s sending gens to %s" % (H,f))1319new_sub = []1320for a in xrange(len(G.gens())):1321new_sub.append(G.gen(a).list() + [f[a]])1322if H != x:1323new_sub.append([0]*A.ngens() + [H])1324subgps.append(self.subgroup_reduced(new_sub))13251326if check:1327from sage.interfaces.all import gap1328verbose("Running Gap cross-check")1329t = ZZ(gap.eval("Size(SubgroupsSolvableGroup(AbelianGroup(%s)))" % v))1330if t != len(subgps):1331raise ArithmeticError, "For %s Gap finds %s subgroups, I found %s" % (v, t, len(subgps))1332verbose("Gap check OK for %s: %s" % (v, t))1333return subgps13341335def subgroup_reduced(self,elts, verbose=False):1336r"""1337Given a list of lists of integers (corresponding to elements of self),1338find a set of independent generators for the subgroup generated by1339these elements, and return the subgroup with these as generators,1340forgetting the original generators.13411342This is used by the ``subgroups`` routine.13431344An error will be raised if the elements given are not linearly1345independent over QQ.13461347EXAMPLE::13481349sage: G = AbelianGroup([4,4])1350sage: G.subgroup( [ G([1,0]), G([1,2]) ])1351Multiplicative Abelian subgroup isomorphic to C2 x C41352generated by {f0, f0*f1^2}1353sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])1354Multiplicative Abelian subgroup isomorphic to C2 x C41355generated by {f1^2, f0}1356"""1357from sage.matrix.constructor import matrix1358d = self.ngens()1359X = ZZ**d1360try:1361elt_lattice = X.submodule_with_basis(elts)1362except ValueError, e:1363# can't happen?1364print "Vectors not LI: ", elts1365raise e1366rel_lattice = X.span([X.gen(i) * self.gens_orders()[i] for i in xrange(d)])1367isect = elt_lattice.intersection(rel_lattice)1368mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)1369D,U,V = mat.smith_form()1370new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i,i]) for i in xrange(U.ncols())]1371return self.subgroup([self([x[0][i] % self.gens_orders()[i]1372for i in xrange(d)]) for x in new_basis if x[1] != 1])13731374class AbelianGroup_subgroup(AbelianGroup_class):1375"""1376Subgroup subclass of AbelianGroup_class, so instance methods are1377inherited.13781379TODO:13801381- There should be a way to coerce an element of a subgroup1382into the ambient group.1383"""1384def __init__(self, ambient, gens, names="f"):1385"""1386EXAMPLES::13871388sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))1389sage: a,b,c,d,e = F.gens()1390sage: F.subgroup([a^3,b])1391Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a^3, b}1392sage: F.subgroup([c])1393Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 generated by {c}1394sage: F.subgroup([a, c])1395Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x Z generated by {a, c}1396sage: F.subgroup([a, b*c])1397Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b*c}1398sage: F.subgroup([b*c, d])1399Multiplicative Abelian subgroup isomorphic to C64 x Z generated by {b*c, d}1400sage: F.subgroup([a*b, c^6, d],names=list("xyz"))1401Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}1402sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H1403Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}1404sage: G = F.subgroup([a*b, c^6, d],names = list("xyz")); G1405Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}1406sage: x,y,z = G.gens()1407sage: x.order()1408+Infinity1409sage: y.order()141051411sage: z.order()1412641413sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde")1414sage: a,b,c,d,e = A.gens()1415sage: A.subgroup([a,b])1416Multiplicative Abelian subgroup isomorphic to C3 x C5 generated by {a, b}1417sage: A.subgroup([a,b,c,d^2,e])1418Multiplicative Abelian subgroup isomorphic to C3 x C5 x C5 x C7 x C8 generated by {a, b, c, d^2, e}1419sage: A.subgroup([a, b, c, d^2, e^2])1420Multiplicative Abelian subgroup isomorphic to C3 x C4 x C5 x C5 x C7 generated by {a, b, c, d^2, e^2}1421sage: B = A.subgroup([a^3, b, c, d, e^2]); B1422Multiplicative Abelian subgroup isomorphic to C4 x C5 x C5 x C7 generated by {b, c, d, e^2}1423sage: B.gens_orders()1424(4, 5, 5, 7)1425sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd")1426sage: a,b,c,d = A.gens()1427sage: B = A.subgroup([a^3,b,c,d])1428sage: B.gens_orders()1429(1009, 2003, 3001, 4001)1430sage: A.order()1431242664732100271432sage: B.order()1433242664732100271434sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd")1435sage: a,b,c,d = A.gens()1436sage: B = A.subgroup([a^3,b,c,d]); B1437Multiplicative Abelian subgroup isomorphic1438to C3 x C7 x C16 x C2003 x C3001 x C4001 generated by {a^3, b, c, d}14391440Infinite groups can also be handled::14411442sage: G = AbelianGroup([3,4,0], names = "abc")1443sage: a,b,c = G.gens()1444sage: F = G.subgroup([a, b^2, c]); F1445Multiplicative Abelian subgroup isomorphic to C2 x C3 x Z generated by {a, b^2, c}14461447sage: F.gens_orders()1448(2, 3, 0)1449sage: F.gens()1450(a, b^2, c)1451sage: F.order()1452+Infinity1453"""1454from sage.interfaces.all import gap1455if not isinstance(ambient, AbelianGroup_class):1456raise TypeError, "ambient (=%s) must be an abelian group."%ambient1457if not isinstance(gens, tuple):1458raise TypeError, "gens (=%s) must be a tuple"%gens14591460self._ambient_group = ambient1461Hgens = tuple(x for x in gens if x != ambient.one()) ## in case someone puts 1 in the list of generators1462self._gens = Hgens1463m = len(gens)1464ell = len(ambient.gens())1465ambient_invs = ambient.gens_orders()1466invsf = [x for x in ambient_invs if x > 0] ## fixes the problem with1467invs0 = [x for x in ambient_invs if x == 0] ## the infinite parts1468Ggens = list(ambient.variable_names())1469if invs0!=[]:1470Gfgens = [x for x in ambient.variable_names() if1471ambient_invs[Ggens.index(x)] != 0]1472Ggens0 = [x for x in ambient.variable_names() if1473ambient_invs[Ggens.index(x)] == 0]1474## ^^ only look at "finite" names1475Gf = AbelianGroup(invsf, names=Gfgens)1476s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_()1477gap.eval(s1)1478Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0]1479# computes the gens of H which do not occur ^^ in the infinite part of G1480Hgens0 = [x for x in Hgens if not(x in Hgensf)]1481# the "infinite" generators of H1482for i in range(len(Gfgens)):1483cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i]1484gap.eval(cmd)1485else: # invs0==[]:1486Hgensf = Hgens1487Hgens0 = [] # added for consistency1488G = ambient1489s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()1490gap.eval(s1)1491for i in range(len(Ggens)):1492cmd = '%s := gens[%s]'%(Ggens[i], i+1)1493#print i," \n",cmd1494gap.eval(cmd)1495s2 = "gensH:=%s"%list(Hgensf) #### remove from this the ones <--> 0 invar1496gap.eval(s2)1497s3 = 'H:=Subgroup(G,gensH)'1498gap.eval(s3)1499# a GAP command which returns the "invariants" of the1500# subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)),1501# works if G is the subgroup declared as a AbelianPcpGroup1502self._abinvs = eval(gap.eval("AbelianInvariants(H)"))1503invs = self._abinvs1504#print s3, invs1505if Hgens0 != []:1506for x in Hgens0:1507invs.append(0)1508invs = tuple(ZZ(i) for i in invs)1509AbelianGroup_class.__init__(self, invs, names)15101511def __contains__(self, x):1512"""1513Test whether ``x`` is an element of this subgroup.15141515EXAMPLES::15161517sage: G.<a,b> = AbelianGroup(2)1518sage: A = G.subgroup([a])1519sage: a in G1520True1521sage: a in A1522True1523"""1524if not isinstance(x, AbelianGroupElement):1525return False1526if x.parent() is self:1527return True1528elif x in self.ambient_group():1529amb_inv = self.ambient_group().gens_orders()1530for a in xrange(len(amb_inv)):1531if amb_inv[a] == 0 and x.list()[a] != 0:1532for g in self._gens:1533if g.list()[a] == 0:1534continue1535if abs(x.list()[a]%g.list()[a]) < abs(x.list()[a]):1536if g.list()[a]*x.list()[a] < 0:1537x *= g**(x.list()[a]/g.list()[a])1538else:1539x *= g**((-1)*(x.list()[a]/g.list()[a]))1540if x.list()[a] == 0:1541break1542elif x.list()[a] != 0:1543for g in self._gens:1544if g.list()[a] == 0:1545continue1546if abs(x.list()[a]%g.list()[a])%abs(amb_inv[a]) < x.list()[a]%abs(amb_inv[a]):1547x *= g**((-1)*(x.list()[a]/g.list()[a]))1548if x.list()[a] == 0:1549break1550return x == x.parent()(1)15511552def ambient_group(self):1553"""1554Return the ambient group related to self.15551556OUTPUT:15571558A multiplicative Abelian group.15591560EXAMPLES::15611562sage: G.<a,b,c> = AbelianGroup([2,3,4])1563sage: H = G.subgroup([a, b^2])1564sage: H.ambient_group() is G1565True1566"""1567return self._ambient_group15681569def equals(left, right):1570"""1571Check whether ``left`` and ``right`` are the same (sub)group.15721573INPUT:15741575- ``right`` -- anything.15761577OUTPUT:15781579Boolean. If ``right`` is a subgroup, test whether ``left`` and1580``right`` are the same subset of the ambient group. If1581``right`` is not a subgroup, test whether they are isomorphic1582groups, see :meth:`~AbelianGroup_class.is_isomorphic`.15831584EXAMPLES::15851586sage: G = AbelianGroup(3, [2,3,4], names="abc"); G1587Multiplicative Abelian group isomorphic to C2 x C3 x C41588sage: a,b,c = G.gens()1589sage: F = G.subgroup([a,b^2]); F1590Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}1591sage: F<G1592True15931594sage: A = AbelianGroup(1, [6])1595sage: A.subgroup(list(A.gens())) == A1596True15971598sage: G.<a,b> = AbelianGroup(2)1599sage: A = G.subgroup([a])1600sage: B = G.subgroup([b])1601sage: A.equals(B)1602False1603sage: A == B # sames as A.equals(B)1604False1605sage: A.is_isomorphic(B)1606True1607"""1608left_ambient = left.ambient_group()1609try:1610right_ambient = right.ambient_group()1611except AttributeError:1612# right is not a subgroup1613return left.is_isomorphic(right)1614if left_ambient is not right_ambient:1615return False1616return left <= right and right <= left16171618__eq__ = equals16191620def _repr_(self):1621"""1622Return a string representation16231624EXAMPLES::16251626sage: G.<a,b> = AbelianGroup(2)1627sage: G._repr_()1628'Multiplicative Abelian group isomorphic to Z x Z'1629sage: A = G.subgroup([a])1630sage: A._repr_()1631'Multiplicative Abelian subgroup isomorphic to Z generated by {a}'1632"""1633eldv = self.gens_orders()1634if self.is_trivial():1635return "Trivial Abelian subgroup"1636s = 'Multiplicative Abelian subgroup isomorphic to '1637s += self._group_notation(eldv)1638s += ' generated by '1639s += '{' + ', '.join(map(str, self.gens())) + '}'1640return s16411642def gens(self):1643"""1644Return the generators for this subgroup.16451646OUTPUT:16471648A tuple of group elements generating the subgroup.16491650EXAMPLES::16511652sage: G.<a,b> = AbelianGroup(2)1653sage: A = G.subgroup([a])1654sage: G.gens()1655(a, b)1656sage: A.gens()1657(a,)1658"""1659return self._gens16601661def gen(self, n):1662"""1663Return the nth generator of this subgroup.16641665EXAMPLE::16661667sage: G.<a,b> = AbelianGroup(2)1668sage: A = G.subgroup([a])1669sage: A.gen(0)1670a1671"""1672return self._gens[n]1673167416751676