# Commits

committed b3e0e55

rebased to sage-5.7.beta2

• Participants
• Parent commits fe4f12f

# File 13687_32bitfix.patch

-# HG changeset patch
-# Parent 35615722fd3e6d0aed6e37164f7318ac8cfe872e
-
-Fix some doctests that are different on 32-bit
-
-diff --git a/sage/rings/number_field/unit_group.py b/sage/rings/number_field/unit_group.py
---- a/sage/rings/number_field/unit_group.py
-+++ b/sage/rings/number_field/unit_group.py
-@@ -136,7 +136,8 @@
-         sage: u = UK.an_element();  u
-         u0*u1
-         sage: u.value()
--        -1/4*a^3 - 7/4*a^2 - 17/4*a - 19/4
-+        -1/4*a^3 + 7/4*a^2 - 17/4*a + 19/4     # 32-bit
-+        -1/4*a^3 - 7/4*a^2 - 17/4*a - 19/4     # 64-bit
-
-         sage: x = polygen(QQ)
-         sage: K.<a> = NumberField(x^4 + 23)
-diff --git a/sage/rings/polynomial/polynomial_quotient_ring.py b/sage/rings/polynomial/polynomial_quotient_ring.py
---- a/sage/rings/polynomial/polynomial_quotient_ring.py
-+++ b/sage/rings/polynomial/polynomial_quotient_ring.py
-@@ -972,7 +972,7 @@
-             sage: S.S_class_group([K.ideal(2, a+1)])
-             []
-             sage: S.S_class_group([K.ideal(a)])
--            [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6, 1/2*xbar - 3/2)] # 32-bit
-+            [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6, -1/2*xbar + 3/2)] # 32-bit
-             [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6, -1/2*xbar + 3/2)] # 64-bit
-
-         Now we take an example over a nontrivial base with two factors, each

# File 13687_parent_for_groups_all.patch

-# HG changeset patch
-# User Volker Braun <vbraun@stp.dias.ie>
-# Date 1352835583 18000
-# Node ID 5a5673e6beb0a82cda2dcfedae5c874ab2176588
-# Parent  908396c26c29b73e36d91ae4821b8a353ef23c83
-New-style parents for Abelian groups
-
-diff --git a/doc/de/tutorial/tour_advanced.rst b/doc/de/tutorial/tour_advanced.rst
---- a/doc/de/tutorial/tour_advanced.rst
-+++ b/doc/de/tutorial/tour_advanced.rst
-@@ -362,7 +362,7 @@
-     Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
-
-     sage: G.unit_gens()
--    [11, 17]
-+    (11, 17)
-     sage: G.zeta()
-     i
-     sage: G.zeta_order()
-diff --git a/doc/de/tutorial/tour_groups.rst b/doc/de/tutorial/tour_groups.rst
---- a/doc/de/tutorial/tour_groups.rst
-+++ b/doc/de/tutorial/tour_groups.rst
-@@ -82,10 +82,10 @@
-     sage: d * b**2 * c**3
-     b^2*c^3*d
-     sage: F = AbelianGroup(3,[2]*3); F
--    Multiplicative Abelian Group isomorphic to C2 x C2 x C2
-+    Multiplicative Abelian group isomorphic to C2 x C2 x C2
-     sage: H = AbelianGroup([2,3], names="xy"); H
--    Multiplicative Abelian Group isomorphic to C2 x C3
-+    Multiplicative Abelian group isomorphic to C2 x C3
-     sage: AbelianGroup(5)
--    Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
-+    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
-     sage: AbelianGroup(5).order()
-     +Infinity
-diff --git a/doc/en/bordeaux_2008/nf_galois_groups.rst b/doc/en/bordeaux_2008/nf_galois_groups.rst
---- a/doc/en/bordeaux_2008/nf_galois_groups.rst
-+++ b/doc/en/bordeaux_2008/nf_galois_groups.rst
-@@ -311,7 +311,7 @@
-     sage: category(C)
-     Category of groups
-     sage: C.gens()
--    [Fractional ideal class (5, a), Fractional ideal class (3, a)]
-+    (Fractional ideal class (5, a), Fractional ideal class (3, a))
-
-
- Arithmetic in the class group
-diff --git a/doc/en/reference/groups.rst b/doc/en/reference/groups.rst
---- a/doc/en/reference/groups.rst
-+++ b/doc/en/reference/groups.rst
-@@ -9,9 +9,12 @@
-    sage/groups/group
-    sage/groups/generic
-    sage/groups/abelian_gps/abelian_group
-+   sage/groups/abelian_gps/values
-+   sage/groups/abelian_gps/dual_abelian_group
-+   sage/groups/abelian_gps/element_base
-    sage/groups/abelian_gps/abelian_group_element
-+   sage/groups/abelian_gps/dual_abelian_group_element
-    sage/groups/abelian_gps/abelian_group_morphism
--   sage/groups/abelian_gps/dual_abelian_group
-    sage/groups/additive_abelian/additive_abelian_group
-    sage/groups/additive_abelian/additive_abelian_wrapper
-    sage/groups/perm_gps/permgroup
-diff --git a/doc/en/tutorial/tour_advanced.rst b/doc/en/tutorial/tour_advanced.rst
---- a/doc/en/tutorial/tour_advanced.rst
-+++ b/doc/en/tutorial/tour_advanced.rst
-@@ -360,7 +360,7 @@
-     Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
-
-     sage: G.unit_gens()
--    [11, 17]
-+    (11, 17)
-     sage: G.zeta()
-     i
-     sage: G.zeta_order()
-diff --git a/doc/en/tutorial/tour_groups.rst b/doc/en/tutorial/tour_groups.rst
---- a/doc/en/tutorial/tour_groups.rst
-+++ b/doc/en/tutorial/tour_groups.rst
-@@ -80,10 +80,10 @@
-     sage: d * b**2 * c**3
-     b^2*c^3*d
-     sage: F = AbelianGroup(3,[2]*3); F
--    Multiplicative Abelian Group isomorphic to C2 x C2 x C2
-+    Multiplicative Abelian group isomorphic to C2 x C2 x C2
-     sage: H = AbelianGroup([2,3], names="xy"); H
--    Multiplicative Abelian Group isomorphic to C2 x C3
-+    Multiplicative Abelian group isomorphic to C2 x C3
-     sage: AbelianGroup(5)
--    Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
-+    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
-     sage: AbelianGroup(5).order()
-     +Infinity
-diff --git a/doc/fr/tutorial/tour_advanced.rst b/doc/fr/tutorial/tour_advanced.rst
---- a/doc/fr/tutorial/tour_advanced.rst
-+++ b/doc/fr/tutorial/tour_advanced.rst
-@@ -360,7 +360,7 @@
-     Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
-
-     sage: G.unit_gens()
--    [11, 17]
-+    (11, 17)
-     sage: G.zeta()
-     i
-     sage: G.zeta_order()
-diff --git a/doc/fr/tutorial/tour_groups.rst b/doc/fr/tutorial/tour_groups.rst
---- a/doc/fr/tutorial/tour_groups.rst
-+++ b/doc/fr/tutorial/tour_groups.rst
-@@ -83,10 +83,10 @@
-     sage: d * b**2 * c**3
-     b^2*c^3*d
-     sage: F = AbelianGroup(3,[2]*3); F
--    Multiplicative Abelian Group isomorphic to C2 x C2 x C2
-+    Multiplicative Abelian group isomorphic to C2 x C2 x C2
-     sage: H = AbelianGroup([2,3], names="xy"); H
--    Multiplicative Abelian Group isomorphic to C2 x C3
-+    Multiplicative Abelian group isomorphic to C2 x C3
-     sage: AbelianGroup(5)
--    Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
-+    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
-     sage: AbelianGroup(5).order()
-     +Infinity
-diff --git a/doc/ru/tutorial/tour_advanced.rst b/doc/ru/tutorial/tour_advanced.rst
---- a/doc/ru/tutorial/tour_advanced.rst
-+++ b/doc/ru/tutorial/tour_advanced.rst
-@@ -325,7 +325,7 @@
-     Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
-
-     sage: G.unit_gens()
--    [11, 17]
-+    (11, 17)
-     sage: G.zeta()
-     i
-     sage: G.zeta_order()
-diff --git a/doc/ru/tutorial/tour_groups.rst b/doc/ru/tutorial/tour_groups.rst
---- a/doc/ru/tutorial/tour_groups.rst
-+++ b/doc/ru/tutorial/tour_groups.rst
-@@ -80,10 +80,10 @@
-     sage: d * b**2 * c**3
-     b^2*c^3*d
-     sage: F = AbelianGroup(3,[2]*3); F
--    Multiplicative Abelian Group isomorphic to C2 x C2 x C2
-+    Multiplicative Abelian group isomorphic to C2 x C2 x C2
-     sage: H = AbelianGroup([2,3], names="xy"); H
--    Multiplicative Abelian Group isomorphic to C2 x C3
-+    Multiplicative Abelian group isomorphic to C2 x C3
-     sage: AbelianGroup(5)
--    Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
-+    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
-     sage: AbelianGroup(5).order()
-     +Infinity
-diff --git a/module_list.py b/module_list.py
---- a/module_list.py
-+++ b/module_list.py
-@@ -488,6 +488,9 @@
-     Extension('sage.groups.group',
-               sources = ['sage/groups/group.pyx']),
-
-+    Extension('sage.groups.old',
-+              sources = ['sage/groups/old.pyx']),
-+
-     Extension('sage.groups.perm_gps.permgroup_element',
-               sources = ['sage/groups/perm_gps/permgroup_element.pyx']),
-
-diff --git a/sage/algebras/group_algebra.py b/sage/algebras/group_algebra.py
---- a/sage/algebras/group_algebra.py
-+++ b/sage/algebras/group_algebra.py
-@@ -30,6 +30,7 @@
- from sage.algebras.algebra_element import AlgebraElement
- from sage.rings.all import IntegerRing
- from sage.groups.group import Group
-+from sage.groups.old import Group as OldGroup
- from sage.structure.formal_sum import FormalSums, FormalSum
- from sage.sets.set import Set
-
-@@ -67,7 +68,7 @@
-         if not base_ring.is_commutative():
-             raise NotImplementedError("Base ring must be commutative")
-
--        if not isinstance(group, Group):
-+        if not isinstance(group, (Group, OldGroup)):
-             raise TypeError('"%s" is not a group' % group)
-
-         ParentWithGens.__init__(self, base_ring, category = GroupAlgebras(base_ring))
-@@ -251,7 +252,7 @@
-             sage: ZG(1) == ZG(G(1))
-             True
-             sage: ZG(FormalSum([(1,f), (2, f**2)]))
--            2*f^2 + f
-+            f + 2*f^2
-             sage: G = GL(2,7)
-             sage: OG = GroupAlgebra(G, ZZ[sqrt(5)])
-             sage: OG(2)
-diff --git a/sage/algebras/group_algebra_new.py b/sage/algebras/group_algebra_new.py
---- a/sage/algebras/group_algebra_new.py
-+++ b/sage/algebras/group_algebra_new.py
-@@ -256,10 +256,11 @@
-             Group algebra of group "General Linear Group of degree 3 over Finite Field of size 7" over base ring Integer Ring
-         """
-         from sage.groups.group import Group
-+        from sage.groups.old import Group as OldGroup
-         if not base_ring.is_commutative():
-             raise NotImplementedError("Base ring must be commutative")
-
--        if not isinstance(group, Group):
-+        if not isinstance(group, (Group, OldGroup)):
-             raise TypeError('"%s" is not a group' % group)
-
-         self._group = group
-@@ -680,7 +681,7 @@
-             True
-         """
-         from sage.rings.all import is_Ring
--        from sage.groups.group import Group
-+        from sage.groups.old import Group
-         k = self.base_ring()
-         G = self.group()
-         if isinstance(S, GroupAlgebra):
-@@ -732,7 +733,7 @@
-             [0 1]
-         """
-         from sage.rings.all import is_Ring
--        from sage.groups.group import Group
-+        from sage.groups.old import Group
-         from sage.structure.formal_sum import FormalSum
-         k = self.base_ring()
-         G = self.group()
-diff --git a/sage/all.py b/sage/all.py
---- a/sage/all.py
-+++ b/sage/all.py
-@@ -42,6 +42,7 @@
- exit = quit
-
- import os, sys
-+import operator
-
- if 'SAGE_ROOT' not in os.environ:
-     raise RuntimeError("To use the Sage libraries, set the environment variable SAGE_ROOT to the Sage build directory and LD_LIBRARY_PATH to $SAGE_ROOT/local/lib") -diff --git a/sage/categories/action.pyx b/sage/categories/action.pyx ---- a/sage/categories/action.pyx -+++ b/sage/categories/action.pyx -@@ -216,8 +216,9 @@ - An action that acts as the inverse of the given action. -  - TESTS: -+ - This illustrates a shortcoming in the current coercion model. -- See the comments in _call_ below.  -+ See the comments in _call_ below:: -  - sage: x = polygen(QQ,'x') - sage: a = 2*x^2+2; a -@@ -231,10 +232,11 @@ - def __init__(self, Action action): - G = action.G - try: -+ from sage.groups.old import Group as OldGroup - from sage.groups.group import Group - # We must be in the case that parent(~a) == parent(a) - # so we can invert in call_c code below. -- if (PY_TYPE_CHECK(G, Group) and G.is_multiplicative()) or G.is_field(): -+ if (isinstance(G, (Group, OldGroup)) and G.is_multiplicative()) or G.is_field(): - Action.__init__(self, G, action.underlying_set(), action._is_left) - self._action = action - return -diff --git a/sage/categories/category.py b/sage/categories/category.py ---- a/sage/categories/category.py -+++ b/sage/categories/category.py -@@ -23,7 +23,7 @@ - sage: Sets() - Category of sets - sage: GSets(AbelianGroup([2,4,9])) -- Category of G-sets for Multiplicative Abelian Group isomorphic to C2 x C4 x C9 -+ Category of G-sets for Multiplicative Abelian group isomorphic to C2 x C4 x C9 - sage: Semigroups() - Category of semigroups - sage: VectorSpaces(FiniteField(11)) -diff --git a/sage/groups/abelian_gps/abelian_group.py b/sage/groups/abelian_gps/abelian_group.py ---- a/sage/groups/abelian_gps/abelian_group.py -+++ b/sage/groups/abelian_gps/abelian_group.py -@@ -1,31 +1,60 @@ - r""" - Multiplicative Abelian Groups -  --AUTHORS: -+This module lets you compute with finitely generated Abelian groups of the form -  --- William Stein, David Joyner (2008-12): added (user requested) is_cyclic, -- fixed elementary_divisors. -+.. math:: -  --- David Joyner (2006-03): (based on free abelian monoids by David -- Kohel) -+ G = \ZZ^r \oplus \ZZ_{k_1} \oplus \cdots \oplus \ZZ_{k_t} -  --- David Joyner (2006-05) several significant bug fixes -+It is customary to denote the infinite cyclic group \ZZ as having -+order 0, so the data defining the Abelian group can be written as an -+integer vector -  --- David Joyner (2006-08) trivial changes to docs, added random, fixed -- bug in how invariants are recorded -+.. math:: -  --- David Joyner (2006-10) added dual_group method -+ \vec{k} = (0, \dots, 0, k_1, \dots, k_t) -  --- David Joyner (2008-02) fixed serious bug in word_problem -+where there are r zeroes and t non-zero values. To construct this -+Abelian group in Sage, you can either specify all entries of \vec{k} -+or only the non-zero entries together with the total number of -+generators:: -  --- David Joyner (2008-03) fixed bug in trivial group case -+ sage: AbelianGroup([0,0,0,2,3]) -+ Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3 -+ sage: AbelianGroup(5, [2,3]) -+ Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3 -  --- David Loeffler (2009-05) added subgroups method -+It is also legal to specify 1 as the order. The corresponding -+generator will be the neutral element, but it will still take up an -+index in the labelling of the generators:: -  -+ sage: G = AbelianGroup([2,1,3], names='g') -+ sage: G.gens() -+ (g0, 1, g2) -  --TODO:  -+Note that this presentation is not unique, for example \ZZ_6 = \ZZ_2 -+\times \ZZ_3. The orders of the generators -+\vec{k}=(0,\dots,0,k_1,\dots, k_t) has previously been called -+invariants in Sage, even though they are not necessarily the (unique) -+invariant factors of the group. You should now use -+:meth:~AbelianGroup_class.gens_orders instead:: -  --- additive abelian groups should also be supported -+ sage: J = AbelianGroup([2,0,3,2,4]); J -+ Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4 -+ sage: J.gens_orders() # use this instead -+ (2, 0, 3, 2, 4) -+ sage: J.invariants() # deprecated -+ (2, 0, 3, 2, 4) -+ sage: J.elementary_divisors() # these are the "invariant factors" -+ (2, 2, 12, 0) -+ sage: for i in range(J.ngens()): -+ ... print i, J.gen(i), J.gen(i).order() # or use this form -+ 0 f0 2 -+ 1 f1 +Infinity -+ 2 f2 3 -+ 3 f3 2 -+ 4 f4 4 -  - Background on invariant factors and the Smith normal form  - (according to section 4.1 of [C1]): An abelian group is a -@@ -37,7 +66,7 @@ -  - .. math:: -  -- A = \langle a_1\rangle \times \dots \times \langle a_\ell\rangle , -+ A = \langle a_1\rangle \times \dots \times \langle a_\ell\rangle , -  - where ord(a_i)=p_i^{c_i}, for some primes p_i and some - positive integers c_i, i=1,...,\ell. GAP calls the  -@@ -59,15 +88,15 @@ -  - .. math:: -  -- F= -- \left( -- \begin{array}{cccc} -- f_{11} & f_{12} & \dots & f_{1m}\\ -- f_{21} & f_{22} & \dots & f_{2m}\\ -- \vdots & & \ddots & \vdots \\ -- f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m} -- \end{array} -- \right), -+ F= -+ \left( -+ \begin{array}{cccc} -+ f_{11} & f_{12} & \dots & f_{1m}\\ -+ f_{21} & f_{22} & \dots & f_{2m}\\ -+ \vdots & & \ddots & \vdots \\ -+ f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m} -+ \end{array} -+ \right), -  - regarded as a map  - \ZZ^m\rightarrow (\ZZ/p_1^{c_1}\ZZ)\times ...\times (\ZZ/p_\ell^{c_\ell}\ZZ). -@@ -80,41 +109,37 @@ -  - .. math:: -  -- s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}. -- -- -+ s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}. -  - Sage supports multiplicative abelian groups on any prescribed finite --number n \geq 0 of generators. Use the AbelianGroup function --to create an abelian group, and the gen and gens --functions to obtain the corresponding generators. You can print the --generators as arbitrary strings using the optional names --argument to the AbelianGroup function. -+number n \geq 0 of generators. Use the :func:AbelianGroup -+function to create an abelian group, and the -+:meth:~AbelianGroup_class.gen and :meth:~AbelianGroup_class.gens -+methods to obtain the corresponding generators. You can print the -+generators as arbitrary strings using the optional names argument -+to the :func:AbelianGroup function. -  - EXAMPLE 1: -  - We create an abelian group in zero or more variables; the syntax T(1) --creates the identity element even in the rank zero case. -- --:: -+creates the identity element even in the rank zero case:: -  - sage: T = AbelianGroup(0,[]) - sage: T -- Trivial Abelian Group -+ Trivial Abelian group - sage: T.gens() - () - sage: T(1) - 1 -  --EXAMPLE 2: An abelian group uses a multiplicative representation of --elements, but the underlying representation is lists of integer --exponents. -+EXAMPLE 2: -  --:: -+An Abelian group uses a multiplicative representation of elements, but -+the underlying representation is lists of integer exponents:: -  - sage: F = AbelianGroup(5,[3,4,5,5,7],names = list("abcde")) - sage: F -- Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7 -+ Multiplicative Abelian group isomorphic to C3 x C4 x C5 x C5 x C7 - sage: (a,b,c,d,e) = F.gens() - sage: a*b^2*e*d - a*b^2*d*e -@@ -139,36 +164,59 @@ -  - Many basic properties for infinite abelian groups are not - implemented. -+ -+ -+AUTHORS: -+ -+- William Stein, David Joyner (2008-12): added (user requested) is_cyclic, -+ fixed elementary_divisors. -+ -+- David Joyner (2006-03): (based on free abelian monoids by David -+ Kohel) -+ -+- David Joyner (2006-05) several significant bug fixes -+ -+- David Joyner (2006-08) trivial changes to docs, added random, fixed -+ bug in how invariants are recorded -+ -+- David Joyner (2006-10) added dual_group method -+ -+- David Joyner (2008-02) fixed serious bug in word_problem -+ -+- David Joyner (2008-03) fixed bug in trivial group case -+ -+- David Loeffler (2009-05) added subgroups method -+ -+- Volker Braun (2012-11) port to new Parent base. Use tuples for -+ immutables. Rename invariants to gens_orders. - """ -  - ########################################################################## --# Copyright (C) 2006 David Joyner and William Stein -+# Copyright (C) 2006 William Stein <wstein@gmail.com> -+# Copyright (C) 2006 David Joyner <wdjoyner@gmail.com> -+# Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com> - # - # Distributed under the terms of the GNU General Public License (GPL): - # - # http://www.gnu.org/licenses/ - ########################################################################## -  --# TODO: change the "invariants" terminology everywhere to elementary_divisors -- -- -  - from sage.rings.integer import Integer -- -+from sage.rings.integer_ring import ZZ -+from sage.structure.unique_representation import UniqueRepresentation - from sage.rings.infinity import infinity - from sage.rings.arith import divisors, gcd --from abelian_group_element import AbelianGroupElement -+from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement -+from sage.misc.cachefunc import cached_method - from sage.misc.misc import prod - from sage.misc.mrange import mrange, cartesian_product_iterator --import sage.groups.group as group --from sage.rings.integer_ring import IntegerRing - from sage.rings.arith import lcm --ZZ = IntegerRing() -+from sage.groups.group import AbelianGroup as AbelianGroupBase -+ -  - # TODO: this uses perm groups - the AbelianGroupElement instance method - # uses a different implementation. --  -- - def word_problem(words, g, verbose = False): - r""" - G and H are abelian, g in G, H is a subgroup of G generated by a -@@ -202,7 +250,7 @@ - EXAMPLE:: -  - sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G -- Multiplicative Abelian Group isomorphic to C2 x C3 x C4 -+ Multiplicative Abelian group isomorphic to C2 x C3 x C4 - sage: w = word_problem([a*b,a*c], b*c); w #random  - [[a*b, 1], [a*c, 1]]  - sage: prod([x^i for x,i in w]) == b*c -@@ -242,13 +290,12 @@ - AbelianGroupElement is implemented differently (wrapping - GAP's 'EpimorphismFromFreeGroup' and - 'PreImagesRepresentative') and may be faster. --  - """ - from sage.interfaces.all import gap - G = g.parent() -- invs = G.invariants() -+ invs = map(str, G.gens_orders()) - gap.eval("l:=One(Rationals)") -- s1 = 'A:=AbelianGroup(%s)'%invs -+ s1 = 'A:=AbelianGroup([' + ','.join(invs) + '])' - gap.eval(s1) - s2 = 'phi:=IsomorphismPermGroup(A)' - gap.eval(s2) -@@ -279,32 +326,90 @@ - return [[words[l3[2*i]-1],LL[i]] for i in range(len(LL))] -  -  --def AbelianGroup(n, invfac=None, names="f"): -+def _normalize(n, gens_orders=None, names="f"): -+ """ -+ Helper function for :func:AbelianGroup. Beat some sense into the -+ arguments. -+ -+ This function is also used by some descendents of -+ :class:AbelianGroup_class. -+ -+ INPUT: -+ -+ See :func:AbelianGroup -+ -+ OUTPUT: -+ -+ Unique data for defining a :class:AbelianGroup_class. Raises an -+ exception if the input is invalid. -+ -+ EXAMPLES:: -+ -+ sage: from sage.groups.abelian_gps.abelian_group import _normalize -+ sage: _normalize(5, [2,1,0], names='abc') -+ ((0, 0, 2, 1, 0), 'abc') -+ sage: _normalize(5, (2.0, 1.0, 0/1), names=list('abc')) -+ ((0, 0, 2, 1, 0), ('a', 'b', 'c')) -+ sage: _normalize([0,2,1,0], names='a') -+ ((0, 2, 1, 0), 'a') -+ -+ TESTS:: -+ -+ sage: _normalize(5, (2.0, 1.5, 0/1), names=list('abc')) -+ Traceback (most recent call last): -+ ... -+ TypeError: Attempt to coerce non-integral RealNumber to Integer -+ sage: _normalize('1', '[2]', names='a') -+ Traceback (most recent call last): -+ ... -+ TypeError: unable to convert x (=[) to an integer -+ sage: _normalize(3, 'str', names='a') -+ Traceback (most recent call last): -+ ... -+ TypeError: unable to convert x (=s) to an integer -+ """ -+ if gens_orders is None: -+ if isinstance(n, (list, tuple)): -+ gens_orders = n -+ n = len(n) -+ else: -+ gens_orders = [] -+ n = ZZ(n) -+ if len(gens_orders) < n: -+ gens_orders = [0] * (n - len(gens_orders)) + list(gens_orders) -+ gens_orders = tuple(ZZ(i) for i in gens_orders) -+ if len(gens_orders) > n: -+ raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')') -+ if isinstance(names, list): -+ names = tuple(names) -+ return (gens_orders, names) -+ -+def AbelianGroup(n, gens_orders=None, names="f"): - r""" - Create the multiplicative abelian group in n generators -- with given invariants (which need not be prime powers). -+ with given orders of generators (which need not be prime powers). -  - INPUT: -  -+ - n -- integer (optional). If not specified, will be derived -+ from gens_orders. -  -- - n - integer -+ - gens_orders -- a list of non-negative integers in the form -+ [a_0, a_1, \dots, a_{n-1}], typically written in increasing -+ order. This list is padded with zeros if it has length less -+ than n. The orders of the commuting generators, with 0 -+ denoting an infinite cyclic factor. -  -- - invfac - (the"invariant factors") a list of -- non-negative integers in the form [a0, a1,...,a(n-1)], typically -- written in increasing order. This list is padded with zeros if it -- has length less than n. -+ - names -- (optional) names of generators -  -- - names - (optional) names of generators -+ Alternatively, you can also give input in the form -+ AbelianGroup(gens_orders, names="f"), where the names keyword -+ argument must be explicitly named. -  -- Alternatively, you can also give input in the following form: --  -- AbelianGroup(invfac, names="f"), --  -- where names must be explicitly named. --  --  -- OUTPUT: Abelian group with generators and invariant type. The -- default name for generator A.i is fi, as in GAP. -+ OUTPUT: -+ -+ Abelian group with generators and invariant type. The default name -+ for generator A.i is fi, as in GAP. -  - EXAMPLES:: -  -@@ -317,52 +422,41 @@ - sage: d * b**2 * c**3  - b^2*c^3*d - sage: F = AbelianGroup(3,[2]*3); F -- Multiplicative Abelian Group isomorphic to C2 x C2 x C2 -+ Multiplicative Abelian group isomorphic to C2 x C2 x C2 - sage: H = AbelianGroup([2,3], names="xy"); H -- Multiplicative Abelian Group isomorphic to C2 x C3 -+ Multiplicative Abelian group isomorphic to C2 x C3 - sage: AbelianGroup(5) -- Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z -+ Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z - sage: AbelianGroup(5).order() - +Infinity -  -- Notice how 0's are padded on. -+ Notice that 0's are prepended if necessary:: -  -- :: --  -- sage: AbelianGroup(5, [2,3,4]) -- Multiplicative Abelian Group isomorphic to Z x Z x C2 x C3 x C4 --  -- The invariant list can't be longer than the number of generators. --  -- :: -+ sage: G = AbelianGroup(5, [2,3,4]); G -+ Multiplicative Abelian group isomorphic to Z x Z x C2 x C3 x C4 -+ sage: G.gens_orders() -+ (0, 0, 2, 3, 4) -+ -+ The invariant list must not be longer than the number of generators:: -  - sage: AbelianGroup(2, [2,3,4]) - Traceback (most recent call last): - ... -- ValueError: invfac (=[2, 3, 4]) must have length n (=2) -+ ValueError: gens_orders (=(2, 3, 4)) must have length n (=2) - """ -- if invfac is None: -- if isinstance(n, (list, tuple)): -- invfac = n -- n = len(n) -- else: -- invfac = [] -- if len(invfac) < n: -- invfac = [0] * (n - len(invfac)) + invfac  -- elif len(invfac) > n: -- raise ValueError, "invfac (=%s) must have length n (=%s)"%(invfac, n) -- M = AbelianGroup_class(n, invfac, names) -+ gens_orders, names = _normalize(n, gens_orders, names) -+ M = AbelianGroup_class(gens_orders, names) - return M -  - def is_AbelianGroup(x): - """ -- Return True if x is an abelian group. -+ Return True if x is an Abelian group. -  - EXAMPLES:: -  - sage: from sage.groups.abelian_gps.abelian_group import is_AbelianGroup - sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F -- Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9 -+ Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 - sage: is_AbelianGroup(F) - True - sage: is_AbelianGroup(AbelianGroup(7, [3]*7)) -@@ -371,142 +465,165 @@ - return isinstance(x, AbelianGroup_class) -  -  --class AbelianGroup_class(group.AbelianGroup): -+class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase): - """ -- Abelian group on n generators. The invariant factors -- [a_1,a_2,...,a_k] need not be prime powers. -- divisors will be). -+ The parent for Abelian groups with chosen generator orders. -+ -+ .. warning:: -+ -+ You should use :func:AbelianGroup to construct Abelian -+ groups and not instantiate this class directly. -+  -+ INPUT: -+ -+ - generator_orders -- list of integers. The orders of the -+ (commuting) generators. Zero denotes an infinite cyclic -+ generator. -+ -+ - names -- names of the group generators (optional). -  - EXAMPLES:: -  -+ sage: Z2xZ3 = AbelianGroup([2,3]) -+ sage: Z6 = AbelianGroup([6]) -+ sage: Z2xZ3 is Z2xZ3, Z6 is Z6 -+ (True, True) -+ sage: Z2xZ3 is Z6 -+ False -+ sage: Z2xZ3 == Z6 -+ True -+ - sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F -- Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9 -+ Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9 - sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F -- Multiplicative Abelian Group isomorphic to C2 x C4 x C12 x C24 x C120 -+ Multiplicative Abelian group isomorphic to C2 x C4 x C12 x C24 x C120 - sage: F.elementary_divisors() -- [2, 4, 12, 24, 120] -- -- The entry 1 in the list of invariants is ignored:: -- -- sage: F = AbelianGroup(3,[1,2,3],names='a') -- sage: F.invariants() -- [2, 3] -- sage: F.gens() -- (a0, a1) -- sage: F.ngens() -- 2 -- sage: (F.0).order() -- 2 -- sage: (F.1).order() -- 3 -- sage: AbelianGroup(1, [1], names='e') -- Multiplicative Abelian Group isomorphic to C1 -- sage: AbelianGroup(1, [1], names='e').gens() -- (e,) -- sage: AbelianGroup(1, [1], names='e').list() -- [1] -- sage: AbelianGroup(3, [2, 1, 2], names=list('abc')).list() -- [1, b, a, a*b] -+ (2, 4, 12, 24, 120) -  - sage: F.category() - Category of groups -  -+ TESTS:: -+ -+ sage: AbelianGroup([]).gens_orders() -+ () -+ sage: AbelianGroup([1]).gens_orders() -+ (1,) -+ sage: AbelianGroup([1,1]).gens_orders() -+ (1, 1) -+ sage: AbelianGroup(0).gens_orders() -+ () - """ -- def __init__(self, n, invfac, names="f"): -- #invfac.sort() -- n = Integer(n) -- # if necessary, remove 1 from invfac first -- if n != 1: -- while True: -- try: -- i = invfac.index(1) -- except ValueError: -- break -- else: -- del invfac[i] -- n = n-1 -+ Element = AbelianGroupElement -  -- if n < 0: -- raise ValueError, "n (=%s) must be nonnegative."%n -+ def __init__(self, generator_orders, names): -+ """ -+ The Python constructor -  -- self.__invariants = invfac -+ TESTS:: -  -- # *now* define ngens -- self.__ngens = len(self.__invariants) -- self._assign_names(names[:n]) -- from sage.categories.groups import Groups -- group.Group.__init__(self, category = Groups()) # should be CommutativeGroups() -+ sage: G = AbelianGroup([0,5,0,7],names = list("abcd")); G -+ Multiplicative Abelian group isomorphic to Z x C5 x Z x C7 -+ sage: TestSuite(G).run() -+ """ -+ assert isinstance(names, (basestring, tuple)) -+ assert isinstance(generator_orders, tuple) -+ assert all(isinstance(order,Integer) for order in generator_orders) -+ self._gens_orders = generator_orders -+ n = ZZ(len(generator_orders)) -+ names = self.normalize_names(n, names) -+ self._assign_names(names) -+ AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups() -  -- def __call__(self, x): -+ def is_isomorphic(left, right): - """ -- Create an element of this abelian group from x. -+ Check whether left and right are isomorphic -  -+ INPUT: -+ -+ - right -- anything. -+ -+ OUTPUT: -+ -+ Boolean. Whether left and right are isomorphic as abelian groups. -+ - EXAMPLES:: --  -- sage: F = AbelianGroup(10, [2]*10) -- sage: F(F.2) -- f2 -- sage: F(1) -- 1 -- """ -- if isinstance(x, AbelianGroupElement) and x.parent() is self:  -- return x -- return AbelianGroupElement(self, x) --  -- def __contains__(self, x): -- """ -- Return True if x is an element of this abelian group. --  -- EXAMPLES:: --  -- sage: F = AbelianGroup(10,[2]*10) -- sage: F.2 * F.3 in F -- True -- """ -- return isinstance(x, AbelianGroupElement) and x.parent() == self -  -- def __eq__(self, right): -- """ -- Compare self and right. --  -- The ordering is the ordering induced by that on the invariant -- factors lists. --  -- EXAMPLES:: --  - sage: G1 = AbelianGroup([2,3,4,5]) - sage: G2 = AbelianGroup([2,3,4,5,1]) -- sage: G1 < G2 -- False -- sage: G1 > G2 -- False -- sage: G1 == G2 -+ sage: G1.is_isomorphic(G2) -+ True -+ sage: G1 == G2 # syntactic sugar - True - """ - if not is_AbelianGroup(right): - return False -- if set(self.variable_names()) != set(right.variable_names()): -- return False -- svars = list(self.variable_names()) -- sinvs = self.invariants() -- rvars = list(right.variable_names()) -- rinvs = right.invariants() -- for i in xrange(len(svars)): -- if rinvs[rvars.index(svars[i])] != sinvs[i]: -+ return left.elementary_divisors() == right.elementary_divisors() -+ -+ __eq__ = is_isomorphic -+ -+ def __ne__(left, right): -+ """ -+ Check whether left and right are not isomorphic -+ -+ OUTPUT: -+ -+ Boolean. -+ -+ EXAMPLES:: -+ -+ sage: G1 = AbelianGroup([2,3,4,5]) -+ sage: G2 = AbelianGroup([2,3,4,5,1]) -+ sage: G1 != G2 -+ False -+ sage: G1.__ne__(G2) -+ False -+ """ -+ return not left.is_isomorphic(right) -+ -+ def is_subgroup(left, right): -+ """ -+ Test whether left is a subgroup of right. -+ -+ EXAMPLES:: -+ -+ sage: G = AbelianGroup([2,3,4,5]) -+ sage: G.is_subgroup(G) -+ True -+ -+ sage: H = G.subgroup([G.1]) -+ sage: H.is_subgroup(G) -+ True -+ -+ sage: G.<a, b> = AbelianGroup(2) -+ sage: H.<c> = AbelianGroup(1) -+ sage: H < G -+ False -+ """ -+ for l in left.gens(): -+ if l not in right: - return False - return True -+ -+ __le__ = is_subgroup -+ -+ def __ge__(left, right): -+ """ -+ Test whether right is a subgroup of left -+ -+ EXAMPLE:: -+ -+ sage: G.<a, b> = AbelianGroup(2) -+ sage: H.<c> = AbelianGroup(1) -+ sage: G >= H -+ False -+ """ -+ return right.__le__(left) -  -- def __ne__(self, right): -- return not self == right --  -- def __ge__(self, right): -- for a in right.gens(): -- if a not in self: -- return False -- return True --  -- def __lt__(self, right): -+ def __lt__(left, right): - """ -+ Test whether left is a strict subgroup of right -+ - EXAMPLE:: -  - sage: G.<a, b> = AbelianGroup(2) -@@ -514,16 +631,35 @@ - sage: H < G - False - """ -- return self <= right and self != right -+ return left <= right and left != right -  -- def __gt__(self, right): -- return self >= right and self != right -+ def __gt__(left, right): -+ """ -+ Test whether right is a strict subgroup of left -+ -+ EXAMPLE:: -+ -+ sage: G.<a, b> = AbelianGroup(2) -+ sage: H.<c> = AbelianGroup(1) -+ sage: G > H -+ False -+ """ -+ return left >= right and left != right -  -- def __le__(self, right): -- for a in self.gens(): -- if a not in right: -- return False -- return True -+ def is_trivial(self): -+ """ -+ Return whether the group is trivial -+ -+ A group is trivial if it has precisely one element. -+ -+ EXAMPLES:: -+ -+ sage: AbelianGroup([2, 3]).is_trivial() -+ False -+ sage: AbelianGroup([1, 1]).is_trivial() -+ True -+ """ -+ return self.elementary_divisors() == () -  - def __nonzero__(self): - """ -@@ -536,18 +672,62 @@ - True - sage: bool(AbelianGroup([])) - False -+ sage: bool(AbelianGroup([1,1,1])) -+ False - """ -- return len(self.invariants()) != 0 -+ return not self.is_trivial() -  -- def dual_group(self): -+ @cached_method -+ def dual_group(self, names="X", base_ring=None): - """ - Returns the dual group. -+ -+ INPUT: -+ -+ - names -- string or list of strings. The generator names -+ for the dual group. -+ -+ - base_ring -- the base ring. If None (default), then -+ a suitable cyclotomic field is picked automatically. -  -- EXAMPLES: -+ OUTPUT: -+ -+ The -+ :class:~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class -+ <dual abelian group> -+ -+ EXAMPLES:: -+ -+ sage: G = AbelianGroup([2]) -+ sage: G.dual_group() -+ Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1 -+ sage: G.dual_group().gens() -+ (X,) -+ sage: G.dual_group(names='Z').gens() -+ (Z,) -+ -+ sage: G.dual_group(base_ring=QQ) -+ Dual of Abelian Group isomorphic to Z/2Z over Rational Field -+ -+ -+ TESTS:: -+ -+ sage: H = AbelianGroup(1) -+ sage: H.dual_group() -+ Traceback (most recent call last): -+ ... -+ ValueError: the group must be finite - """ -- from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup -- return DualAbelianGroup(self) -+ from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup_class -+ if not self.is_finite(): -+ raise ValueError('the group must be finite') -+ if base_ring is None: -+ from sage.rings.number_field.number_field import CyclotomicField -+ from sage.rings.arith import LCM -+ base_ring = CyclotomicField(LCM(self.gens_orders())) -+ return DualAbelianGroup_class(self, names=names, base_ring=base_ring) -  -+ @cached_method - def elementary_divisors(self): - r""" - This returns the elementary divisors of the group, using Pari. -@@ -566,34 +746,39 @@ - on these ""smaller invariants"" to compute d_{i-1}, and so on. - (Thanks to Robert Miller for communicating this algorithm.) -  -+ OUTPUT: -+ -+ A tuple of integers. -+ - EXAMPLES:: -  - sage: G = AbelianGroup(2,[2,3]) - sage: G.elementary_divisors() -- [6] -+ (6,) - sage: G = AbelianGroup(1, [6]) - sage: G.elementary_divisors() -- [6] -+ (6,) - sage: G = AbelianGroup(2,[2,6]) - sage: G -- Multiplicative Abelian Group isomorphic to C2 x C6 -- sage: G.invariants() -- [2, 6] -+ Multiplicative Abelian group isomorphic to C2 x C6 -+ sage: G.gens_orders() -+ (2, 6) - sage: G.elementary_divisors() -- [2, 6] -+ (2, 6) - sage: J = AbelianGroup([1,3,5,12]) - sage: J.elementary_divisors() -- [3, 60] -+ (3, 60) - sage: G = AbelianGroup(2,[0,6]) - sage: G.elementary_divisors() -- [6, 0] -+ (6, 0) - sage: AbelianGroup([3,4,5]).elementary_divisors() -- [60] -+ (60,) - """ - from sage.matrix.constructor import diagonal_matrix -- ed = diagonal_matrix(ZZ, self.invariants()).elementary_divisors() -- return [d for d in ed if d!=1] -+ ed = diagonal_matrix(ZZ, self.gens_orders()).elementary_divisors() -+ return tuple(d for d in ed if d!=1) -  -+ @cached_method - def exponent(self): - """ - Return the exponent of this abelian group. -@@ -601,20 +786,15 @@ - EXAMPLES:: -  - sage: G = AbelianGroup([2,3,7]); G -- Multiplicative Abelian Group isomorphic to C2 x C3 x C7 -+ Multiplicative Abelian group isomorphic to C2 x C3 x C7 - sage: G.exponent() - 42 - sage: G = AbelianGroup([2,4,6]); G -- Multiplicative Abelian Group isomorphic to C2 x C4 x C6 -+ Multiplicative Abelian group isomorphic to C2 x C4 x C6 - sage: G.exponent() - 12 - """ -- try: -- return self.__exponent -- except AttributeError: -- self.__exponent = e = lcm(self.invariants()) -- return e --  -+ return lcm(self.gens_orders()) -  - def identity(self): - r""" -@@ -633,9 +813,25 @@ - f0 - """ - return self(1) -- -  - def _group_notation(self, eldv): -+ """ -+ Return abstract group notation for generator orders eldv -+ -+ INPUT: -+ -+ - eldv -- iterable of integers. -+ -+ OUTPUT: -+ -+ String. -+ -+ EXAMPLES:: -+ -+ sage: G = AbelianGroup([2,2]) -+ sage: G._group_notation([0,1,2,3]) -+ 'Z x C1 x C2 x C3' -+ """ - v = [] - for x in eldv: - if x: -@@ -652,9 +848,9 @@ -  - sage: F = AbelianGroup(10, [2]*10) - sage: F._latex_() -- '$\\mathrm{AbelianGroup}( 10, [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] )$' -+ '$\\mathrm{AbelianGroup}( 10, (2, 2, 2, 2, 2, 2, 2, 2, 2, 2) )$' - """ -- s = "$\mathrm{AbelianGroup}( %s, %s )$"%(len(self.invariants()), self.invariants()) -+ s = "$\mathrm{AbelianGroup}( %s, %s )\$"%(self.ngens(), self.gens_orders())
-         return s
-
-     def _gap_init_(self):
-@@ -669,12 +865,10 @@
-             sage: gap(G)
-             Group( [ f1, f2, f3 ] )
-
--        Only works for finite groups.
--
--        ::
-+        Only works for finite groups::
-
-             sage: G = AbelianGroup(3,[0,3,4],names="abc"); G
--            Multiplicative Abelian Group isomorphic to Z x C3 x C4
-+            Multiplicative Abelian group isomorphic to Z x C3 x C4
-             sage: G._gap_init_()
-             Traceback (most recent call last):
-             ...
-@@ -683,11 +877,10 @@
-         # TODO: Use the package polycyclic has AbelianPcpGroup, which can handle
-         # the infinite case but it is a GAP package not GPL'd.
-         # Use this when the group is infinite...
--        if (False and prod(self.invariants())==0):   # if False for now...
--            return 'AbelianPcpGroup(%s)'%self.invariants()
-+        # return 'AbelianPcpGroup(%s)'%list(self.invariants())
-         if not self.is_finite():
--            raise TypeError, "abelian groups in GAP are finite, but self is infinite"
--        return 'AbelianGroup(%s)'%self.invariants()
-+            raise TypeError('abelian groups in GAP are finite, but self is infinite')
-+        return 'AbelianGroup(%s)'%list(self.gens_orders())
-
-     def gen(self, i=0):
-         """
-@@ -700,36 +893,129 @@
-             a0
-             sage: F.2
-             a2
--            sage: F.invariants()
--            [0, 0, 0, 0, 0]
-+            sage: F.gens_orders()
-+            (0, 0, 0, 0, 0)
-+
-+            sage: G = AbelianGroup([2,1,3])
-+            sage: G.gens()
-+            (f0, 1, f2)
-         """
--        n = self.__ngens
-+        n = self.ngens()
-         if i < 0 or i >= n:
-             raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)
--        x = [0]*int(n)
--        x[int(i)] = 1
--        return AbelianGroupElement(self, x)
-+        x = [0]*n
-+        if self._gens_orders[i] != 1:
-+            x[i] = 1
-+        return self.element_class(x, self)
-+
-+    def gens(self):
-+        """
-+        Return the generators of the group.
-+
-+        OUTPUT:
-+
-+        A tuple of group elements. The generators according to the
-+        chosen :meth:gens_orders.
-+
-+        EXAMPLES::
-+
-+            sage: F = AbelianGroup(5,[3,2],names='abcde')
-+            sage: F.gens()
-+            (a, b, c, d, e)
-+            sage: [ g.order() for g in F.gens() ]
-+            [+Infinity, +Infinity, +Infinity, 3, 2]
-+        """
-+        return tuple( self.gen(i) for i in range(self.ngens()) )
-+
-+    def gens_orders(self):
-+        """
-+        Return the orders of the cyclic factors that this group has
-+        been defined with.
-+
-+        Use :meth:elementary_divisors if you are looking for an
-+        invariant of the group.
-+
-+        OUTPUT:
-+
-+        A tuple of integers.
-+
-+        EXAMPLES::
-+
-+            sage: Z2xZ3 = AbelianGroup([2,3])
-+            sage: Z2xZ3.gens_orders()
-+            (2, 3)
-+            sage: Z2xZ3.elementary_divisors()
-+            (6,)
-+
-+            sage: Z6 = AbelianGroup([6])
-+            sage: Z6.gens_orders()
-+            (6,)
-+            sage: Z6.elementary_divisors()
-+            (6,)
-+
-+            sage: Z2xZ3.is_isomorphic(Z6)
-+            True
-+            sage: Z2xZ3 is Z6
-+            False
-+
-+        TESTS::
-+
-+            sage: F = AbelianGroup(3, [2], names='abc')
-+            sage: map(type, F.gens_orders())
-+            [<type 'sage.rings.integer.Integer'>,
-+             <type 'sage.rings.integer.Integer'>,
-+             <type 'sage.rings.integer.Integer'>]
-+        """
-+        return self._gens_orders
-
-     def invariants(self):
-         """
--        Return a copy of the list of invariants of this group.
--
--        It is safe to modify the returned list.
-+        Return the orders of the cyclic factors that this group has
-+        been defined with.
-+
-+        For historical reasons this has been called invariants in
-+        Sage, even though they are not necessarily the invariant
-+        factors of the group. Use :meth:gens_orders instead::
-+
-+            sage: J = AbelianGroup([2,0,3,2,4]);  J
-+            Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
-+            sage: J.invariants()    # deprecated
-+            (2, 0, 3, 2, 4)
-+            sage: J.gens_orders()   # use this instead
-+            (2, 0, 3, 2, 4)
-+            sage: for i in range(J.ngens()):
-+            ...       print i, J.gen(i), J.gen(i).order()     # or use this
-+            0 f0 2
-+            1 f1 +Infinity
-+            2 f2 3
-+            3 f3 2
-+            4 f4 4
-+
-+        Use :meth:elementary_divisors if you are looking for an
-+        invariant of the group.
-+
-+        OUTPUT:
-+
-+        A tuple of integers. Zero means infinite cyclic factor.
-
-         EXAMPLES::
-
-             sage: J = AbelianGroup([2,3])
-             sage: J.invariants()
--            [2, 3]
--            sage: v = J.invariants(); v
--            [2, 3]
--            sage: v[0] = 5
--            sage: J.invariants()
--            [2, 3]
--            sage: J.invariants() is J.invariants()
--            False
-+            (2, 3)
-+            sage: J.elementary_divisors()
-+            (6,)
-+
-+        TESTS::
-+
-+            sage: F = AbelianGroup(3, [2], names='abc')
-+            sage: map(type, F.gens_orders())
-+            [<type 'sage.rings.integer.Integer'>,
-+             <type 'sage.rings.integer.Integer'>,
-+             <type 'sage.rings.integer.Integer'>]
-         """
--        return list(self.__invariants)
-+        # TODO: deprecate
-+        return self.gens_orders()
-
-     def is_cyclic(self):
-         """
-@@ -738,25 +1024,25 @@
-         EXAMPLES::
-
-             sage: J = AbelianGroup([2,3])
--            sage: J.invariants()
--            [2, 3]
-+            sage: J.gens_orders()
-+            (2, 3)
-             sage: J.elementary_divisors()
--            [6]
-+            (6,)
-             sage: J.is_cyclic()
-             True
-             sage: G = AbelianGroup([6])
--            sage: G.invariants()
--            [6]
-+            sage: G.gens_orders()
-+            (6,)
-             sage: G.is_cyclic()
-             True
-             sage: H = AbelianGroup([2,2])
--            sage: H.invariants()
--            [2, 2]
-+            sage: H.gens_orders()
-+            (2, 2)
-             sage: H.is_cyclic()
-             False
-             sage: H = AbelianGroup([2,4])
-             sage: H.elementary_divisors()
--            [2, 4]
-+            (2, 4)
-             sage: H.is_cyclic()
-             False
-             sage: H.permutation_group().is_cyclic()
-@@ -765,7 +1051,7 @@
-             sage: T.is_cyclic()
-             True
-             sage: T = AbelianGroup(1,[0]); T
--            Multiplicative Abelian Group isomorphic to Z
-+            Multiplicative Abelian group isomorphic to Z
-             sage: T.is_cyclic()
-             True
-             sage: B = AbelianGroup([3,4,5])
-@@ -774,6 +1060,7 @@
-         """
-         return len(self.elementary_divisors()) <= 1
-
-+    @cached_method
-     def ngens(self):
-         """
-         The number of free generators of the abelian group.
-@@ -784,8 +1071,9 @@
-             sage: F.ngens()
-             10000
-         """
--        return self.__ngens
-+        return len(self.gens_orders())
-
-+    @cached_method
-     def order(self):
-         """
-         Return the order of this group.
-@@ -799,18 +1087,12 @@
-             sage: G.order()
-             +Infinity
-         """
--        try:
--            return self.__len
--        except AttributeError:
--            from sage.rings.all import infinity, Integer
--            if len(self.invariants()) < self.ngens():
--                self.__len = infinity
--            else:
--                self.__len = Integer(prod(self.invariants()))
--                if self.__len == 0:
--                    self.__len = infinity
--        return self.__len
--
-+        from sage.rings.all import infinity
-+        length = prod(self.gens_orders())
-+        if length == 0:
-+            return infinity
-+        return length
-+
-     def permutation_group(self):
-         r"""
-         Return the permutation group isomorphic to this abelian group.
-@@ -822,7 +1104,7 @@
-         EXAMPLES::
-
-             sage: G = AbelianGroup(2,[2,3]); G
--            Multiplicative Abelian Group isomorphic to C2 x C3
-+            Multiplicative Abelian group isomorphic to C2 x C3
-             sage: G.permutation_group()
-             Permutation Group with generators [(3,4,5), (1,2)]
-         """
-@@ -830,7 +1112,6 @@
-         s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()
-         return PermutationGroup(gap_group=s)
-
--
-     def is_commutative(self):
-         """
-         Return True since this group is commutative.
-@@ -847,32 +1128,38 @@
-
-     def random_element(self):
-         """
--        Return a random element of this group. (Renamed random to
--        random_element.)
-+        Return a random element of this group.
-
-         EXAMPLES::
-
-             sage: G = AbelianGroup([2,3,9])
-             sage: G.random_element()
--            f0*f1^2*f2
-+            f1^2
-         """
-         from sage.misc.prandom import randint
--        if self.order() is infinity:
--            NotImplementedError, "The group must be finite"
--        gens = self.gens()
--        g = gens[0]**0
--        for i in range(len(gens)):
--            g = g*gens[i]**(randint(1,gens[i].order()))
--        return g
--
-+        result = self.one()
-+        for g in self.gens():
-+            order = g.order()
-+            if order not in ZZ:
-+                order = 42  # infinite order; randomly chosen maximum
-+            result *= g**(randint(0,order))
-+        return result
-
-     def _repr_(self):
--        eldv = self.invariants()
-+        """
-+        Return a string representation of self.
-+
-+        EXAMPLES::
-+
-+            sage: G = AbelianGroup([2,3,9])
-+            sage: G._repr_()
-+            'Multiplicative Abelian group isomorphic to C2 x C3 x C9'
-+       """
-+        eldv = self.gens_orders()
-         if len(eldv) == 0:
--            return "Trivial Abelian Group"
-+            return "Trivial Abelian group"
-         g = self._group_notation(eldv)
--        return "Multiplicative Abelian Group isomorphic to " + g
--
-+        return "Multiplicative Abelian group isomorphic to " + g
-
-     def subgroup(self, gensH, names="f"):
-         """
-@@ -881,74 +1168,59 @@
-
-          INPUT:
-
--
--         -  gensH - list of elements which are products of
--            the generators of the ambient abelian group G = self
--
-+         - gensH -- list of elements which are products of the
-+            generators of the ambient abelian group G = self
-
-          EXAMPLES::
-
-              sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G
--             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
-+             Multiplicative Abelian group isomorphic to C2 x C3 x C4
-              sage: H = G.subgroup([a*b,a]); H
--             Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
--             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
--             generated by [a*b, a]
-+             Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a}
-              sage: H < G
-              True
-              sage: F = G.subgroup([a,b^2])
-              sage: F
--             Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
--             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
--             generated by [a, b^2]
-+             Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
-              sage: F.gens()
--             [a, b^2]
-+             (a, b^2)
-              sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
-              sage: a,b,c,d,e = F.gens()
-              sage: F.subgroup([a,b])
--             Multiplicative Abelian Group isomorphic to Z x Z, which is
--             the subgroup of Multiplicative Abelian Group isomorphic to
--             Z x Z x C30 x C64 x C729 generated by [a, b]
-+             Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b}
-              sage: F.subgroup([c,e])
--             Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
--             C729, which is the subgroup of Multiplicative Abelian
--             Group isomorphic to Z x Z x C30 x C64 x C729 generated by
--             [c, e]
-+             Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729 generated by {c, e}
-          """
--        if not isinstance(gensH, (list, tuple)):
--            raise TypeError, "gensH = (%s) must be a list or tuple"%(gensH)
--
-         G = self
--        for i in range(len(gensH)):
--            if not(gensH[i] in G):
--                raise TypeError, "Subgroup generators must belong to the given group."
-+        gensH = tuple(gensH)
-+        if isinstance(names, list):
-+            names = tuple(names)
-+        for h in gensH:
-+            if h not in G:
-+                raise TypeError('Subgroup generators must belong to the given group.')
-         return AbelianGroup_subgroup(self, gensH, names)
-
-+    @cached_method
-     def list(self):
-         """
--        Return list of all elements of this group.
-+        Return tuple of all elements of this group.
-
-         EXAMPLES::
-
-             sage: G = AbelianGroup([2,3], names = "ab")
-             sage: G.list()
--            [1, b, b^2, a, a*b, a*b^2]
-+            (1, b, b^2, a, a*b, a*b^2)
-
-         ::
-
-             sage: G = AbelianGroup([]); G
--            Trivial Abelian Group
-+            Trivial Abelian group
-             sage: G.list()
--            [1]
-+            (1,)
-         """
--        try:
--            return list(self.__list)
--        except AttributeError:
--            pass
-         if not(self.is_finite()):
-            raise NotImplementedError, "Group must be finite"
--        self.__list = list(self.__iter__())
--        return list(self.__list)
-+        return tuple(self.__iter__())
-
-     def __iter__(self):
-         """
-@@ -973,14 +1245,13 @@
-             [1]
-             sage: G = AbelianGroup([])
-             sage: G.list()
--            [1]
-+            (1,)
-             sage: list(G)
-             [1]
-         """
--        invs = self.invariants()
-+        invs = self.gens_orders()
-         for t in mrange(invs):
--            yield AbelianGroupElement(self, t)
--
-+            yield self(t)
-
-     def subgroups(self, check=False):
-         r"""
-@@ -1010,35 +1281,28 @@
-         EXAMPLES::
-
-             sage: AbelianGroup([2,3]).subgroups()
--            [Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C2 x C3
--            generated by [f0*f1^2],
--             Multiplicative Abelian Group isomorphic to C2, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C2 x C3
--            generated by [f0],
--             Multiplicative Abelian Group isomorphic to C3, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C2 x C3
--            generated by [f1],
--             Trivial Abelian Group, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C2 x C3
--            generated by []]
--
-+            [Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {f0*f1^2},
-+             Multiplicative Abelian subgroup isomorphic to C2 generated by {f0},
-+             Multiplicative Abelian subgroup isomorphic to C3 generated by {f1},
-+             Trivial Abelian subgroup]
-             sage: len(AbelianGroup([2,4,8]).subgroups())
-             81
-
-+        TESTS::
-+
-+            sage: AbelianGroup([]).subgroups()
-+            [Trivial Abelian group]
-         """
-         if not self.is_finite(): raise ValueError, "Group must be finite"
-         from sage.misc.misc import verbose
-
--        v = self.invariants()
--
--
--        if len(v) <= 1:
--            if v == [] or v[0] == 1:
--                return [self]
--            else:
--                return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1]] + [self.subgroup([])]
-+        if self.is_trivial():
-+            return [self]
-+        if self.ngens() == 1:
-+            n = self.gen(0).order()
-+            return [ self.subgroup([self.gen(0)**i]) for i in divisors(n) ]
-
-+        v = self.gens_orders()
-         A = AbelianGroup(v[:-1])
-         x = v[-1]
-
-@@ -1046,8 +1310,8 @@
-
-         subgps = []
-         for G in Wsubs:
--            verbose("G = subgp generated by %s" % G.gens())
--            verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work
-+            verbose("G = subgp generated by %s" % list(G.gens()))
-+            verbose("invariants are:", [t.order() for t in G.gens()])
-             for H in divisors(x):
-                 # H = the subgroup of *index* H.
-                 its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))]
-@@ -1085,13 +1349,11 @@
-
-             sage: G = AbelianGroup([4,4])
-             sage: G.subgroup( [ G([1,0]), G([1,2]) ])
--            Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C4 x C4
--            generated by [f0, f0*f1^2]
-+            Multiplicative Abelian subgroup isomorphic to C2 x C4
-+            generated by {f0, f0*f1^2}
-             sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])
--            Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C4 x C4
--            generated by [f1^2, f0]
-+            Multiplicative Abelian subgroup isomorphic to C2 x C4
-+            generated by {f1^2, f0}
-         """
-         from sage.matrix.constructor import matrix
-         d = self.ngens()
-@@ -1102,12 +1364,13 @@
-             # can't happen?
-             print "Vectors not LI: ", elts
-             raise e
--        rel_lattice = X.span([X.gen(i) * self.invariants()[i] for i in xrange(d)])
-+        rel_lattice = X.span([X.gen(i) * self.gens_orders()[i] for i in xrange(d)])
-         isect = elt_lattice.intersection(rel_lattice)
-         mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)
-         D,U,V = mat.smith_form()
-         new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i,i]) for i in xrange(U.ncols())]
--        return self.subgroup([self([x[0][i] % self.invariants()[i] for i in xrange(d)]) for x in new_basis if x[1] != 1])
-+        return self.subgroup([self([x[0][i] % self.gens_orders()[i]
-+                                    for i in xrange(d)]) for x in new_basis if x[1] != 1])
-
- class AbelianGroup_subgroup(AbelianGroup_class):
-     """
-@@ -1126,61 +1389,21 @@
-             sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
-             sage: a,b,c,d,e = F.gens()
-             sage: F.subgroup([a^3,b])
--            Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
--            generated by [a^3, b]
--
--        ::
--
-+            Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a^3, b}
-             sage: F.subgroup([c])
--            Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
--            generated by [c]
--
--        ::
--
--            sage: F.subgroup([a,c])
--            Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
--            Z, which is the subgroup of Multiplicative Abelian Group
--            isomorphic to Z x Z x C30 x C64 x C729 generated by [a, c]
--
--        ::
--
--            sage: F.subgroup([a,b*c])
--            Multiplicative Abelian Group isomorphic to Z x Z, which is
--            the subgroup of Multiplicative Abelian Group isomorphic to
--            Z x Z x C30 x C64 x C729 generated by [a, b*c]
--
--        ::
--
--            sage: F.subgroup([b*c,d])
--            Multiplicative Abelian Group isomorphic to C64 x Z, which
--            is the subgroup of Multiplicative Abelian Group isomorphic
--            to Z x Z x C30 x C64 x C729 generated by [b*c, d]
--
--        ::
--
--            sage: F.subgroup([a*b,c^6,d],names = list("xyz"))
--            Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
--            which is the subgroup of Multiplicative Abelian Group
--            isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
--            c^6, d]
--
--        ::
--
-+            Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 generated by {c}
-+            sage: F.subgroup([a, c])
-+            Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x Z generated by {a, c}
-+            sage: F.subgroup([a, b*c])
-+            Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b*c}
-+            sage: F.subgroup([b*c, d])
-+            Multiplicative Abelian subgroup isomorphic to C64 x Z generated by {b*c, d}
-+            sage: F.subgroup([a*b, c^6, d],names=list("xyz"))
-+            Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}
-             sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H
--            Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
--            which is the subgroup of Multiplicative Abelian Group
--            isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
--            c^6, d]
--
--        ::
--
--            sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G
--            Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
--            which is the subgroup of Multiplicative Abelian Group
--            isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
--            c^6, d]
-+            Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}
-+            sage: G = F.subgroup([a*b, c^6, d],names = list("xyz")); G
-+            Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}
-             sage: x,y,z = G.gens()
-             sage: x.order()
-             +Infinity
-@@ -1191,28 +1414,20 @@
-             sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde")
-             sage: a,b,c,d,e = A.gens()
-             sage: A.subgroup([a,b])
--            Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
--            generated by [a, b]
-+            Multiplicative Abelian subgroup isomorphic to C3 x C5 generated by {a, b}
-             sage: A.subgroup([a,b,c,d^2,e])
--            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
--            generated by [a, b, c, d^2, e]
--            sage: A.subgroup([a,b,c,d^2,e^2])
--            Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
--            generated by [a, b, c, d^2, e^2]
--            sage: B = A.subgroup([a^3,b,c,d,e^2]); B
--            Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
--            generated by [b, c, d, e^2]
--            sage: B.invariants()
--            [4, 5, 5, 7]
-+            Multiplicative Abelian subgroup isomorphic to C3 x C5 x C5 x C7 x C8 generated by {a, b, c, d^2, e}
-+            sage: A.subgroup([a, b, c, d^2, e^2])
-+            Multiplicative Abelian subgroup isomorphic to C3 x C4 x C5 x C5 x C7 generated by {a, b, c, d^2, e^2}
-+            sage: B = A.subgroup([a^3, b, c, d, e^2]); B
-+            Multiplicative Abelian subgroup isomorphic to C4 x C5 x C5 x C7 generated by {b, c, d, e^2}
-+            sage: B.gens_orders()
-+            (4, 5, 5, 7)
-             sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd")
-             sage: a,b,c,d = A.gens()
-             sage: B = A.subgroup([a^3,b,c,d])
--            sage: B.invariants()
--            [1009, 2003, 3001, 4001]
-+            sage: B.gens_orders()
-+            (1009, 2003, 3001, 4001)
-             sage: A.order()
-             24266473210027
-             sage: B.order()
-@@ -1220,41 +1435,35 @@
-             sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd")
-             sage: a,b,c,d = A.gens()
-             sage: B = A.subgroup([a^3,b,c,d]); B
--            Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x
--            C2003 x C3001 x C4001, which is the subgroup of
--            Multiplicative Abelian Group isomorphic to C1008 x C2003 x
--            C3001 x C4001 generated by [a^3, b, c, d]
-+            Multiplicative Abelian subgroup isomorphic
-+            to C3 x C7 x C16 x C2003 x C3001 x C4001 generated by {a^3, b, c, d}
-
-         Infinite groups can also be handled::
-
-             sage: G = AbelianGroup([3,4,0], names = "abc")
-             sage: a,b,c = G.gens()
--            sage: F = G.subgroup([a,b^2,c]); F
--            Multiplicative Abelian Group isomorphic to C2 x C3 x Z,
--            which is the subgroup of Multiplicative Abelian Group
--            isomorphic to C3 x C4 x Z generated by [a, b^2, c]
-+            sage: F = G.subgroup([a, b^2, c]); F
-+            Multiplicative Abelian subgroup isomorphic to C2 x C3 x Z generated by {a, b^2, c}
-
--        ::
--
--            sage: F.invariants()
--            [2, 3, 0]
-+            sage: F.gens_orders()
-+            (2, 3, 0)
-             sage: F.gens()
--            [a, b^2, c]
-+            (a, b^2, c)
-             sage: F.order()
-             +Infinity
-         """
-         from sage.interfaces.all import gap
-         if not isinstance(ambient, AbelianGroup_class):
-             raise TypeError, "ambient (=%s) must be an abelian group."%ambient
--        if not isinstance(gens, list):
--            raise TypeError, "gens (=%s) must be a list"%gens
-+        if not isinstance(gens, tuple):
-+            raise TypeError, "gens (=%s) must be a tuple"%gens
-
--        self.__ambient_group = ambient
--        Hgens = [x for x in gens if x != ambient(1)]  ## in case someone puts 1 in the list of generators
--        self.__gens = Hgens
-+        self._ambient_group = ambient
-+        Hgens = tuple(x for x in gens if x != ambient.one())  ## in case someone puts 1 in the list of generators
-+        self._gens = Hgens
-         m = len(gens)
-         ell = len(ambient.gens())
--        ambient_invs = ambient.invariants()
-+        ambient_invs = ambient.gens_orders()
-         invsf = [x for x in ambient_invs if x > 0]    ## fixes the problem with
-         invs0 = [x for x in ambient_invs if x == 0]   ## the infinite parts
-         Ggens = list(ambient.variable_names())
-@@ -1264,7 +1473,7 @@
-             Ggens0 = [x for x in ambient.variable_names() if
-                         ambient_invs[Ggens.index(x)] == 0]
-             ##     ^^ only look at "finite" names
--            Gf = AbelianGroup_class(len(invsf), invsf, names = Gfgens)
-+            Gf = AbelianGroup(invsf, names=Gfgens)
-             s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_()
-             gap.eval(s1)
-             Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0]
-@@ -1274,35 +1483,35 @@
-             for i in range(len(Gfgens)):
-                cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i]
-                gap.eval(cmd)
--        if invs0==[]:
--           Hgensf = Hgens
--           Hgens0 = []  # added for consistency
--           G = ambient
--           s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()
--           gap.eval(s1)
--           for i in range(len(Ggens)):
--               cmd = '%s := gens[%s]'%(Ggens[i], i+1)
--               #print i,"  \n",cmd
--               gap.eval(cmd)
--        s2 = "gensH:=%s"%Hgensf #### remove from this the ones <--> 0 invar
-+        else:  # invs0==[]:
-+            Hgensf = Hgens
-+            Hgens0 = []  # added for consistency
-+            G = ambient
-+            s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()
-+            gap.eval(s1)
-+            for i in range(len(Ggens)):
-+                cmd = '%s := gens[%s]'%(Ggens[i], i+1)
-+                #print i,"  \n",cmd
-+                gap.eval(cmd)
-+        s2 = "gensH:=%s"%list(Hgensf) #### remove from this the ones <--> 0 invar
-         gap.eval(s2)
-         s3 = 'H:=Subgroup(G,gensH)'
-         gap.eval(s3)
-         # a GAP command which returns the "invariants" of the
-         # subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)),
-         # works if G is the subgroup declared as a AbelianPcpGroup
--        self.__abinvs = eval(gap.eval("AbelianInvariants(H)"))
--        invs = self.__abinvs
-+        self._abinvs = eval(gap.eval("AbelianInvariants(H)"))
-+        invs = self._abinvs
-         #print s3, invs
-         if Hgens0 != []:
-             for x in Hgens0:
-                invs.append(0)
--        #print Hgensf, invs, invs0
--        AbelianGroup_class.__init__(self, len(invs), invs, names)
-+        invs = tuple(ZZ(i) for i in invs)
-+        AbelianGroup_class.__init__(self, invs, names)
-
-     def __contains__(self, x):