Ticket #13687: 13687_parent_for_groups_all_vb.patch

File 13687_parent_for_groups_all_vb.patch, 232.2 KB (added by Volker Braun, 10 years ago)

Updated patch

  • doc/de/tutorial/tour_advanced.rst

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1352835583 18000
    # Node ID 0da1a1dfbe77ef1d848546e7e32a281d587bb1d6
    # Parent  1bbcf5453b41f569f09a12ac0530f4e12bb5cd63
    New-style parents for Abelian groups
    
    diff --git a/doc/de/tutorial/tour_advanced.rst b/doc/de/tutorial/tour_advanced.rst
    a b  
    362362    Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
    363363
    364364    sage: G.unit_gens()
    365     [11, 17]
     365    (11, 17)
    366366    sage: G.zeta()
    367367    i
    368368    sage: G.zeta_order()
  • doc/de/tutorial/tour_groups.rst

    diff --git a/doc/de/tutorial/tour_groups.rst b/doc/de/tutorial/tour_groups.rst
    a b  
    8282    sage: d * b**2 * c**3
    8383    b^2*c^3*d
    8484    sage: F = AbelianGroup(3,[2]*3); F
    85     Multiplicative Abelian Group isomorphic to C2 x C2 x C2
     85    Multiplicative Abelian group isomorphic to C2 x C2 x C2
    8686    sage: H = AbelianGroup([2,3], names="xy"); H
    87     Multiplicative Abelian Group isomorphic to C2 x C3
     87    Multiplicative Abelian group isomorphic to C2 x C3
    8888    sage: AbelianGroup(5)
    89     Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
     89    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
    9090    sage: AbelianGroup(5).order()
    9191    +Infinity
  • doc/en/bordeaux_2008/nf_galois_groups.rst

    diff --git a/doc/en/bordeaux_2008/nf_galois_groups.rst b/doc/en/bordeaux_2008/nf_galois_groups.rst
    a b  
    311311    sage: category(C)
    312312    Category of groups
    313313    sage: C.gens()
    314     [Fractional ideal class (5, a), Fractional ideal class (3, a)]
     314    (Fractional ideal class (5, a), Fractional ideal class (3, a))
    315315
    316316
    317317Arithmetic in the class group
  • doc/en/reference/groups.rst

    diff --git a/doc/en/reference/groups.rst b/doc/en/reference/groups.rst
    a b  
    1010   sage/groups/group
    1111   sage/groups/generic
    1212   sage/groups/abelian_gps/abelian_group
     13   sage/groups/abelian_gps/values
     14   sage/groups/abelian_gps/dual_abelian_group
     15   sage/groups/abelian_gps/element_base
    1316   sage/groups/abelian_gps/abelian_group_element
     17   sage/groups/abelian_gps/dual_abelian_group_element
    1418   sage/groups/abelian_gps/abelian_group_morphism
    15    sage/groups/abelian_gps/dual_abelian_group
    1619   sage/groups/additive_abelian/additive_abelian_group
    1720   sage/groups/additive_abelian/additive_abelian_wrapper
    1821   sage/groups/perm_gps/permgroup
  • doc/en/tutorial/tour_advanced.rst

    diff --git a/doc/en/tutorial/tour_advanced.rst b/doc/en/tutorial/tour_advanced.rst
    a b  
    360360    Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
    361361
    362362    sage: G.unit_gens()
    363     [11, 17]
     363    (11, 17)
    364364    sage: G.zeta()
    365365    i
    366366    sage: G.zeta_order()
  • doc/en/tutorial/tour_groups.rst

    diff --git a/doc/en/tutorial/tour_groups.rst b/doc/en/tutorial/tour_groups.rst
    a b  
    8080    sage: d * b**2 * c**3
    8181    b^2*c^3*d
    8282    sage: F = AbelianGroup(3,[2]*3); F
    83     Multiplicative Abelian Group isomorphic to C2 x C2 x C2
     83    Multiplicative Abelian group isomorphic to C2 x C2 x C2
    8484    sage: H = AbelianGroup([2,3], names="xy"); H
    85     Multiplicative Abelian Group isomorphic to C2 x C3
     85    Multiplicative Abelian group isomorphic to C2 x C3
    8686    sage: AbelianGroup(5)
    87     Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
     87    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
    8888    sage: AbelianGroup(5).order()
    8989    +Infinity
  • doc/fr/tutorial/tour_advanced.rst

    diff --git a/doc/fr/tutorial/tour_advanced.rst b/doc/fr/tutorial/tour_advanced.rst
    a b  
    360360    Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
    361361
    362362    sage: G.unit_gens()
    363     [11, 17]
     363    (11, 17)
    364364    sage: G.zeta()
    365365    i
    366366    sage: G.zeta_order()
  • doc/fr/tutorial/tour_groups.rst

    diff --git a/doc/fr/tutorial/tour_groups.rst b/doc/fr/tutorial/tour_groups.rst
    a b  
    8383    sage: d * b**2 * c**3
    8484    b^2*c^3*d
    8585    sage: F = AbelianGroup(3,[2]*3); F
    86     Multiplicative Abelian Group isomorphic to C2 x C2 x C2
     86    Multiplicative Abelian group isomorphic to C2 x C2 x C2
    8787    sage: H = AbelianGroup([2,3], names="xy"); H
    88     Multiplicative Abelian Group isomorphic to C2 x C3
     88    Multiplicative Abelian group isomorphic to C2 x C3
    8989    sage: AbelianGroup(5)
    90     Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
     90    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
    9191    sage: AbelianGroup(5).order()
    9292    +Infinity
  • doc/ru/tutorial/tour_advanced.rst

    diff --git a/doc/ru/tutorial/tour_advanced.rst b/doc/ru/tutorial/tour_advanced.rst
    a b  
    325325    Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> i)
    326326
    327327    sage: G.unit_gens()
    328     [11, 17]
     328    (11, 17)
    329329    sage: G.zeta()
    330330    i
    331331    sage: G.zeta_order()
  • doc/ru/tutorial/tour_groups.rst

    diff --git a/doc/ru/tutorial/tour_groups.rst b/doc/ru/tutorial/tour_groups.rst
    a b  
    8080    sage: d * b**2 * c**3
    8181    b^2*c^3*d
    8282    sage: F = AbelianGroup(3,[2]*3); F
    83     Multiplicative Abelian Group isomorphic to C2 x C2 x C2
     83    Multiplicative Abelian group isomorphic to C2 x C2 x C2
    8484    sage: H = AbelianGroup([2,3], names="xy"); H
    85     Multiplicative Abelian Group isomorphic to C2 x C3
     85    Multiplicative Abelian group isomorphic to C2 x C3
    8686    sage: AbelianGroup(5)
    87     Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
     87    Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
    8888    sage: AbelianGroup(5).order()
    8989    +Infinity
  • module_list.py

    diff --git a/module_list.py b/module_list.py
    a b  
    491491    Extension('sage.groups.group',
    492492              sources = ['sage/groups/group.pyx']),
    493493
     494    Extension('sage.groups.old',
     495              sources = ['sage/groups/old.pyx']),
     496
    494497    Extension('sage.groups.perm_gps.permgroup_element',
    495498              sources = ['sage/groups/perm_gps/permgroup_element.pyx']),
    496499
  • sage/algebras/group_algebra.py

    diff --git a/sage/algebras/group_algebra.py b/sage/algebras/group_algebra.py
    a b  
    3030from sage.algebras.algebra_element import AlgebraElement
    3131from sage.rings.all import IntegerRing
    3232from sage.groups.group import Group
     33from sage.groups.old import Group as OldGroup
    3334from sage.structure.formal_sum import FormalSums, FormalSum
    3435from sage.sets.set import Set
    3536
     
    6768        if not base_ring.is_commutative():
    6869            raise NotImplementedError("Base ring must be commutative")
    6970       
    70         if not isinstance(group, Group):
     71        if not isinstance(group, (Group, OldGroup)):
    7172            raise TypeError('"%s" is not a group' % group)
    7273
    7374        ParentWithGens.__init__(self, base_ring, category = GroupAlgebras(base_ring))
     
    251252            sage: ZG(1) == ZG(G(1))
    252253            True
    253254            sage: ZG(FormalSum([(1,f), (2, f**2)]))
    254             2*f^2 + f
     255            f + 2*f^2
    255256            sage: G = GL(2,7)
    256257            sage: OG = GroupAlgebra(G, ZZ[sqrt(5)])
    257258            sage: OG(2)
  • sage/algebras/group_algebra_new.py

    diff --git a/sage/algebras/group_algebra_new.py b/sage/algebras/group_algebra_new.py
    a b  
    256256            Group algebra of group "General Linear Group of degree 3 over Finite Field of size 7" over base ring Integer Ring
    257257        """
    258258        from sage.groups.group import Group
     259        from sage.groups.old import Group as OldGroup
    259260        if not base_ring.is_commutative():
    260261            raise NotImplementedError("Base ring must be commutative")
    261262
    262         if not isinstance(group, Group):
     263        if not isinstance(group, (Group, OldGroup)):
    263264            raise TypeError('"%s" is not a group' % group)
    264265
    265266        self._group = group
     
    680681            True
    681682        """
    682683        from sage.rings.all import is_Ring
    683         from sage.groups.group import Group
     684        from sage.groups.old import Group
    684685        k = self.base_ring()
    685686        G = self.group()
    686687        if isinstance(S, GroupAlgebra):
     
    732733            [0 1]
    733734        """
    734735        from sage.rings.all import is_Ring
    735         from sage.groups.group import Group
     736        from sage.groups.old import Group
    736737        from sage.structure.formal_sum import FormalSum
    737738        k = self.base_ring()
    738739        G = self.group()
  • sage/all.py

    diff --git a/sage/all.py b/sage/all.py
    a b  
    4242exit = quit
    4343
    4444import os, sys
     45import operator
    4546
    4647if 'SAGE_ROOT' not in os.environ:
    4748    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")
  • sage/categories/action.pyx

    diff --git a/sage/categories/action.pyx b/sage/categories/action.pyx
    a b  
    216216    An action that acts as the inverse of the given action.
    217217
    218218    TESTS:
     219
    219220    This illustrates a shortcoming in the current coercion model.
    220     See the comments in _call_ below.
     221    See the comments in _call_ below::
    221222   
    222223        sage: x = polygen(QQ,'x')
    223224        sage: a = 2*x^2+2; a
     
    231232    def __init__(self, Action action):
    232233        G = action.G
    233234        try:
     235            from sage.groups.old import Group as OldGroup
    234236            from sage.groups.group import Group
    235237            # We must be in the case that parent(~a) == parent(a)
    236238            # so we can invert in call_c code below.
    237             if (PY_TYPE_CHECK(G, Group) and G.is_multiplicative()) or G.is_field():
     239            if (isinstance(G, (Group, OldGroup)) and G.is_multiplicative()) or G.is_field():
    238240                Action.__init__(self, G, action.underlying_set(), action._is_left)
    239241                self._action = action
    240242                return
  • sage/categories/category.py

    diff --git a/sage/categories/category.py b/sage/categories/category.py
    a b  
    2323    sage: Sets()
    2424    Category of sets
    2525    sage: GSets(AbelianGroup([2,4,9]))
    26     Category of G-sets for Multiplicative Abelian Group isomorphic to C2 x C4 x C9
     26    Category of G-sets for Multiplicative Abelian group isomorphic to C2 x C4 x C9
    2727    sage: Semigroups()
    2828    Category of semigroups
    2929    sage: VectorSpaces(FiniteField(11))
  • sage/groups/abelian_gps/abelian_group.py

    diff --git a/sage/groups/abelian_gps/abelian_group.py b/sage/groups/abelian_gps/abelian_group.py
    a b  
    11r"""
    22Multiplicative Abelian Groups
    33
    4 AUTHORS:
     4This module lets you compute with finitely generated Abelian groups of the form
    55
    6 - William Stein, David Joyner (2008-12): added (user requested) is_cyclic,
    7   fixed elementary_divisors.
     6.. math::
    87
    9 - David Joyner (2006-03): (based on free abelian monoids by David
    10   Kohel)
     8    G = \ZZ^r \oplus \ZZ_{k_1} \oplus \cdots \oplus \ZZ_{k_t}
    119
    12 - David Joyner (2006-05) several significant bug fixes
     10It is customary to denote the infinite cyclic group `\ZZ` as having
     11order `0`, so the data defining the Abelian group can be written as an
     12integer vector
    1313
    14 - David Joyner (2006-08) trivial changes to docs, added random, fixed
    15   bug in how invariants are recorded
     14.. math::
    1615
    17 - David Joyner (2006-10) added dual_group method
     16    \vec{k} = (0, \dots, 0, k_1, \dots, k_t)
    1817
    19 - David Joyner (2008-02) fixed serious bug in word_problem
     18where there are `r` zeroes and `t` non-zero values. To construct this
     19Abelian group in Sage, you can either specify all entries of `\vec{k}`
     20or only the non-zero entries together with the total number of
     21generators::
    2022
    21 - David Joyner (2008-03) fixed bug in trivial group case
     23    sage: AbelianGroup([0,0,0,2,3])
     24    Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3
     25    sage: AbelianGroup(5, [2,3])
     26    Multiplicative Abelian group isomorphic to Z x Z x Z x C2 x C3
    2227
    23 - David Loeffler (2009-05) added subgroups method
     28It is also legal to specify `1` as the order. The corresponding
     29generator will be the neutral element, but it will still take up an
     30index in the labelling of the generators::
    2431
     32    sage: G = AbelianGroup([2,1,3], names='g')
     33    sage: G.gens()
     34    (g0, 1, g2)
    2535
    26 TODO:
     36Note that this presentation is not unique, for example `\ZZ_6 = \ZZ_2
     37\times \ZZ_3`. The orders of the generators
     38`\vec{k}=(0,\dots,0,k_1,\dots, k_t)` has previously been called
     39invariants in Sage, even though they are not necessarily the (unique)
     40invariant factors of the group. You should now use
     41:meth:`~AbelianGroup_class.gens_orders` instead::
    2742
    28 - additive abelian groups should also be supported
     43   sage: J = AbelianGroup([2,0,3,2,4]);  J
     44   Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
     45   sage: J.gens_orders()            # use this instead
     46   (2, 0, 3, 2, 4)
     47   sage: J.invariants()             # deprecated
     48   (2, 0, 3, 2, 4)
     49   sage: J.elementary_divisors()    # these are the "invariant factors"
     50   (2, 2, 12, 0)
     51   sage: for i in range(J.ngens()):
     52   ...       print i, J.gen(i), J.gen(i).order()     # or use this form
     53   0 f0 2
     54   1 f1 +Infinity
     55   2 f2 3
     56   3 f3 2
     57   4 f4 4
    2958
    3059Background on invariant factors and the Smith normal form
    3160(according to section 4.1 of [C1]): An abelian group is a
     
    3766
    3867.. math::
    3968
    40    A = \langle a_1\rangle \times \dots \times  \langle a_\ell\rangle ,
     69    A = \langle a_1\rangle \times \dots \times  \langle a_\ell\rangle ,
    4170
    4271where `ord(a_i)=p_i^{c_i}`, for some primes `p_i` and some
    4372positive integers `c_i`, `i=1,...,\ell`. GAP calls the
     
    5988
    6089.. math::
    6190
    62    F=
    63    \left(
    64    \begin{array}{cccc}
    65    f_{11} & f_{12} & \dots & f_{1m}\\
    66    f_{21} & f_{22} & \dots & f_{2m}\\
    67    \vdots &        & \ddots & \vdots \\
    68    f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m}
    69    \end{array}
    70    \right),
     91    F=
     92    \left(
     93    \begin{array}{cccc}
     94    f_{11} & f_{12} & \dots & f_{1m}\\
     95    f_{21} & f_{22} & \dots & f_{2m}\\
     96    \vdots &        & \ddots & \vdots \\
     97    f_{\ell,1} & f_{\ell,2} & \dots & f_{\ell,m}
     98    \end{array}
     99    \right),
    71100
    72101regarded as a map
    73102`\ZZ^m\rightarrow (\ZZ/p_1^{c_1}\ZZ)\times ...\times (\ZZ/p_\ell^{c_\ell}\ZZ)`.
     
    80109
    81110.. math::
    82111
    83   s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}.
    84 
    85 
     112    s_1, s_2/s_1, s_3/s_2, ... s_r/s_{r-1}.
    86113
    87114Sage supports multiplicative abelian groups on any prescribed finite
    88 number `n \geq 0` of generators.  Use the ``AbelianGroup`` function
    89 to create an abelian group, and the ``gen`` and ``gens``
    90 functions to obtain the corresponding generators.  You can print the
    91 generators as arbitrary strings using the optional ``names``
    92 argument to the ``AbelianGroup`` function.
     115number `n \geq 0` of generators.  Use the :func:`AbelianGroup`
     116function to create an abelian group, and the
     117:meth:`~AbelianGroup_class.gen` and :meth:`~AbelianGroup_class.gens`
     118methods to obtain the corresponding generators.  You can print the
     119generators as arbitrary strings using the optional ``names`` argument
     120to the :func:`AbelianGroup` function.
    93121
    94122EXAMPLE 1:
    95123
    96124We create an abelian group in zero or more variables; the syntax T(1)
    97 creates the identity element even in the rank zero case.
    98 
    99 ::
     125creates the identity element even in the rank zero case::
    100126
    101127    sage: T = AbelianGroup(0,[])
    102128    sage: T
    103     Trivial Abelian Group
     129    Trivial Abelian group
    104130    sage: T.gens()
    105131    ()
    106132    sage: T(1)
    107133    1
    108134
    109 EXAMPLE 2: An abelian group uses a multiplicative representation of
    110 elements, but the underlying representation is lists of integer
    111 exponents.
     135EXAMPLE 2:
    112136
    113 ::
     137An Abelian group uses a multiplicative representation of elements, but
     138the underlying representation is lists of integer exponents::
    114139
    115140    sage: F = AbelianGroup(5,[3,4,5,5,7],names = list("abcde"))
    116141    sage: F
    117     Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7
     142    Multiplicative Abelian group isomorphic to C3 x C4 x C5 x C5 x C7
    118143    sage: (a,b,c,d,e) = F.gens()
    119144    sage: a*b^2*e*d
    120145    a*b^2*d*e
     
    139164
    140165   Many basic properties for infinite abelian groups are not
    141166   implemented.
     167
     168
     169AUTHORS:
     170
     171- William Stein, David Joyner (2008-12): added (user requested) is_cyclic,
     172  fixed elementary_divisors.
     173
     174- David Joyner (2006-03): (based on free abelian monoids by David
     175  Kohel)
     176
     177- David Joyner (2006-05) several significant bug fixes
     178
     179- David Joyner (2006-08) trivial changes to docs, added random, fixed
     180  bug in how invariants are recorded
     181
     182- David Joyner (2006-10) added dual_group method
     183
     184- David Joyner (2008-02) fixed serious bug in word_problem
     185
     186- David Joyner (2008-03) fixed bug in trivial group case
     187
     188- David Loeffler (2009-05) added subgroups method
     189
     190- Volker Braun (2012-11) port to new Parent base. Use tuples for
     191  immutables. Rename invariants to gens_orders.
    142192"""
    143193
    144194##########################################################################
    145 #  Copyright (C) 2006 David Joyner and William Stein
     195#  Copyright (C) 2006 William Stein <wstein@gmail.com>
     196#  Copyright (C) 2006 David Joyner  <wdjoyner@gmail.com>
     197#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
    146198#
    147199#  Distributed under the terms of the GNU General Public License (GPL):
    148200#
    149201#                  http://www.gnu.org/licenses/
    150202##########################################################################
    151203
    152 # TODO: change the "invariants" terminology everywhere to elementary_divisors
    153 
    154 
    155204
    156205from sage.rings.integer import Integer
    157 
     206from sage.rings.integer_ring import ZZ
     207from sage.structure.unique_representation import UniqueRepresentation
    158208from sage.rings.infinity import infinity
    159209from sage.rings.arith import divisors, gcd
    160 from abelian_group_element import AbelianGroupElement
     210from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
     211from sage.misc.cachefunc import cached_method
    161212from sage.misc.misc import prod
    162213from sage.misc.mrange import mrange, cartesian_product_iterator
    163 import sage.groups.group as group
    164 from sage.rings.integer_ring import IntegerRing
    165214from sage.rings.arith import lcm
    166 ZZ = IntegerRing()
     215from sage.groups.group import AbelianGroup as AbelianGroupBase
     216
    167217
    168218# TODO: this uses perm groups - the AbelianGroupElement instance method
    169219# uses a different implementation.
    170  
    171 
    172220def word_problem(words, g, verbose = False):
    173221    r"""
    174222    G and H are abelian, g in G, H is a subgroup of G generated by a
     
    202250    EXAMPLE::
    203251   
    204252        sage: G.<a,b,c> = AbelianGroup(3,[2,3,4]); G
    205         Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     253        Multiplicative Abelian group isomorphic to C2 x C3 x C4
    206254        sage: w = word_problem([a*b,a*c], b*c); w #random
    207255        [[a*b, 1], [a*c, 1]] 
    208256        sage: prod([x^i for x,i in w]) == b*c
     
    242290          AbelianGroupElement is implemented differently (wrapping
    243291          GAP's 'EpimorphismFromFreeGroup' and
    244292          'PreImagesRepresentative') and may be faster.
    245        
    246293    """
    247294    from sage.interfaces.all import gap
    248295    G = g.parent()
    249     invs = G.invariants()
     296    invs = map(str, G.gens_orders())
    250297    gap.eval("l:=One(Rationals)")
    251     s1 = 'A:=AbelianGroup(%s)'%invs
     298    s1 = 'A:=AbelianGroup([' + ','.join(invs) + '])'
    252299    gap.eval(s1)
    253300    s2 = 'phi:=IsomorphismPermGroup(A)'
    254301    gap.eval(s2)
     
    279326    return [[words[l3[2*i]-1],LL[i]] for i in range(len(LL))]
    280327
    281328
    282 def AbelianGroup(n, invfac=None, names="f"):
     329def _normalize(n, gens_orders=None, names="f"):
     330    """
     331    Helper function for :func:`AbelianGroup`. Beat some sense into the
     332    arguments.
     333
     334    This function is also used by some descendents of
     335    :class:`AbelianGroup_class`.
     336
     337    INPUT:
     338
     339    See :func:`AbelianGroup`
     340
     341    OUTPUT:
     342
     343    Unique data for defining a :class:`AbelianGroup_class`. Raises an
     344    exception if the input is invalid.
     345
     346    EXAMPLES::
     347
     348        sage: from sage.groups.abelian_gps.abelian_group import _normalize
     349        sage: _normalize(5, [2,1,0], names='abc')
     350        ((0, 0, 2, 1, 0), 'abc')
     351        sage: _normalize(5, (2.0, 1.0, 0/1), names=list('abc'))
     352        ((0, 0, 2, 1, 0), ('a', 'b', 'c'))
     353        sage: _normalize([0,2,1,0], names='a')
     354        ((0, 2, 1, 0), 'a')
     355
     356    TESTS::
     357
     358        sage: _normalize(5, (2.0, 1.5, 0/1), names=list('abc'))
     359        Traceback (most recent call last):
     360        ...
     361        TypeError: Attempt to coerce non-integral RealNumber to Integer
     362        sage: _normalize('1', '[2]', names='a')
     363        Traceback (most recent call last):
     364        ...
     365        TypeError: unable to convert x (=[) to an integer
     366        sage: _normalize(3, 'str', names='a')
     367        Traceback (most recent call last):
     368        ...
     369        TypeError: unable to convert x (=s) to an integer
     370   """
     371    if gens_orders is None:
     372        if isinstance(n, (list, tuple)):
     373            gens_orders = n
     374            n = len(n)
     375        else:
     376            gens_orders = []
     377    n = ZZ(n)
     378    if len(gens_orders) < n:
     379        gens_orders = [0] * (n - len(gens_orders)) + list(gens_orders)
     380    gens_orders = tuple(ZZ(i) for i in gens_orders)
     381    if len(gens_orders) > n:
     382        raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')')
     383    if isinstance(names, list):
     384        names = tuple(names)
     385    return (gens_orders, names)
     386
     387def AbelianGroup(n, gens_orders=None, names="f"):
    283388    r"""
    284389    Create the multiplicative abelian group in `n` generators
    285     with given invariants (which need not be prime powers).
     390    with given orders of generators (which need not be prime powers).
    286391   
    287392    INPUT:
    288393   
     394    - ``n`` -- integer (optional). If not specified, will be derived
     395       from ``gens_orders``.
    289396   
    290     -  ``n`` - integer
     397    - ``gens_orders`` -- a list of non-negative integers in the form
     398       `[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing
     399       order. This list is padded with zeros if it has length less
     400       than n. The orders of the commuting generators, with `0`
     401       denoting an infinite cyclic factor.
    291402   
    292     -  ``invfac`` - (the"invariant factors") a list of
    293        non-negative integers in the form [a0, a1,...,a(n-1)], typically
    294        written in increasing order. This list is padded with zeros if it
    295        has length less than n.
     403    -  ``names`` -- (optional) names of generators
    296404   
    297     -  ``names`` - (optional) names of generators
     405    Alternatively, you can also give input in the form
     406    ``AbelianGroup(gens_orders, names="f")``, where the names keyword
     407    argument must be explicitly named.
    298408   
    299        Alternatively, you can also give input in the following form:
    300    
    301        ``AbelianGroup(invfac, names="f")``,
    302    
    303        where names must be explicitly named.
    304    
    305    
    306     OUTPUT: Abelian group with generators and invariant type. The
    307     default name for generator A.i is fi, as in GAP.
     409    OUTPUT:
     410
     411    Abelian group with generators and invariant type. The default name
     412    for generator ``A.i`` is ``fi``, as in GAP.
    308413   
    309414    EXAMPLES::
    310415   
     
    317422        sage: d * b**2 * c**3
    318423        b^2*c^3*d
    319424        sage: F = AbelianGroup(3,[2]*3); F
    320         Multiplicative Abelian Group isomorphic to C2 x C2 x C2
     425        Multiplicative Abelian group isomorphic to C2 x C2 x C2
    321426        sage: H = AbelianGroup([2,3], names="xy"); H
    322         Multiplicative Abelian Group isomorphic to C2 x C3
     427        Multiplicative Abelian group isomorphic to C2 x C3
    323428        sage: AbelianGroup(5)
    324         Multiplicative Abelian Group isomorphic to Z x Z x Z x Z x Z
     429        Multiplicative Abelian group isomorphic to Z x Z x Z x Z x Z
    325430        sage: AbelianGroup(5).order()
    326431        +Infinity
    327432   
    328     Notice how `0`'s are padded on.
     433    Notice that `0`'s are prepended if necessary::
    329434   
    330     ::
    331    
    332         sage: AbelianGroup(5, [2,3,4])
    333         Multiplicative Abelian Group isomorphic to Z x Z x C2 x C3 x C4
    334    
    335     The invariant list can't be longer than the number of generators.
    336    
    337     ::
     435        sage: G = AbelianGroup(5, [2,3,4]);  G
     436        Multiplicative Abelian group isomorphic to Z x Z x C2 x C3 x C4
     437        sage: G.gens_orders()
     438        (0, 0, 2, 3, 4)
     439
     440    The invariant list must not be longer than the number of generators::
    338441   
    339442        sage: AbelianGroup(2, [2,3,4])
    340443        Traceback (most recent call last):
    341444        ...
    342         ValueError: invfac (=[2, 3, 4]) must have length n (=2)
     445        ValueError: gens_orders (=(2, 3, 4)) must have length n (=2)
    343446    """
    344     if invfac is None:
    345         if isinstance(n, (list, tuple)):
    346             invfac = n
    347             n = len(n)
    348         else:
    349             invfac = []
    350     if len(invfac) < n:
    351         invfac = [0] * (n - len(invfac)) + invfac
    352     elif len(invfac) > n:
    353         raise ValueError, "invfac (=%s) must have length n (=%s)"%(invfac, n)
    354     M = AbelianGroup_class(n, invfac, names)
     447    gens_orders, names = _normalize(n, gens_orders, names)
     448    M = AbelianGroup_class(gens_orders, names)
    355449    return M
    356450
    357451def is_AbelianGroup(x):
    358452    """
    359     Return True if `x` is an abelian group.
     453    Return True if ``x`` is an Abelian group.
    360454   
    361455    EXAMPLES::
    362456   
    363457        sage: from sage.groups.abelian_gps.abelian_group import is_AbelianGroup
    364458        sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F
    365         Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
     459        Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9
    366460        sage: is_AbelianGroup(F)
    367461        True
    368462        sage: is_AbelianGroup(AbelianGroup(7, [3]*7))
     
    371465    return isinstance(x, AbelianGroup_class)
    372466
    373467
    374 class AbelianGroup_class(group.AbelianGroup):
     468class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase):
    375469    """
    376     Abelian group on `n` generators. The invariant factors
    377     `[a_1,a_2,...,a_k]` need not be prime powers.
    378     divisors will be).
     470    The parent for Abelian groups with chosen generator orders.
     471
     472    .. warning::
     473
     474        You should use :func:`AbelianGroup` to construct Abelian
     475        groups and not instantiate this class directly.
     476   
     477    INPUT:
     478
     479    - ``generator_orders`` -- list of integers. The orders of the
     480      (commuting) generators. Zero denotes an infinite cyclic
     481      generator.
     482
     483    - ``names`` -- names of the group generators (optional).
    379484   
    380485    EXAMPLES::
    381486   
     487        sage: Z2xZ3 = AbelianGroup([2,3])
     488        sage: Z6 = AbelianGroup([6])
     489        sage: Z2xZ3 is Z2xZ3, Z6 is Z6
     490        (True, True)
     491        sage: Z2xZ3 is Z6
     492        False
     493        sage: Z2xZ3 == Z6
     494        True
     495
    382496        sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F
    383         Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
     497        Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9
    384498        sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F
    385         Multiplicative Abelian Group isomorphic to C2 x C4 x C12 x C24 x C120
     499        Multiplicative Abelian group isomorphic to C2 x C4 x C12 x C24 x C120
    386500        sage: F.elementary_divisors()
    387         [2, 4, 12, 24, 120]
    388 
    389     The entry 1 in the list of invariants is ignored::
    390 
    391         sage: F = AbelianGroup(3,[1,2,3],names='a')
    392         sage: F.invariants()
    393         [2, 3]
    394         sage: F.gens()
    395         (a0, a1)
    396         sage: F.ngens()
    397         2
    398         sage: (F.0).order()
    399         2
    400         sage: (F.1).order()
    401         3
    402         sage: AbelianGroup(1, [1], names='e')
    403         Multiplicative Abelian Group isomorphic to C1
    404         sage: AbelianGroup(1, [1], names='e').gens()
    405         (e,)
    406         sage: AbelianGroup(1, [1], names='e').list()
    407         [1]
    408         sage: AbelianGroup(3, [2, 1, 2], names=list('abc')).list()
    409         [1, b, a, a*b]
     501        (2, 4, 12, 24, 120)
    410502
    411503        sage: F.category()
    412504        Category of groups
    413505
     506    TESTS::
     507
     508        sage: AbelianGroup([]).gens_orders()
     509        ()
     510        sage: AbelianGroup([1]).gens_orders()
     511        (1,)
     512        sage: AbelianGroup([1,1]).gens_orders()
     513        (1, 1)
     514        sage: AbelianGroup(0).gens_orders()
     515        ()
    414516    """
    415     def __init__(self, n, invfac, names="f"):
    416         #invfac.sort()
    417         n = Integer(n)
    418         # if necessary, remove 1 from invfac first
    419         if n != 1:
    420             while True:
    421                 try:
    422                     i = invfac.index(1)
    423                 except ValueError:
    424                     break
    425                 else:
    426                     del invfac[i]
    427                     n = n-1
     517    Element = AbelianGroupElement
    428518
    429         if n < 0:
    430             raise ValueError, "n (=%s) must be nonnegative."%n
     519    def __init__(self, generator_orders, names):
     520        """
     521        The Python constructor
    431522
    432         self.__invariants = invfac
     523        TESTS::
    433524
    434         # *now* define ngens
    435         self.__ngens = len(self.__invariants)
    436         self._assign_names(names[:n])
    437         from sage.categories.groups import Groups
    438         group.Group.__init__(self, category = Groups()) # should be CommutativeGroups()
     525            sage: G = AbelianGroup([0,5,0,7],names = list("abcd")); G
     526            Multiplicative Abelian group isomorphic to Z x C5 x Z x C7
     527            sage: TestSuite(G).run()
     528        """
     529        assert isinstance(names, (basestring, tuple))
     530        assert isinstance(generator_orders, tuple)
     531        assert all(isinstance(order,Integer) for order in generator_orders)
     532        self._gens_orders = generator_orders
     533        n = ZZ(len(generator_orders))
     534        names = self.normalize_names(n, names)
     535        self._assign_names(names)
     536        AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()
    439537
    440     def __call__(self, x):
     538    def is_isomorphic(left, right):
    441539        """
    442         Create an element of this abelian group from `x`.
     540        Check whether ``left`` and ``right`` are isomorphic
    443541       
     542        INPUT:
     543
     544        - ``right`` -- anything.
     545
     546        OUTPUT:
     547
     548        Boolean. Whether ``left`` and ``right`` are isomorphic as abelian groups.
     549
    444550        EXAMPLES::
    445        
    446             sage: F = AbelianGroup(10, [2]*10)
    447             sage: F(F.2)
    448             f2
    449             sage: F(1)
    450             1
    451         """
    452         if isinstance(x, AbelianGroupElement) and x.parent() is self:
    453             return x
    454         return AbelianGroupElement(self, x)
    455                                
    456     def __contains__(self, x):
    457         """
    458         Return True if `x` is an element of this abelian group.
    459        
    460         EXAMPLES::
    461        
    462             sage: F = AbelianGroup(10,[2]*10)
    463             sage: F.2 * F.3 in F
    464             True
    465         """
    466         return isinstance(x, AbelianGroupElement) and x.parent() == self
    467551
    468     def __eq__(self, right):
    469         """
    470         Compare self and right.
    471        
    472         The ordering is the ordering induced by that on the invariant
    473         factors lists.
    474        
    475         EXAMPLES::
    476        
    477552            sage: G1 = AbelianGroup([2,3,4,5])
    478553            sage: G2 = AbelianGroup([2,3,4,5,1])
    479             sage: G1 < G2
    480             False
    481             sage: G1 > G2
    482             False
    483             sage: G1 == G2
     554            sage: G1.is_isomorphic(G2)
     555            True
     556            sage: G1 == G2    # syntactic sugar
    484557            True
    485558        """
    486559        if not is_AbelianGroup(right):
    487560            return False
    488         if set(self.variable_names()) != set(right.variable_names()):
    489             return False
    490         svars = list(self.variable_names())
    491         sinvs = self.invariants()
    492         rvars = list(right.variable_names())
    493         rinvs = right.invariants()
    494         for i in xrange(len(svars)):
    495             if rinvs[rvars.index(svars[i])] != sinvs[i]:
     561        return left.elementary_divisors() == right.elementary_divisors()
     562
     563    __eq__ = is_isomorphic
     564
     565    def __ne__(left, right):
     566        """
     567        Check whether ``left`` and ``right`` are not isomorphic
     568
     569        OUTPUT:
     570
     571        Boolean.
     572
     573        EXAMPLES::
     574
     575            sage: G1 = AbelianGroup([2,3,4,5])
     576            sage: G2 = AbelianGroup([2,3,4,5,1])
     577            sage: G1 != G2
     578            False
     579            sage: G1.__ne__(G2)
     580            False
     581        """
     582        return not left.is_isomorphic(right)
     583
     584    def is_subgroup(left, right):
     585        """
     586        Test whether ``left`` is a subgroup of ``right``.
     587
     588        EXAMPLES::
     589
     590            sage: G = AbelianGroup([2,3,4,5])
     591            sage: G.is_subgroup(G)
     592            True
     593
     594            sage: H = G.subgroup([G.1])
     595            sage: H.is_subgroup(G)
     596            True
     597
     598            sage: G.<a, b> = AbelianGroup(2)
     599            sage: H.<c> = AbelianGroup(1)
     600            sage: H < G
     601            False
     602       """
     603        for l in left.gens():
     604            if l not in right:
    496605                return False
    497606        return True
     607
     608    __le__ = is_subgroup
     609
     610    def __ge__(left, right):
     611        """
     612        Test whether ``right`` is a subgroup of ``left``
     613
     614        EXAMPLE::
     615
     616            sage: G.<a, b> = AbelianGroup(2)
     617            sage: H.<c> = AbelianGroup(1)
     618            sage: G >= H
     619            False
     620        """
     621        return right.__le__(left)
    498622   
    499     def __ne__(self, right):
    500         return not self == right
    501    
    502     def __ge__(self, right):
    503         for a in right.gens():
    504             if a not in self:
    505                 return False
    506         return True
    507    
    508     def __lt__(self, right):
     623    def __lt__(left, right):
    509624        """
     625        Test whether ``left`` is a strict subgroup of ``right``
     626
    510627        EXAMPLE::
    511628       
    512629            sage: G.<a, b> = AbelianGroup(2)
     
    514631            sage: H < G
    515632            False
    516633        """
    517         return self <= right and self != right
     634        return left <= right and left != right
    518635   
    519     def __gt__(self, right):
    520         return self >= right and self != right
     636    def __gt__(left, right):
     637        """
     638        Test whether ``right`` is a strict subgroup of ``left``
     639
     640        EXAMPLE::
     641
     642            sage: G.<a, b> = AbelianGroup(2)
     643            sage: H.<c> = AbelianGroup(1)
     644            sage: G > H
     645            False
     646        """
     647        return left >= right and left != right
    521648   
    522     def __le__(self, right):
    523         for a in self.gens():
    524             if a not in right:
    525                 return False
    526         return True
     649    def is_trivial(self):
     650        """
     651        Return whether the group is trivial
     652
     653        A group is trivial if it has precisely one element.
     654
     655        EXAMPLES::
     656
     657            sage: AbelianGroup([2, 3]).is_trivial()
     658            False
     659            sage: AbelianGroup([1, 1]).is_trivial()
     660            True
     661        """
     662        return self.elementary_divisors() == ()
    527663
    528664    def __nonzero__(self):
    529665        """
     
    536672            True
    537673            sage: bool(AbelianGroup([]))
    538674            False
     675            sage: bool(AbelianGroup([1,1,1]))
     676            False
    539677        """
    540         return len(self.invariants()) != 0
     678        return not self.is_trivial()
    541679
    542     def dual_group(self):
     680    @cached_method
     681    def dual_group(self, names="X", base_ring=None):
    543682        """
    544683        Returns the dual group.
     684
     685        INPUT:
     686
     687        - ``names`` -- string or list of strings. The generator names
     688          for the dual group.
     689
     690        - ``base_ring`` -- the base ring. If ``None`` (default), then
     691          a suitable cyclotomic field is picked automatically.
    545692       
    546         EXAMPLES:
     693        OUTPUT:
     694
     695        The
     696        :class:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class
     697        <dual abelian group>`
     698
     699        EXAMPLES::
     700
     701            sage: G = AbelianGroup([2])
     702            sage: G.dual_group()
     703            Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1
     704            sage: G.dual_group().gens()
     705            (X,)
     706            sage: G.dual_group(names='Z').gens()
     707            (Z,)
     708
     709            sage: G.dual_group(base_ring=QQ)
     710            Dual of Abelian Group isomorphic to Z/2Z over Rational Field
     711
     712
     713        TESTS::
     714
     715            sage: H = AbelianGroup(1)
     716            sage: H.dual_group()
     717            Traceback (most recent call last):
     718            ...
     719            ValueError: the group must be finite
    547720        """
    548         from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup
    549         return DualAbelianGroup(self)
     721        from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup_class
     722        if not self.is_finite():
     723            raise ValueError('the group must be finite')
     724        if base_ring is None:
     725            from sage.rings.number_field.number_field import CyclotomicField
     726            from sage.rings.arith import LCM
     727            base_ring = CyclotomicField(LCM(self.gens_orders()))
     728        return DualAbelianGroup_class(self, names=names, base_ring=base_ring)
    550729                 
     730    @cached_method
    551731    def elementary_divisors(self):
    552732        r"""
    553733        This returns the elementary divisors of the group, using Pari.
     
    566746            on these ""smaller invariants"" to compute `d_{i-1}`, and so on.
    567747            (Thanks to Robert Miller for communicating this algorithm.)
    568748
     749        OUTPUT:
     750
     751        A tuple of integers.
     752
    569753        EXAMPLES::
    570754       
    571755            sage: G = AbelianGroup(2,[2,3])
    572756            sage: G.elementary_divisors()
    573             [6]
     757            (6,)
    574758            sage: G = AbelianGroup(1, [6])
    575759            sage: G.elementary_divisors()
    576             [6]
     760            (6,)
    577761            sage: G = AbelianGroup(2,[2,6])
    578762            sage: G
    579             Multiplicative Abelian Group isomorphic to C2 x C6
    580             sage: G.invariants()
    581             [2, 6]
     763            Multiplicative Abelian group isomorphic to C2 x C6
     764            sage: G.gens_orders()
     765            (2, 6)
    582766            sage: G.elementary_divisors()
    583             [2, 6]
     767            (2, 6)
    584768            sage: J = AbelianGroup([1,3,5,12])
    585769            sage: J.elementary_divisors()
    586             [3, 60]
     770            (3, 60)
    587771            sage: G = AbelianGroup(2,[0,6])
    588772            sage: G.elementary_divisors()
    589             [6, 0]
     773            (6, 0)
    590774            sage: AbelianGroup([3,4,5]).elementary_divisors()
    591             [60]
     775            (60,)
    592776        """
    593777        from sage.matrix.constructor import diagonal_matrix
    594         ed = diagonal_matrix(ZZ, self.invariants()).elementary_divisors()
    595         return [d for d in ed if d!=1]
     778        ed = diagonal_matrix(ZZ, self.gens_orders()).elementary_divisors()
     779        return tuple(d for d in ed if d!=1)
    596780
     781    @cached_method
    597782    def exponent(self):
    598783        """
    599784        Return the exponent of this abelian group.
     
    601786        EXAMPLES::
    602787       
    603788            sage: G = AbelianGroup([2,3,7]); G
    604             Multiplicative Abelian Group isomorphic to C2 x C3 x C7
     789            Multiplicative Abelian group isomorphic to C2 x C3 x C7
    605790            sage: G.exponent()
    606791            42
    607792            sage: G = AbelianGroup([2,4,6]); G
    608             Multiplicative Abelian Group isomorphic to C2 x C4 x C6
     793            Multiplicative Abelian group isomorphic to C2 x C4 x C6
    609794            sage: G.exponent()
    610795            12
    611796        """
    612         try:
    613             return self.__exponent
    614         except AttributeError:
    615             self.__exponent = e = lcm(self.invariants())
    616             return e
    617            
     797        return lcm(self.gens_orders())
    618798   
    619799    def identity(self):
    620800        r"""
     
    633813            f0
    634814        """
    635815        return self(1)
    636 
    637816   
    638817    def _group_notation(self, eldv):
     818        """
     819        Return abstract group notation for generator orders ``eldv``
     820
     821        INPUT:
     822
     823        - ``eldv`` -- iterable of integers.
     824
     825        OUTPUT:
     826
     827        String.
     828
     829        EXAMPLES::
     830
     831            sage: G = AbelianGroup([2,2])
     832            sage: G._group_notation([0,1,2,3])
     833            'Z x C1 x C2 x C3'
     834        """
    639835        v = []
    640836        for x in eldv:
    641837            if x:
     
    652848       
    653849            sage: F = AbelianGroup(10, [2]*10)
    654850            sage: F._latex_()
    655             '$\\mathrm{AbelianGroup}( 10, [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] )$'
     851            '$\\mathrm{AbelianGroup}( 10, (2, 2, 2, 2, 2, 2, 2, 2, 2, 2) )$'
    656852        """
    657         s = "$\mathrm{AbelianGroup}( %s, %s )$"%(len(self.invariants()), self.invariants())
     853        s = "$\mathrm{AbelianGroup}( %s, %s )$"%(self.ngens(), self.gens_orders())
    658854        return s
    659855
    660856    def _gap_init_(self):
     
    669865            sage: gap(G)
    670866            Group( [ f1, f2, f3 ] )
    671867       
    672         Only works for finite groups.
    673        
    674         ::
     868        Only works for finite groups::
    675869       
    676870            sage: G = AbelianGroup(3,[0,3,4],names="abc"); G
    677             Multiplicative Abelian Group isomorphic to Z x C3 x C4
     871            Multiplicative Abelian group isomorphic to Z x C3 x C4
    678872            sage: G._gap_init_()
    679873            Traceback (most recent call last):
    680874            ...
     
    683877        # TODO: Use the package polycyclic has AbelianPcpGroup, which can handle
    684878        # the infinite case but it is a GAP package not GPL'd.
    685879        # Use this when the group is infinite...
    686         if (False and prod(self.invariants())==0):   # if False for now...
    687             return 'AbelianPcpGroup(%s)'%self.invariants()
     880        # return 'AbelianPcpGroup(%s)'%list(self.invariants())
    688881        if not self.is_finite():
    689             raise TypeError, "abelian groups in GAP are finite, but self is infinite"
    690         return 'AbelianGroup(%s)'%self.invariants()
     882            raise TypeError('abelian groups in GAP are finite, but self is infinite')
     883        return 'AbelianGroup(%s)'%list(self.gens_orders())
    691884
    692885    def gen(self, i=0):
    693886        """
     
    700893            a0
    701894            sage: F.2
    702895            a2
    703             sage: F.invariants()
    704             [0, 0, 0, 0, 0]
     896            sage: F.gens_orders()
     897            (0, 0, 0, 0, 0)
     898
     899            sage: G = AbelianGroup([2,1,3])
     900            sage: G.gens()
     901            (f0, 1, f2)
    705902        """
    706         n = self.__ngens
     903        n = self.ngens()
    707904        if i < 0 or i >= n:
    708905            raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)
    709         x = [0]*int(n)
    710         x[int(i)] = 1
    711         return AbelianGroupElement(self, x)
     906        x = [0]*n
     907        if self._gens_orders[i] != 1:
     908            x[i] = 1
     909        return self.element_class(x, self)
     910
     911    def gens(self):
     912        """
     913        Return the generators of the group.
     914
     915        OUTPUT:
     916
     917        A tuple of group elements. The generators according to the
     918        chosen :meth:`gens_orders`.
     919
     920        EXAMPLES::
     921
     922            sage: F = AbelianGroup(5,[3,2],names='abcde')
     923            sage: F.gens()
     924            (a, b, c, d, e)
     925            sage: [ g.order() for g in F.gens() ]
     926            [+Infinity, +Infinity, +Infinity, 3, 2]
     927        """
     928        return tuple( self.gen(i) for i in range(self.ngens()) )
     929
     930    def gens_orders(self):
     931        """
     932        Return the orders of the cyclic factors that this group has
     933        been defined with.
     934
     935        Use :meth:`elementary_divisors` if you are looking for an
     936        invariant of the group.
     937
     938        OUTPUT:
     939
     940        A tuple of integers.
     941
     942        EXAMPLES::
     943
     944            sage: Z2xZ3 = AbelianGroup([2,3])
     945            sage: Z2xZ3.gens_orders()
     946            (2, 3)
     947            sage: Z2xZ3.elementary_divisors()
     948            (6,)
     949
     950            sage: Z6 = AbelianGroup([6])
     951            sage: Z6.gens_orders()
     952            (6,)
     953            sage: Z6.elementary_divisors()
     954            (6,)
     955
     956            sage: Z2xZ3.is_isomorphic(Z6)
     957            True
     958            sage: Z2xZ3 is Z6
     959            False
     960
     961        TESTS::
     962
     963            sage: F = AbelianGroup(3, [2], names='abc')
     964            sage: map(type, F.gens_orders())
     965            [<type 'sage.rings.integer.Integer'>,
     966             <type 'sage.rings.integer.Integer'>,
     967             <type 'sage.rings.integer.Integer'>]
     968        """
     969        return self._gens_orders
    712970
    713971    def invariants(self):
    714972        """
    715         Return a copy of the list of invariants of this group.
    716        
    717         It is safe to modify the returned list.
     973        Return the orders of the cyclic factors that this group has
     974        been defined with.
     975
     976        For historical reasons this has been called invariants in
     977        Sage, even though they are not necessarily the invariant
     978        factors of the group. Use :meth:`gens_orders` instead::
     979
     980            sage: J = AbelianGroup([2,0,3,2,4]);  J
     981            Multiplicative Abelian group isomorphic to C2 x Z x C3 x C2 x C4
     982            sage: J.invariants()    # deprecated
     983            (2, 0, 3, 2, 4)
     984            sage: J.gens_orders()   # use this instead
     985            (2, 0, 3, 2, 4)
     986            sage: for i in range(J.ngens()):
     987            ...       print i, J.gen(i), J.gen(i).order()     # or use this
     988            0 f0 2
     989            1 f1 +Infinity
     990            2 f2 3
     991            3 f3 2
     992            4 f4 4
     993
     994        Use :meth:`elementary_divisors` if you are looking for an
     995        invariant of the group.
     996
     997        OUTPUT:
     998
     999        A tuple of integers. Zero means infinite cyclic factor.
    7181000       
    7191001        EXAMPLES::
    7201002       
    7211003            sage: J = AbelianGroup([2,3])
    7221004            sage: J.invariants()
    723             [2, 3]
    724             sage: v = J.invariants(); v
    725             [2, 3]
    726             sage: v[0] = 5
    727             sage: J.invariants()
    728             [2, 3]
    729             sage: J.invariants() is J.invariants()
    730             False
     1005            (2, 3)
     1006            sage: J.elementary_divisors()
     1007            (6,)
     1008
     1009        TESTS::
     1010
     1011            sage: F = AbelianGroup(3, [2], names='abc')
     1012            sage: map(type, F.gens_orders())
     1013            [<type 'sage.rings.integer.Integer'>,
     1014             <type 'sage.rings.integer.Integer'>,
     1015             <type 'sage.rings.integer.Integer'>]
    7311016        """
    732         return list(self.__invariants)
     1017        # TODO: deprecate
     1018        return self.gens_orders()
    7331019
    7341020    def is_cyclic(self):
    7351021        """
     
    7381024        EXAMPLES::
    7391025       
    7401026            sage: J = AbelianGroup([2,3])
    741             sage: J.invariants()
    742             [2, 3]
     1027            sage: J.gens_orders()
     1028            (2, 3)
    7431029            sage: J.elementary_divisors()
    744             [6]
     1030            (6,)
    7451031            sage: J.is_cyclic()
    7461032            True
    7471033            sage: G = AbelianGroup([6])
    748             sage: G.invariants()
    749             [6]
     1034            sage: G.gens_orders()
     1035            (6,)
    7501036            sage: G.is_cyclic()
    7511037            True
    7521038            sage: H = AbelianGroup([2,2])
    753             sage: H.invariants()
    754             [2, 2]
     1039            sage: H.gens_orders()
     1040            (2, 2)
    7551041            sage: H.is_cyclic()
    7561042            False
    7571043            sage: H = AbelianGroup([2,4])
    7581044            sage: H.elementary_divisors()
    759             [2, 4]
     1045            (2, 4)
    7601046            sage: H.is_cyclic()
    7611047            False
    7621048            sage: H.permutation_group().is_cyclic()
     
    7651051            sage: T.is_cyclic()
    7661052            True           
    7671053            sage: T = AbelianGroup(1,[0]); T
    768             Multiplicative Abelian Group isomorphic to Z
     1054            Multiplicative Abelian group isomorphic to Z
    7691055            sage: T.is_cyclic()
    7701056            True
    7711057            sage: B = AbelianGroup([3,4,5])
     
    7741060        """
    7751061        return len(self.elementary_divisors()) <= 1
    7761062
     1063    @cached_method
    7771064    def ngens(self):
    7781065        """
    7791066        The number of free generators of the abelian group.
     
    7841071            sage: F.ngens()
    7851072            10000
    7861073        """
    787         return self.__ngens
     1074        return len(self.gens_orders())
    7881075
     1076    @cached_method
    7891077    def order(self):
    7901078        """
    7911079        Return the order of this group.
     
    7991087            sage: G.order()
    8001088            +Infinity
    8011089        """
    802         try:
    803             return self.__len
    804         except AttributeError:
    805             from sage.rings.all import infinity, Integer
    806             if len(self.invariants()) < self.ngens():
    807                 self.__len = infinity
    808             else:
    809                 self.__len = Integer(prod(self.invariants()))
    810                 if self.__len == 0:
    811                     self.__len = infinity
    812         return self.__len
    813    
     1090        from sage.rings.all import infinity
     1091        length = prod(self.gens_orders())
     1092        if length == 0:
     1093            return infinity
     1094        return length
     1095
    8141096    def permutation_group(self):
    8151097        r"""
    8161098        Return the permutation group isomorphic to this abelian group.
     
    8221104        EXAMPLES::
    8231105       
    8241106            sage: G = AbelianGroup(2,[2,3]); G
    825             Multiplicative Abelian Group isomorphic to C2 x C3
     1107            Multiplicative Abelian group isomorphic to C2 x C3
    8261108            sage: G.permutation_group()
    8271109            Permutation Group with generators [(3,4,5), (1,2)]
    8281110        """
     
    8301112        s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()
    8311113        return PermutationGroup(gap_group=s)
    8321114
    833 
    8341115    def is_commutative(self):
    8351116        """
    8361117        Return True since this group is commutative.
     
    8471128
    8481129    def random_element(self):
    8491130        """
    850         Return a random element of this group. (Renamed random to
    851         random_element.)
     1131        Return a random element of this group.
    8521132       
    8531133        EXAMPLES::
    8541134       
    8551135            sage: G = AbelianGroup([2,3,9])
    8561136            sage: G.random_element()
    857             f0*f1^2*f2
     1137            f1^2
    8581138        """
    8591139        from sage.misc.prandom import randint
    860         if self.order() is infinity:
    861             NotImplementedError, "The group must be finite"
    862         gens = self.gens()
    863         g = gens[0]**0
    864         for i in range(len(gens)):
    865             g = g*gens[i]**(randint(1,gens[i].order()))
    866         return g
    867 
     1140        result = self.one()
     1141        for g in self.gens():
     1142            order = g.order()
     1143            if order not in ZZ:
     1144                order = 42  # infinite order; randomly chosen maximum
     1145            result *= g**(randint(0,order))
     1146        return result
    8681147
    8691148    def _repr_(self):
    870         eldv = self.invariants()
     1149        """
     1150        Return a string representation of ``self``.
     1151
     1152        EXAMPLES::
     1153
     1154            sage: G = AbelianGroup([2,3,9])
     1155            sage: G._repr_()
     1156            'Multiplicative Abelian group isomorphic to C2 x C3 x C9'
     1157       """
     1158        eldv = self.gens_orders()
    8711159        if len(eldv) == 0:
    872             return "Trivial Abelian Group"
     1160            return "Trivial Abelian group"
    8731161        g = self._group_notation(eldv)
    874         return "Multiplicative Abelian Group isomorphic to " + g
    875 
     1162        return "Multiplicative Abelian group isomorphic to " + g
    8761163
    8771164    def subgroup(self, gensH, names="f"):
    8781165        """
     
    8811168         
    8821169         INPUT:
    8831170         
    884          
    885          -  ``gensH`` - list of elements which are products of
    886             the generators of the ambient abelian group G = self
    887          
     1171         - ``gensH`` -- list of elements which are products of the
     1172            generators of the ambient abelian group G = self
    8881173         
    8891174         EXAMPLES::
    8901175         
    8911176             sage: G.<a,b,c> = AbelianGroup(3, [2,3,4]); G
    892              Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     1177             Multiplicative Abelian group isomorphic to C2 x C3 x C4
    8931178             sage: H = G.subgroup([a*b,a]); H
    894              Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    895              Multiplicative Abelian Group isomorphic to C2 x C3 x C4
    896              generated by [a*b, a]
     1179             Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a*b, a}
    8971180             sage: H < G
    8981181             True
    8991182             sage: F = G.subgroup([a,b^2])
    9001183             sage: F
    901              Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    902              Multiplicative Abelian Group isomorphic to C2 x C3 x C4
    903              generated by [a, b^2]
     1184             Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
    9041185             sage: F.gens()
    905              [a, b^2]
     1186             (a, b^2)
    9061187             sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
    9071188             sage: a,b,c,d,e = F.gens()
    9081189             sage: F.subgroup([a,b])
    909              Multiplicative Abelian Group isomorphic to Z x Z, which is
    910              the subgroup of Multiplicative Abelian Group isomorphic to
    911              Z x Z x C30 x C64 x C729 generated by [a, b]
     1190             Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b}
    9121191             sage: F.subgroup([c,e])
    913              Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
    914              C729, which is the subgroup of Multiplicative Abelian
    915              Group isomorphic to Z x Z x C30 x C64 x C729 generated by
    916              [c, e]
     1192             Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x C729 generated by {c, e}
    9171193         """
    918         if not isinstance(gensH, (list, tuple)):
    919             raise TypeError, "gensH = (%s) must be a list or tuple"%(gensH)
    920          
    9211194        G = self
    922         for i in range(len(gensH)):
    923             if not(gensH[i] in G):
    924                 raise TypeError, "Subgroup generators must belong to the given group."
     1195        gensH = tuple(gensH)
     1196        if isinstance(names, list):
     1197            names = tuple(names)
     1198        for h in gensH:
     1199            if h not in G:
     1200                raise TypeError('Subgroup generators must belong to the given group.')
    9251201        return AbelianGroup_subgroup(self, gensH, names)
    9261202
     1203    @cached_method
    9271204    def list(self):
    9281205        """
    929         Return list of all elements of this group.
     1206        Return tuple of all elements of this group.
    9301207       
    9311208        EXAMPLES::
    9321209       
    9331210            sage: G = AbelianGroup([2,3], names = "ab")
    9341211            sage: G.list()
    935             [1, b, b^2, a, a*b, a*b^2]
     1212            (1, b, b^2, a, a*b, a*b^2)
    9361213       
    9371214        ::
    9381215       
    9391216            sage: G = AbelianGroup([]); G
    940             Trivial Abelian Group
     1217            Trivial Abelian group
    9411218            sage: G.list()
    942             [1]
     1219            (1,)
    9431220        """
    944         try:
    945             return list(self.__list)
    946         except AttributeError:
    947             pass
    9481221        if not(self.is_finite()):
    9491222           raise NotImplementedError, "Group must be finite"
    950         self.__list = list(self.__iter__())
    951         return list(self.__list)
     1223        return tuple(self.__iter__())
    9521224     
    9531225    def __iter__(self):
    9541226        """
     
    9731245            [1]
    9741246            sage: G = AbelianGroup([])
    9751247            sage: G.list()
    976             [1]
     1248            (1,)
    9771249            sage: list(G)
    9781250            [1]
    9791251        """
    980         invs = self.invariants()
     1252        invs = self.gens_orders()
    9811253        for t in mrange(invs):
    982             yield AbelianGroupElement(self, t)
    983 
     1254            yield self(t)
    9841255
    9851256    def subgroups(self, check=False):
    9861257        r"""
     
    10101281        EXAMPLES::
    10111282
    10121283            sage: AbelianGroup([2,3]).subgroups()
    1013             [Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    1014             Multiplicative Abelian Group isomorphic to C2 x C3
    1015             generated by [f0*f1^2],
    1016              Multiplicative Abelian Group isomorphic to C2, which is the subgroup of
    1017             Multiplicative Abelian Group isomorphic to C2 x C3
    1018             generated by [f0],
    1019              Multiplicative Abelian Group isomorphic to C3, which is the subgroup of
    1020             Multiplicative Abelian Group isomorphic to C2 x C3
    1021             generated by [f1],
    1022              Trivial Abelian Group, which is the subgroup of
    1023             Multiplicative Abelian Group isomorphic to C2 x C3
    1024             generated by []]
    1025 
     1284            [Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {f0*f1^2},
     1285             Multiplicative Abelian subgroup isomorphic to C2 generated by {f0},
     1286             Multiplicative Abelian subgroup isomorphic to C3 generated by {f1},
     1287             Trivial Abelian subgroup]
    10261288            sage: len(AbelianGroup([2,4,8]).subgroups())
    10271289            81
    10281290
     1291        TESTS::
     1292
     1293            sage: AbelianGroup([]).subgroups()
     1294            [Trivial Abelian group]
    10291295        """
    10301296        if not self.is_finite(): raise ValueError, "Group must be finite"
    10311297        from sage.misc.misc import verbose
    10321298
    1033         v = self.invariants()
    1034        
    1035        
    1036         if len(v) <= 1:
    1037             if v == [] or v[0] == 1:
    1038                 return [self]
    1039             else:
    1040                 return [ self.subgroup([self.gen(0)**i]) for i in divisors(v[0])[:-1]] + [self.subgroup([])]
     1299        if self.is_trivial():
     1300            return [self]
     1301        if self.ngens() == 1:
     1302            n = self.gen(0).order()
     1303            return [ self.subgroup([self.gen(0)**i]) for i in divisors(n) ]
    10411304
     1305        v = self.gens_orders()
    10421306        A = AbelianGroup(v[:-1])
    10431307        x = v[-1]
    10441308
     
    10461310
    10471311        subgps = []
    10481312        for G in Wsubs:
    1049             verbose("G = subgp generated by %s" % G.gens())
    1050             verbose("invariants are:", [t.order() for t in G.gens()]) # G.invariants() doesn't work
     1313            verbose("G = subgp generated by %s" % list(G.gens()))
     1314            verbose("invariants are:", [t.order() for t in G.gens()])
    10511315            for H in divisors(x):
    10521316                # H = the subgroup of *index* H.
    10531317                its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))]
     
    10851349
    10861350            sage: G = AbelianGroup([4,4])
    10871351            sage: G.subgroup( [ G([1,0]), G([1,2]) ])
    1088             Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
    1089             Multiplicative Abelian Group isomorphic to C4 x C4
    1090             generated by [f0, f0*f1^2]
     1352            Multiplicative Abelian subgroup isomorphic to C2 x C4
     1353            generated by {f0, f0*f1^2}
    10911354            sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])
    1092             Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
    1093             Multiplicative Abelian Group isomorphic to C4 x C4
    1094             generated by [f1^2, f0]
     1355            Multiplicative Abelian subgroup isomorphic to C2 x C4
     1356            generated by {f1^2, f0}
    10951357        """
    10961358        from sage.matrix.constructor import matrix
    10971359        d = self.ngens()
     
    11021364            # can't happen?
    11031365            print "Vectors not LI: ", elts
    11041366            raise e
    1105         rel_lattice = X.span([X.gen(i) * self.invariants()[i] for i in xrange(d)])
     1367        rel_lattice = X.span([X.gen(i) * self.gens_orders()[i] for i in xrange(d)])
    11061368        isect = elt_lattice.intersection(rel_lattice)
    11071369        mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)
    11081370        D,U,V = mat.smith_form()
    11091371        new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i,i]) for i in xrange(U.ncols())]
    1110         return self.subgroup([self([x[0][i] % self.invariants()[i] for i in xrange(d)]) for x in new_basis if x[1] != 1])
     1372        return self.subgroup([self([x[0][i] % self.gens_orders()[i]
     1373                                    for i in xrange(d)]) for x in new_basis if x[1] != 1])
    11111374
    11121375class AbelianGroup_subgroup(AbelianGroup_class):
    11131376    """
     
    11261389            sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
    11271390            sage: a,b,c,d,e = F.gens()
    11281391            sage: F.subgroup([a^3,b])
    1129             Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of
    1130             Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
    1131             generated by [a^3, b]           
    1132        
    1133         ::
    1134        
     1392            Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a^3, b}
    11351393            sage: F.subgroup([c])
    1136             Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of
    1137             Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
    1138             generated by [c]
    1139        
    1140         ::
    1141        
    1142             sage: F.subgroup([a,c])
    1143             Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
    1144             Z, which is the subgroup of Multiplicative Abelian Group
    1145             isomorphic to Z x Z x C30 x C64 x C729 generated by [a, c]
    1146        
    1147         ::
    1148        
    1149             sage: F.subgroup([a,b*c])
    1150             Multiplicative Abelian Group isomorphic to Z x Z, which is
    1151             the subgroup of Multiplicative Abelian Group isomorphic to
    1152             Z x Z x C30 x C64 x C729 generated by [a, b*c]
    1153        
    1154         ::
    1155        
    1156             sage: F.subgroup([b*c,d])
    1157             Multiplicative Abelian Group isomorphic to C64 x Z, which
    1158             is the subgroup of Multiplicative Abelian Group isomorphic
    1159             to Z x Z x C30 x C64 x C729 generated by [b*c, d]
    1160        
    1161         ::
    1162        
    1163             sage: F.subgroup([a*b,c^6,d],names = list("xyz"))
    1164             Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
    1165             which is the subgroup of Multiplicative Abelian Group
    1166             isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
    1167             c^6, d]
    1168        
    1169         ::
    1170        
     1394            Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 generated by {c}
     1395            sage: F.subgroup([a, c])
     1396            Multiplicative Abelian subgroup isomorphic to C2 x C3 x C5 x Z generated by {a, c}
     1397            sage: F.subgroup([a, b*c])
     1398            Multiplicative Abelian subgroup isomorphic to Z x Z generated by {a, b*c}
     1399            sage: F.subgroup([b*c, d])
     1400            Multiplicative Abelian subgroup isomorphic to C64 x Z generated by {b*c, d}
     1401            sage: F.subgroup([a*b, c^6, d],names=list("xyz"))
     1402            Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}
    11711403            sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H
    1172             Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
    1173             which is the subgroup of Multiplicative Abelian Group
    1174             isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
    1175             c^6, d]
    1176        
    1177         ::
    1178        
    1179             sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G
    1180             Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
    1181             which is the subgroup of Multiplicative Abelian Group
    1182             isomorphic to Z x Z x C30 x C64 x C729 generated by [a*b,
    1183             c^6, d]
     1404            Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}
     1405            sage: G = F.subgroup([a*b, c^6, d],names = list("xyz")); G
     1406            Multiplicative Abelian subgroup isomorphic to C5 x C64 x Z generated by {a*b, c^6, d}
    11841407            sage: x,y,z = G.gens()
    11851408            sage: x.order()
    11861409            +Infinity
     
    11911414            sage: A = AbelianGroup(5,[3, 5, 5, 7, 8], names = "abcde")
    11921415            sage: a,b,c,d,e = A.gens()
    11931416            sage: A.subgroup([a,b])
    1194             Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of
    1195             Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1196             generated by [a, b]
     1417            Multiplicative Abelian subgroup isomorphic to C3 x C5 generated by {a, b}
    11971418            sage: A.subgroup([a,b,c,d^2,e])
    1198             Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of
    1199             Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1200             generated by [a, b, c, d^2, e]
    1201             sage: A.subgroup([a,b,c,d^2,e^2])
    1202             Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of
    1203             Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1204             generated by [a, b, c, d^2, e^2]
    1205             sage: B = A.subgroup([a^3,b,c,d,e^2]); B
    1206             Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of
    1207             Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1208             generated by [b, c, d, e^2]
    1209             sage: B.invariants()
    1210             [4, 5, 5, 7]
     1419            Multiplicative Abelian subgroup isomorphic to C3 x C5 x C5 x C7 x C8 generated by {a, b, c, d^2, e}
     1420            sage: A.subgroup([a, b, c, d^2, e^2])
     1421            Multiplicative Abelian subgroup isomorphic to C3 x C4 x C5 x C5 x C7 generated by {a, b, c, d^2, e^2}
     1422            sage: B = A.subgroup([a^3, b, c, d, e^2]); B
     1423            Multiplicative Abelian subgroup isomorphic to C4 x C5 x C5 x C7 generated by {b, c, d, e^2}
     1424            sage: B.gens_orders()
     1425            (4, 5, 5, 7)
    12111426            sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd")
    12121427            sage: a,b,c,d = A.gens()
    12131428            sage: B = A.subgroup([a^3,b,c,d])
    1214             sage: B.invariants()
    1215             [1009, 2003, 3001, 4001]
     1429            sage: B.gens_orders()
     1430            (1009, 2003, 3001, 4001)
    12161431            sage: A.order()
    12171432            24266473210027
    12181433            sage: B.order()
     
    12201435            sage: A = AbelianGroup(4,[1008, 2003, 3001, 4001], names = "abcd")
    12211436            sage: a,b,c,d = A.gens()
    12221437            sage: B = A.subgroup([a^3,b,c,d]); B
    1223             Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x
    1224             C2003 x C3001 x C4001, which is the subgroup of
    1225             Multiplicative Abelian Group isomorphic to C1008 x C2003 x
    1226             C3001 x C4001 generated by [a^3, b, c, d]
     1438            Multiplicative Abelian subgroup isomorphic
     1439            to C3 x C7 x C16 x C2003 x C3001 x C4001 generated by {a^3, b, c, d}
    12271440       
    12281441        Infinite groups can also be handled::
    12291442       
    12301443            sage: G = AbelianGroup([3,4,0], names = "abc")
    12311444            sage: a,b,c = G.gens()
    1232             sage: F = G.subgroup([a,b^2,c]); F
    1233             Multiplicative Abelian Group isomorphic to C2 x C3 x Z,
    1234             which is the subgroup of Multiplicative Abelian Group
    1235             isomorphic to C3 x C4 x Z generated by [a, b^2, c]
     1445            sage: F = G.subgroup([a, b^2, c]); F
     1446            Multiplicative Abelian subgroup isomorphic to C2 x C3 x Z generated by {a, b^2, c}
    12361447       
    1237         ::
    1238        
    1239             sage: F.invariants()
    1240             [2, 3, 0]
     1448            sage: F.gens_orders()
     1449            (2, 3, 0)
    12411450            sage: F.gens()
    1242             [a, b^2, c]
     1451            (a, b^2, c)
    12431452            sage: F.order()
    12441453            +Infinity
    12451454        """
    12461455        from sage.interfaces.all import gap
    12471456        if not isinstance(ambient, AbelianGroup_class):
    12481457            raise TypeError, "ambient (=%s) must be an abelian group."%ambient
    1249         if not isinstance(gens, list):
    1250             raise TypeError, "gens (=%s) must be a list"%gens
     1458        if not isinstance(gens, tuple):
     1459            raise TypeError, "gens (=%s) must be a tuple"%gens
    12511460           
    1252         self.__ambient_group = ambient
    1253         Hgens = [x for x in gens if x != ambient(1)]  ## in case someone puts 1 in the list of generators
    1254         self.__gens = Hgens
     1461        self._ambient_group = ambient
     1462        Hgens = tuple(x for x in gens if x != ambient.one())  ## in case someone puts 1 in the list of generators
     1463        self._gens = Hgens
    12551464        m = len(gens)
    12561465        ell = len(ambient.gens())
    1257         ambient_invs = ambient.invariants()
     1466        ambient_invs = ambient.gens_orders()
    12581467        invsf = [x for x in ambient_invs if x > 0]    ## fixes the problem with
    12591468        invs0 = [x for x in ambient_invs if x == 0]   ## the infinite parts
    12601469        Ggens = list(ambient.variable_names())
     
    12641473            Ggens0 = [x for x in ambient.variable_names() if
    12651474                        ambient_invs[Ggens.index(x)] == 0]
    12661475            ##     ^^ only look at "finite" names
    1267             Gf = AbelianGroup_class(len(invsf), invsf, names = Gfgens)
     1476            Gf = AbelianGroup(invsf, names=Gfgens)
    12681477            s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_()
    12691478            gap.eval(s1)
    12701479            Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0]
     
    12741483            for i in range(len(Gfgens)):
    12751484               cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i]
    12761485               gap.eval(cmd)
    1277         if invs0==[]:
    1278            Hgensf = Hgens
    1279            Hgens0 = []  # added for consistency
    1280            G = ambient
    1281            s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()
    1282            gap.eval(s1)
    1283            for i in range(len(Ggens)):
    1284                cmd = '%s := gens[%s]'%(Ggens[i], i+1)
    1285                #print i,"  \n",cmd
    1286                gap.eval(cmd)
    1287         s2 = "gensH:=%s"%Hgensf #### remove from this the ones <--> 0 invar
     1486        else:  # invs0==[]:
     1487            Hgensf = Hgens
     1488            Hgens0 = []  # added for consistency
     1489            G = ambient
     1490            s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()
     1491            gap.eval(s1)
     1492            for i in range(len(Ggens)):
     1493                cmd = '%s := gens[%s]'%(Ggens[i], i+1)
     1494                #print i,"  \n",cmd
     1495                gap.eval(cmd)
     1496        s2 = "gensH:=%s"%list(Hgensf) #### remove from this the ones <--> 0 invar
    12881497        gap.eval(s2)
    12891498        s3 = 'H:=Subgroup(G,gensH)'
    12901499        gap.eval(s3)
    12911500        # a GAP command which returns the "invariants" of the
    12921501        # subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)),
    12931502        # works if G is the subgroup declared as a AbelianPcpGroup
    1294         self.__abinvs = eval(gap.eval("AbelianInvariants(H)"))
    1295         invs = self.__abinvs
     1503        self._abinvs = eval(gap.eval("AbelianInvariants(H)"))
     1504        invs = self._abinvs
    12961505        #print s3, invs
    12971506        if Hgens0 != []:
    12981507            for x in Hgens0:
    12991508               invs.append(0)
    1300         #print Hgensf, invs, invs0
    1301         AbelianGroup_class.__init__(self, len(invs), invs, names)
     1509        invs = tuple(ZZ(i) for i in invs)
     1510        AbelianGroup_class.__init__(self, invs, names)
    13021511
    13031512    def __contains__(self, x):
    13041513        """
    1305         Return True if `x` is an element of this subgroup.
     1514        Test whether ``x`` is an element of this subgroup.
    13061515       
    13071516        EXAMPLES::
    13081517       
     
    13181527        if x.parent() is self:
    13191528            return True
    13201529        elif x in self.ambient_group():
    1321             amb_inv = self.ambient_group().invariants()
     1530            amb_inv = self.ambient_group().gens_orders()
    13221531            for a in xrange(len(amb_inv)):
    13231532                if amb_inv[a] == 0 and x.list()[a] != 0:
    1324                     for g in self.__gens:
     1533                    for g in self._gens:
    13251534                        if g.list()[a] == 0:
    13261535                            continue
    13271536                        if abs(x.list()[a]%g.list()[a]) < abs(x.list()[a]):
     
    13321541                        if x.list()[a] == 0:
    13331542                            break
    13341543                elif x.list()[a] != 0:
    1335                     for g in self.__gens:
     1544                    for g in self._gens:
    13361545                        if g.list()[a] == 0:
    13371546                            continue
    13381547                        if abs(x.list()[a]%g.list()[a])%abs(amb_inv[a]) < x.list()[a]%abs(amb_inv[a]):
     
    13441553    def ambient_group(self):
    13451554        """
    13461555        Return the ambient group related to self.
     1556
     1557        OUTPUT:
     1558
     1559        A multiplicative Abelian group.
     1560
     1561        EXAMPLES::
     1562
     1563            sage: G.<a,b,c> = AbelianGroup([2,3,4])
     1564            sage: H = G.subgroup([a, b^2])
     1565            sage: H.ambient_group() is G
     1566            True
    13471567        """
    1348         return self.__ambient_group
     1568        return self._ambient_group
    13491569
    1350     def __eq__(self, right):
     1570    def equals(left, right):
    13511571        """
    1352         ::
     1572        Check whether ``left`` and ``right`` are the same (sub)group.
     1573
     1574        INPUT:
     1575
     1576        - ``right`` -- anything.
     1577
     1578        OUTPUT:
     1579
     1580        Boolean. If ``right`` is a subgroup, test whether ``left`` and
     1581        ``right`` are the same subset of the ambient group. If
     1582        ``right`` is not a subgroup, test whether they are isomorphic
     1583        groups, see :meth:`~AbelianGroup_class.is_isomorphic`.
     1584
     1585        EXAMPLES::
    13531586       
    13541587            sage: G = AbelianGroup(3, [2,3,4], names="abc"); G
    1355             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     1588            Multiplicative Abelian group isomorphic to C2 x C3 x C4
    13561589            sage: a,b,c = G.gens()
    1357             sage: F=G.subgroup([a,b^2]); F
    1358             Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    1359             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
    1360             generated by [a, b^2]
     1590            sage: F = G.subgroup([a,b^2]); F
     1591            Multiplicative Abelian subgroup isomorphic to C2 x C3 generated by {a, b^2}
    13611592            sage: F<G
    13621593            True
    13631594       
    1364         ::
    1365        
    13661595            sage: A = AbelianGroup(1, [6])
    13671596            sage: A.subgroup(list(A.gens())) == A
    13681597            True
    13691598       
    1370         ::
    1371        
    13721599            sage: G.<a,b> = AbelianGroup(2)
    13731600            sage: A = G.subgroup([a])
    13741601            sage: B = G.subgroup([b])
    1375             sage: A == B
     1602            sage: A.equals(B)
    13761603            False
     1604            sage: A == B        # sames as A.equals(B)
     1605            False
     1606            sage: A.is_isomorphic(B)
     1607            True
    13771608        """
    1378         if not is_AbelianGroup(right):
    1379             return -1
    1380         return self <= right and right <= self
    1381    
     1609        left_ambient = left.ambient_group()
     1610        try:
     1611            right_ambient = right.ambient_group()
     1612        except AttributeError:
     1613            # right is not a subgroup
     1614            return left.is_isomorphic(right)
     1615        if left_ambient is not right_ambient:
     1616            return False
     1617        return left <= right and right <= left
     1618
     1619    __eq__ = equals
     1620
    13821621    def _repr_(self):
    1383         return '%s, which is the subgroup of\n%s\ngenerated by %s'%(
    1384             AbelianGroup_class._repr_(self),
    1385             self.ambient_group(),
    1386             self.gens())
     1622        """
     1623        Return a string representation
     1624
     1625        EXAMPLES::
     1626
     1627            sage: G.<a,b> = AbelianGroup(2)
     1628            sage: G._repr_()
     1629            'Multiplicative Abelian group isomorphic to Z x Z'
     1630            sage: A = G.subgroup([a])
     1631            sage: A._repr_()
     1632            'Multiplicative Abelian subgroup isomorphic to Z generated by {a}'
     1633       """
     1634        eldv = self.gens_orders()
     1635        if self.is_trivial():
     1636            return "Trivial Abelian subgroup"
     1637        s = 'Multiplicative Abelian subgroup isomorphic to '
     1638        s += self._group_notation(eldv)
     1639        s += ' generated by '
     1640        s += '{' + ', '.join(map(str, self.gens())) + '}'
     1641        return s
    13871642       
    1388     def invs(self):
    1389         """
    1390         Return the invariants for this subgroup.
    1391         """
    1392         G = self.ambient_group()
    1393         invsG = G.invariants()
    1394         Hgap = self._gap_init_()
    1395        
    1396 
    13971643    def gens(self):
    13981644        """
    13991645        Return the generators for this subgroup.
     1646
     1647        OUTPUT:
     1648
     1649        A tuple of group elements generating the subgroup.
     1650
     1651        EXAMPLES::
     1652
     1653            sage: G.<a,b> = AbelianGroup(2)
     1654            sage: A = G.subgroup([a])
     1655            sage: G.gens()
     1656            (a, b)
     1657            sage: A.gens()
     1658            (a,)
    14001659        """
    1401         return self.__gens
     1660        return self._gens
    14021661
    14031662    def gen(self, n):
    14041663        """
     
    14111670            sage: A.gen(0)
    14121671            a
    14131672        """
    1414         return self.__gens[n]
     1673        return self._gens[n]
    14151674
  • sage/groups/abelian_gps/abelian_group_element.py

    diff --git a/sage/groups/abelian_gps/abelian_group_element.py b/sage/groups/abelian_gps/abelian_group_element.py
    a b  
    1111
    1212- David Joyner (2009-02): Fixed bug in order.
    1313
    14 EXAMPLES: Recall an example from abelian groups.
     14- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.
    1515
    16 ::
     16
     17EXAMPLES:
     18
     19Recall an example from abelian groups::
    1720
    1821    sage: F = AbelianGroup(5,[4,5,5,7,8],names = list("abcde"))
    1922    sage: (a,b,c,d,e) = F.gens()
     
    3033    a^3*b*c*d^5*e^4
    3134    sage: x.list()
    3235    [2, 2, 3, 6, 4]
    33 
    34 It is important to note that lists are mutable and the returned
    35 list is not a copy. As a result, reassignment of an element of the
    36 list changes the object.
    37 
    38 ::
    39 
    40     sage: x.list()[0] = 3
    41     sage: x.list()
    42     [3, 2, 3, 6, 4]
    43     sage: x
    44     a^3*b^2*c^3*d^6*e^4
    4536"""
    4637
    4738###########################################################################
    4839#  Copyright (C) 2006 William Stein <wstein@gmail.com>
    49 #  Copyright (C) 2006 David Joyner
     40#  Copyright (C) 2006 David Joyner  <wdjoyner@gmail.com>
     41#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
    5042#
    5143#  Distributed under the terms of the GNU General Public License (GPL)
    5244#                  http://www.gnu.org/licenses/
     
    5446
    5547
    5648from sage.rings.integer import Integer
    57 from sage.structure.element import MultiplicativeGroupElement
    5849from sage.rings.infinity import infinity
    5950from sage.rings.arith import LCM, GCD
     51from sage.groups.abelian_gps.element_base import AbelianGroupElementBase
    6052
    6153def is_AbelianGroupElement(x):
    6254    """
     
    7567    """
    7668    return isinstance(x, AbelianGroupElement)
    7769
    78 class AbelianGroupElement(MultiplicativeGroupElement):
    79     def __init__(self, F, x):
    80         """
    81         Create the element x of the AbelianGroup F.
     70
     71class AbelianGroupElement(AbelianGroupElementBase):
     72    """
     73    Elements of an
     74    :class:`~sage.groups.abelian_gps.abelian_group.AbelianGroup`
     75
     76    INPUT:
     77
     78    - ``x`` -- list/tuple/iterable of integers (the element vector)
     79
     80    - ``parent`` -- the parent
     81      :class:`~sage.groups.abelian_gps.abelian_group.AbelianGroup`
    8282       
    83         EXAMPLES::
     83    EXAMPLES::
    8484       
    85             sage: F = AbelianGroup(5, [3,4,5,8,7], 'abcde')
    86             sage: a, b, c, d, e = F.gens()
    87             sage: a^2 * b^3 * a^2 * b^-4
    88             a*b^3
    89             sage: b^-11
    90             b
    91             sage: a^-11
    92             a
    93             sage: a*b in F
    94             True
    95         """
    96         MultiplicativeGroupElement.__init__(self, F)
    97         self.__repr = None
    98         n = F.ngens()
    99         if isinstance(x, (int, Integer)) and x == 1:
    100             self.__element_vector = [ 0 for i in range(n) ]
    101         elif isinstance(x, list):
    102             if len(x) != n:
    103                 raise IndexError, \
    104                       "Argument length (= %s) must be %s."%(len(x), n)
    105             self.__element_vector = x
    106         else:
    107             raise TypeError, "Argument x (= %s) is of wrong type."%x
    108              
    109     def _repr_(self):
    110         """
    111         EXAMPLES::
    112        
    113             sage: AbelianGroupElement(AbelianGroup(1, [1], names='e'),[0])
    114             1
    115             sage: AbelianGroupElement(AbelianGroup(3, [2,3,4], names='e'),[1,2,3])
    116             e0*e1^2*e2^3
    117         """
    118         s = ""
    119         A = self.parent()
    120         n = A.ngens()
    121         x = A.variable_names()
    122         v = self.__element_vector
    123         for i in range(n):
    124             if v[i] == 0:
    125                 continue
    126             elif v[i] == 1:
    127                 if len(s) > 0: s += "*"
    128                 s += "%s"%x[i]
    129             else:
    130                 if len(s) > 0: s += "*"
    131                 s += "%s^%s"%(x[i],v[i])
    132         if len(s) == 0: s = str(1)
    133         return s
    134 
    135     def _div_(self, y):
    136         """
    137         TESTS::
    138        
    139             sage: G.<a,b> = AbelianGroup(2)
    140             sage: a/b
    141             a*b^-1
    142         """
    143         return self*y.inverse()
    144 
    145     def _mul_(self, y):
    146         #Same as _mul_ in FreeAbelianMonoidElement except that the
    147         #exponents get reduced mod the invariant.
    148        
    149         M = self.parent()
    150         n = M.ngens()
    151         invs = M.invariants()
    152         z = M(1)
    153         xelt = self.__element_vector
    154         yelt = y.__element_vector
    155         zelt = [ xelt[i]+yelt[i] for i in range(len(xelt)) ]
    156         if len(invs) >= n:
    157             L =  []
    158             for i in range(len(xelt)):
    159                 if invs[i]!=0:
    160                     L.append(zelt[i]%invs[i])
    161                 if invs[i]==0:
    162                     L.append(zelt[i])
    163             z.__element_vector = L
    164         if len(invs) < n:
    165             L1 =  []
    166             for i in range(len(invs)):
    167                 if invs[i]!=0:
    168                     L1.append(zelt[i]%invs[i])
    169                 if invs[i]==0:
    170                     L1.append(zelt[i])
    171             L2 =  [ zelt[i] for i in range(len(invs),len(xelt)) ]
    172             z.__element_vector = L1+L2
    173         return z
    174 
    175     def __pow__(self, _n):
    176         """
    177         requires that len(invs) = n
    178         """
    179         n = int(_n)
    180         if n != _n:
    181             raise TypeError, "Argument n (= %s) must be an integer."%n
    182         M = self.parent()
    183         N = M.ngens()
    184         invs = M.invariants()
    185         z = M(1)
    186         for i in xrange(len(invs)):
    187             if invs[i] == 0:
    188                 z.__element_vector[i] = self.__element_vector[i]*n
    189             else:
    190                 z.__element_vector[i] = (self.__element_vector[i]*n)%invs[i]
    191         return z
    192 
    193     def inverse(self):
    194         """
    195         Returns the inverse element.
    196        
    197         EXAMPLE::
    198        
    199             sage: G.<a,b> = AbelianGroup(2)
    200             sage: a^-1
    201             a^-1
    202             sage: a.list()
    203             [1, 0]
    204             sage: a.inverse().list()
    205             [-1, 0]
    206             sage: a.inverse()
    207             a^-1
    208         """
    209         new_list = [-1*n for n in self.list()]
    210         par_inv = self.parent().invariants()
    211         for i in xrange(len(par_inv)):
    212             if par_inv[i] != 0 and new_list[i] < 0:
    213                 while new_list[i] < 0:
    214                     new_list[i] += abs(par_inv[i])
    215         return AbelianGroupElement(self.parent(), new_list)
     85        sage: F = AbelianGroup(5, [3,4,5,8,7], 'abcde')
     86        sage: a, b, c, d, e = F.gens()
     87        sage: a^2 * b^3 * a^2 * b^-4
     88        a*b^3
     89        sage: b^-11
     90        b
     91        sage: a^-11
     92        a
     93        sage: a*b in F
     94        True
     95    """
    21696
    21797    def as_permutation(self):
    21898        r"""
     
    222102        EXAMPLES::
    223103       
    224104            sage: G = AbelianGroup(3,[2,3,4],names="abc"); G
    225             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     105            Multiplicative Abelian group isomorphic to C2 x C3 x C4
    226106            sage: a,b,c=G.gens()
    227107            sage: Gp = G.permutation_group(); Gp
    228108            Permutation Group with generators [(6,7,8,9), (3,4,5), (1,2)]
     
    236116        from sage.groups.perm_gps.permgroup import PermutationGroup
    237117        from sage.interfaces.all import gap
    238118        G = self.parent()
    239         invs = G.invariants()
     119        invs = list(G.gens_orders())
    240120        s1 = 'A:=AbelianGroup(%s)'%invs
    241121        gap.eval(s1)
    242122        s2 = 'phi:=IsomorphismPermGroup(A)'
     
    252132        gp = Gp(pg)
    253133        return gp
    254134
    255     def list(self):
    256         """
    257         Return (a reference to) the underlying list used to represent this
    258         element. If this is a word in an abelian group on `n`
    259         generators, then this is a list of nonnegative integers of length
    260         `n`.
    261        
    262         EXAMPLES::
    263        
    264             sage: F = AbelianGroup(5, [3,4,5,8,7], 'abcde')
    265             sage: (a, b, c, d, e) = F.gens()
    266             sage: a.list()
    267             [1, 0, 0, 0, 0]
    268         """
    269         return self.__element_vector
    270 
    271     def __cmp__(self,other):
    272         if (self.list() != other.list()):
    273                 return -1
    274         return 0
    275                        
    276     def order(self):
    277         """
    278         Returns the (finite) order of this element or Infinity if this
    279         element does not have finite order.
    280        
    281         EXAMPLES::
    282        
    283             sage: F = AbelianGroup(3,[7,8,9]); F
    284             Multiplicative Abelian Group isomorphic to C7 x C8 x C9
    285             sage: F.gens()[2].order()
    286             9
    287             sage: a,b,c = F.gens()
    288             sage: (b*c).order()
    289             72
    290             sage: G = AbelianGroup(3,[7,8,9])
    291             sage: type((G.0 * G.1).order())==Integer
    292             True
    293         """
    294         M = self.parent()
    295         if self == M(1):
    296             return Integer(1)
    297         invs = M.invariants()
    298         if self in M.gens():
    299             o = invs[list(M.gens()).index(self)]
    300             if o == 0:
    301                 return infinity
    302             return o
    303         L = list(self.list())
    304         N = LCM([invs[i]//GCD(invs[i],L[i]) for i in range(len(invs)) if L[i]!=0])
    305         if N == 0:
    306             return infinity
    307         else:
    308             return Integer(N)
    309 
    310     def random_element(self):
    311         """
    312         Return a random element of this dual group.
    313         """
    314         if not(self.is_finite()):
    315             raise NotImplementedError, "Only implemented for finite groups"
    316         gens = self.gens()
    317         g = gens[0]**0
    318         for i in range(len(gens)):
    319             g = g*gens[i]**(random(gens[i].order()))
    320         return g
    321    
    322 
    323 
    324135    def word_problem(self, words):
    325136        """
    326137        TODO - this needs a rewrite - see stuff in the matrix_grp
     
    351162            [[x, 1], [y, 1]]
    352163            sage: prod([x^i for x,i in v]) == y*x
    353164            True
    354 
    355165        """
    356166        from sage.groups.abelian_gps.abelian_group import AbelianGroup, word_problem
    357167        return word_problem(words,self)
  • sage/groups/abelian_gps/abelian_group_morphism.py

    diff --git a/sage/groups/abelian_gps/abelian_group_morphism.py b/sage/groups/abelian_gps/abelian_group_morphism.py
    a b  
    3535    A set-theoretic map between AbelianGroups.
    3636    """
    3737    def __init__(self, parent):
     38        """
     39        The Python constructor.
     40        """
    3841        Morphism.__init__(self, parent)
    3942
    4043    def _repr_type(self):
     
    5255    def _repr_defn(self):
    5356        return "Identity map of "+str(X)
    5457
    55 class AbelianGroupMorphism:
     58class AbelianGroupMorphism(Morphism):
    5659    """
    5760    Some python code for wrapping GAP's GroupHomomorphismByImages
    5861    function for abelian groups. Returns "fail" if gens does not
     
    6265    EXAMPLES::
    6366   
    6467        sage: G = AbelianGroup(3,[2,3,4],names="abc"); G
    65         Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     68        Multiplicative Abelian group isomorphic to C2 x C3 x C4
    6669        sage: a,b,c = G.gens()
    6770        sage: H = AbelianGroup(2,[2,3],names="xy"); H
    68         Multiplicative Abelian Group isomorphic to C2 x C3
     71        Multiplicative Abelian group isomorphic to C2 x C3
    6972        sage: x,y = H.gens()
    7073   
    7174    ::
     
    97100#TypeError: Sorry, the list [a*b, c^2] must generate G.
    98101
    99102    def __init__(self, G, H, genss, imgss ):
     103        from sage.categories.homset import Hom
     104        Morphism.__init__(self, Hom(G, H))
    100105        if len(genss) != len(imgss):
    101106            raise TypeError, "Sorry, the lengths of %s, %s must be equal."%(genss,imgss)
    102107        self._domain = G
     
    108113        G_domain = G.subgroup(genss)
    109114        if G_domain.order() != G.order():
    110115            raise TypeError, "Sorry, the list %s must generate G."%genss
    111         self.domain_invs = G.invariants()
    112         self.codomaininvs = H.invariants()
     116        # self.domain_invs = G.gens_orders()
     117        # self.codomaininvs = H.gens_orders()
    113118        self.domaingens = genss
    114119        self.codomaingens = imgss
    115120        #print genss, imgss
     
    124129        EXAMPLES::
    125130       
    126131            sage: G = AbelianGroup(3,[2,3,4],names="abc"); G
    127             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     132            Multiplicative Abelian group isomorphic to C2 x C3 x C4
    128133            sage: a,b,c = G.gens()
    129134            sage: H = AbelianGroup(2,[2,3],names="xy"); H
    130             Multiplicative Abelian Group isomorphic to C2 x C3
     135            Multiplicative Abelian group isomorphic to C2 x C3
    131136            sage: x,y = H.gens()
    132137            sage: phi = AbelianGroupMorphism(H,G,[x,y],[a,b])
    133138            sage: phi._gap_init_()
    134139            'phi := GroupHomomorphismByImages(G,H,[x, y],[a, b])'
    135140        """
    136141        G  = (self.domain())._gap_init_()
    137         H  = (self.range())._gap_init_()
     142        H  = (self.codomain())._gap_init_()
    138143        # print G,H
    139144        s3 = 'G:=%s; H:=%s'%(G,H)
    140145        #print s3,"\n"
    141146        gap.eval(s3)
    142147        gensG = self.domain().variable_names()                    ## the Sage group generators
    143         gensH = self.range().variable_names()
     148        gensH = self.codomain().variable_names()
    144149        #print gensG, gensH
    145150        s1 = "gensG := GeneratorsOfGroup(G)"          ## the GAP group generators
    146151        gap.eval(s1)
     
    163168    def _repr_type(self):
    164169        return "AbelianGroup"
    165170
    166     def domain(self):
    167         return self._domain
    168 
    169     def range(self):
    170         return self._codomain
    171 
    172     def codomain(self):
    173         return self._codomain
    174 
    175171    def kernel(self):
    176172        """
    177173        Only works for finite groups.
     
    182178        EXAMPLES::
    183179       
    184180            sage: H = AbelianGroup(3,[2,3,4],names="abc"); H
    185             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     181            Multiplicative Abelian group isomorphic to C2 x C3 x C4
    186182            sage: a,b,c = H.gens()
    187183            sage: G = AbelianGroup(2,[2,3],names="xy"); G
    188             Multiplicative Abelian Group isomorphic to C2 x C3
     184            Multiplicative Abelian group isomorphic to C2 x C3
    189185            sage: x,y = G.gens()
    190186            sage: phi = AbelianGroupMorphism(G,H,[x,y],[a,b])
    191187            sage: phi.kernel()
     
    218214        L = [self(g) for g in gensJ]
    219215        return G.subgroup(L)
    220216
    221     def __call__( self, g ):
     217    def _call_( self, g ):
    222218        """
    223219        Some python code for wrapping GAP's Images function but only for
    224220        permutation groups. Returns an error if g is not in G.
  • sage/groups/abelian_gps/all.py

    diff --git a/sage/groups/abelian_gps/all.py b/sage/groups/abelian_gps/all.py
    a b  
    2020#                  http://www.gnu.org/licenses/
    2121#*****************************************************************************
    2222
    23 from dual_abelian_group import *
    24 from dual_abelian_group_element import *
     23#from dual_abelian_group import DualAbelianGroup
     24from abelian_group import AbelianGroup, is_AbelianGroup, word_problem
     25from values import AbelianGroupWithValues
    2526
    26 from abelian_group import AbelianGroup,is_AbelianGroup,AbelianGroup_class,AbelianGroup_subgroup, word_problem
    27 
    28 from abelian_group_element import AbelianGroupElement,is_AbelianGroupElement
    29 
    30 from abelian_group_morphism import is_AbelianGroupMorphism,AbelianGroupMap,AbelianGroupMorphism_id,AbelianGroupMorphism,AbelianGroupMorphism
    31 
     27# TODO:
     28# Implement group homset, conversion of generator images to morphism
     29from abelian_group_morphism import AbelianGroupMorphism
  • sage/groups/abelian_gps/dual_abelian_group.py

    diff --git a/sage/groups/abelian_gps/dual_abelian_group.py b/sage/groups/abelian_gps/dual_abelian_group.py
    a b  
    11r"""
    2 Basic functionality for dual groups of finite multiplicative Abelian groups
     2Dual groups of Finite Multiplicative Abelian Groups
     3
     4The basic idea is very simple. Let G be an abelian group and `G^*` its
     5dual (i.e., the group of homomorphisms from G to `\CC^\times`). Let
     6`g_j`, `j=1,..,n`, denote generators of `G` - say `g_j` is of order
     7`m_j>1`. There are generators `X_j`, `j=1,..,n`, of `G^*` for which
     8`X_j(g_j)=\exp(2\pi i/m_j)` and `X_i(g_j)=1` if `i\not= j`. These are
     9used to construct `G^*`.
     10
     11Sage supports multiplicative abelian groups on any prescribed finite
     12number `n > 0` of generators. Use
     13:func:`~sage.groups.abelian_gps.abelian_group.AbelianGroup` function
     14to create an abelian group, the
     15:meth:`~sage.groups.abelian_gps.abelian_group.AbelianGroup_class.dual_group`
     16method to create its dual, and then the :meth:`gen` and :meth:`gens`
     17methods to obtain the corresponding generators. You can print the
     18generators as arbitrary strings using the optional ``names`` argument
     19to the
     20:meth:`~sage.groups.abelian_gps.abelian_group.AbelianGroup_class.dual_group`
     21method.
     22
     23EXAMPLES::
     24
     25    sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
     26    sage: (a, b, c, d, e) = F.gens()
     27
     28    sage: Fd = F.dual_group(names='ABCDE')
     29    sage: Fd.base_ring()
     30    Cyclotomic Field of order 2520 and degree 576
     31    sage: A,B,C,D,E = Fd.gens()
     32    sage: A(a)
     33    -1
     34    sage: A(b), A(c), A(d), A(e)
     35    (1, 1, 1, 1)
     36
     37    sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)
     38    sage: A,B,C,D,E = Fd.gens()
     39    sage: A(a)    # abs tol 1e-8
     40    -1.00000000000000 + 0.00000000000000*I
     41    sage: A(b); A(c); A(d); A(e)
     42    1.00000000000000
     43    1.00000000000000
     44    1.00000000000000
     45    1.00000000000000
    346
    447AUTHORS:
    548
     
    750
    851- David Joyner (2006-10) modifications suggested by William Stein
    952
    10 TODO:
    11 
    12 - additive abelian groups should also be supported.
    13 
    14 The basic idea is very simple. Let G be an abelian group and
    15 `G^*` its dual (i.e., the group of homomorphisms from G to
    16 `\CC^\times`). Let `g_j`,
    17 `j=1,..,n`, denote generators of `G` - say
    18 `g_j` is of order `m_j>1`. There are generators
    19 `X_j`, `j=1,..,n`, of `G^*` for which
    20 `X_j(g_j)=\exp(2\pi i/m_j)` and `X_i(g_j)=1`
    21 if `i\not= j`. These are used to construct `G^*` in
    22 the DualAbelianGroup class below.
    23 
    24 Sage supports multiplicative abelian groups on any prescribed
    25 finite number `n > 0` of generators. Use the
    26 ``AbelianGroup`` function to create an abelian group,
    27 the ``DualAbelianGroup`` function to create its dual,
    28 and then the ``gen`` and ``gens`` functions
    29 to obtain the corresponding generators. You can print the
    30 generators as arbitrary strings using the optional
    31 ``names`` argument to the
    32 ``DualAbelianGroup`` function.
     53- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.
     54  Default to cyclotomic base ring.
    3355"""
    3456
    35 ##########################################################################
    36 #  Copyright (C) 2006 David Joyner <wdjoyner@gmail.com> and William Stein
     57###########################################################################
     58#  Copyright (C) 2006 William Stein <wstein@gmail.com>
     59#  Copyright (C) 2006 David Joyner  <wdjoyner@gmail.com>
     60#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
    3761#
    38 #  Distributed under the terms of the GNU General Public License (GPL):
    39 #
     62#  Distributed under the terms of the GNU General Public License (GPL)
    4063#                  http://www.gnu.org/licenses/
    41 ##########################################################################
    42 
    43 
     64###########################################################################
    4465
    4566from sage.rings.infinity import infinity
    46 from sage.rings.arith import LCM
    47 import sage.groups.group as group
    48 from dual_abelian_group_element import DualAbelianGroupElement,is_DualAbelianGroupElement
     67from sage.structure.unique_representation import UniqueRepresentation
     68from sage.groups.abelian_gps.dual_abelian_group_element import (
     69    DualAbelianGroupElement, is_DualAbelianGroupElement )
    4970from sage.misc.mrange import mrange
    50 from sage.rings.integer_ring import IntegerRing
    51 ZZ = IntegerRing()
    52 from sage.rings.complex_field import ComplexField
    53 CC = ComplexField()
    54 from sage.rings.number_field.number_field import CyclotomicField
     71from sage.misc.cachefunc import cached_method
     72from sage.groups.group import AbelianGroup as AbelianGroupBase
    5573
    56 def DualAbelianGroup(G, names="X", base_ring=CC):
    57     r"""
    58     Create the dual group of the multiplicative abelian group
    59     `G`.
    60    
    61     INPUT:
    62    
    63    
    64     -  ``G`` - a finite abelian group
    65    
    66     -  ``names`` - (optional) names of generators
    67    
    68    
    69     OUTPUT: The dual group of G.
    70    
    71     EXAMPLES::
    72    
    73         sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
    74         sage: (a, b, c, d, e) = F.gens()
    75         sage: Fd = DualAbelianGroup(F,names='ABCDE')
    76         sage: A,B,C,D,E = Fd.gens()
    77         sage: A(a)    ## random
    78         -1.0000000000000000 + 0.00000000000000013834419720915037*I
    79         sage: A(b); A(c); A(d); A(e)
    80         1.00000000000000
    81         1.00000000000000
    82         1.00000000000000
    83         1.00000000000000
    84     """
    85     if G.order() is infinity:
    86         NotImplementedError, "The group must be finite"
    87     #infac = G.invariants()
    88     #n = G.ngens()
    89     #namesG = [G.gen(i) for i in range(n)]
    90     M = DualAbelianGroup_class(G, names, base_ring)
    91     return M
    9274
    9375def is_DualAbelianGroup(x):
    9476    """
     
    9779    EXAMPLES::
    9880   
    9981        sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup
    100         sage: F = AbelianGroup(5,[3,5,7,8,9],names = list("abcde"))
    101         sage: Fd = DualAbelianGroup(F)
     82        sage: F = AbelianGroup(5,[3,5,7,8,9], names=list("abcde"))
     83        sage: Fd = F.dual_group()
    10284        sage: is_DualAbelianGroup(Fd)
    10385        True
    104         sage: F = AbelianGroup(3,[1,2,3],names='a')
    105         sage: Fd = DualAbelianGroup(F)
     86        sage: F = AbelianGroup(3,[1,2,3], names='a')
     87        sage: Fd = F.dual_group()
    10688        sage: Fd.gens()
    107         (X0, X1)
     89        (1, X1, X2)
    10890        sage: F.gens()
    109         (a0, a1)
     91        (1, a1, a2)
    11092    """
    11193    return isinstance(x, DualAbelianGroup_class)
    11294
    11395
    114 class DualAbelianGroup_class(group.AbelianGroup):
     96class DualAbelianGroup_class(UniqueRepresentation, AbelianGroupBase):
    11597    """
    11698    Dual of abelian group.
    11799   
    118100    EXAMPLES::
    119101   
    120         sage: F = AbelianGroup(5,[3,5,7,8,9],names = list("abcde"))
    121         sage: DualAbelianGroup(F)
    122         Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z  over Complex Field with 53 bits of precision
    123         sage: F = AbelianGroup(4,[15,7,8,9],names = list("abcd"))
    124         sage: DualAbelianGroup(F)
    125         Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z  over Complex Field with 53 bits of precision
     102        sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
     103        sage: F.dual_group()
     104        Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
     105        over Cyclotomic Field of order 2520 and degree 576
     106        sage: F = AbelianGroup(4,[15,7,8,9], names="abcd")
     107        sage: F.dual_group(base_ring=CC)
     108        Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z
     109        over Complex Field with 53 bits of precision
    126110    """
    127     def __init__(self, G, names="X", bse_ring=None):
     111    Element = DualAbelianGroupElement
     112
     113    def __init__(self, G, names, base_ring):
    128114        """
    129         If G has invariants invs = [n1,...,nk] then the default base_ring
    130         is CyclotoomicField(N), where N = LCM(n1,...,nk).
    131         """
    132         if bse_ring == None:   
    133             base_ring = CyclotomicField(LCM(G.invariants()))
    134         else:
    135             base_ring = bse_ring
    136         self.__group = G
     115        The Python constructor
     116
     117        EXAMPLES::
     118
     119            sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
     120            sage: F.dual_group()
     121            Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
     122            over Cyclotomic Field of order 2520 and degree 576
     123       """
     124        self._base_ring = base_ring
     125        self._group = G
     126        names = self.normalize_names(G.ngens(), names)
    137127        self._assign_names(names)
    138         self._base_ring = base_ring
     128        AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()
    139129       
    140130    def group(self):
    141         return self.__group
     131        """
     132        Return the group that ``self`` is the dual of.
     133
     134        EXAMPLES::
     135
     136            sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
     137            sage: Fd = F.dual_group(base_ring=CC)
     138            sage: Fd.group() is F
     139            True
     140        """
     141        return self._group
    142142   
    143143    def base_ring(self):
     144        """
     145        Return the scalars over which the group is dualized.
     146
     147        EXAMPLES::
     148
     149            sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
     150            sage: Fd = F.dual_group(base_ring=CC)
     151            sage: Fd.base_ring()
     152            Complex Field with 53 bits of precision
     153        """
    144154        return self._base_ring
    145155   
    146156    def __str__(self):
     
    149159       
    150160        EXAMPLES::
    151161       
    152                    sage: F = AbelianGroup(3,[5,64,729],names = list("abc"))
    153                    sage: Fd = DualAbelianGroup(F)
     162            sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
     163            sage: Fd = F.dual_group(base_ring=CC)
    154164            sage: print Fd
    155                    DualAbelianGroup( AbelianGroup ( 3, [5, 64, 729] ) )
     165            DualAbelianGroup( AbelianGroup ( 3, (5, 64, 729) ) )
    156166        """
    157         s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.invariants())
     167        s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.gens_orders())
    158168        return s
    159169
    160170    def _repr_(self):
    161171        """
     172        Return a string representation.
     173
    162174        EXAMPLES::
    163175       
    164176            sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
    165             sage: Fd = DualAbelianGroup(F,names='ABCDE',base_ring = CyclotomicField(2*5*7*8*9))
     177            sage: Fd = F.dual_group(names='ABCDE', base_ring=CyclotomicField(2*5*7*8*9))
     178            sage: Fd   # indirect doctest
     179            Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
     180            over Cyclotomic Field of order 5040 and degree 1152
     181            sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)
    166182            sage: Fd
    167             Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z  over Cyclotomic Field of order 5040 and degree 1152
    168             sage: Fd = DualAbelianGroup(F,names='ABCDE')
    169             sage: Fd
    170             Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z  over Complex Field with 53 bits of precision
     183            Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
     184            over Complex Field with 53 bits of precision
    171185        """
    172186        G = self.group()
    173         eldv = G.invariants()
     187        eldv = G.gens_orders()
    174188        gp = ""
    175189        for x in eldv:
    176190            if x!=0:
    177191                gp = gp + "Z/%sZ x "%x
    178192            if x==0:
    179193                gp = gp + "Z x "
    180         gp = gp[:-2]
    181         s = "Dual of Abelian Group isomorphic to "+gp+" over %s"%self.base_ring()
     194        gp = gp[:-2].strip()
     195        s = 'Dual of Abelian Group isomorphic to ' + gp + ' over ' + str(self.base_ring())
    182196        return s
    183197
    184198    def _latex_(self):
     
    188202        EXAMPLES::
    189203       
    190204            sage: F = AbelianGroup(3, [2]*3)
    191             sage: Fd = DualAbelianGroup(F)
     205            sage: Fd = F.dual_group()
    192206            sage: Fd._latex_() 
    193             '$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, [2, 2, 2] ) )$'
     207            '$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, (2, 2, 2) ) )$'
    194208        """
    195         s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.invariants())
     209        s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.gens_orders())
    196210        return s
    197211
    198     def __call__(self, x):
    199         """
    200         Create an element of this abelian group from `x`.
    201        
    202         EXAMPLES::
    203        
    204             sage: F = AbelianGroup(10, [2]*10)
    205             sage: Fd = DualAbelianGroup(F)
    206             sage: Fd(Fd.2)
    207             X2
    208             sage: Fd(1)
    209             1
    210         """
    211         if isinstance(x, DualAbelianGroupElement) and x.parent() is self:
    212             return x
    213         return DualAbelianGroupElement(self, x)
    214                                
    215212    def random_element(self):
    216213        """
    217214        Return a random element of this dual group.
     
    219216        EXAMPLES::
    220217       
    221218            sage: G = AbelianGroup([2,3,9])
    222             sage: Gd = DualAbelianGroup(G)
     219            sage: Gd = G.dual_group(base_ring=CC)
    223220            sage: Gd.random_element()
    224             X0*X1^2*X2
     221            X1^2
     222
    225223            sage: N = 43^2-1
    226224            sage: G = AbelianGroup([N],names="a")
    227             sage: Gd = DualAbelianGroup(G,names="A")
     225            sage: Gd = G.dual_group(names="A", base_ring=CC)
    228226            sage: a, = G.gens()
    229227            sage: A, = Gd.gens()
    230228            sage: x = a^(N/4); y = a^(N/3); z = a^(N/14)
    231             sage: X = Gd.random_element(); X
     229            sage: X = A*Gd.random_element(); X
    232230            A^615
    233231            sage: len([a for a in [x,y,z] if abs(X(a)-1)>10^(-8)])
    234232            2
    235233        """
    236234        from sage.misc.prandom import randint
    237         gens = self.gens()
    238         g = gens[0]**0
    239         for i in range(len(gens)):
    240             g = g*gens[i]**(randint(1,gens[i].order()))
    241         return g
    242 
    243     def random(self):
    244         """
    245         Deprecated. Use self.random_element() instead.
    246         """
    247         raise NotImplementedError, "Deprecated: use random_element() instead"
    248 
     235        result = self.one()
     236        for g in self.gens():
     237            order = g.order()
     238            result *= g**(randint(0,order))
     239        return result
    249240
    250241    def gen(self, i=0):
    251242        """
     
    254245        EXAMPLES::
    255246       
    256247            sage: F = AbelianGroup(3,[1,2,3],names='a')
    257             sage: Fd = DualAbelianGroup(F, names="A")
     248            sage: Fd = F.dual_group(names="A")
    258249            sage: Fd.0
    259             A0
     250            1
    260251            sage: Fd.1
    261252            A1
    262             sage: Fd.invariants()
    263             [2, 3]
     253            sage: Fd.gens_orders()
     254            (1, 2, 3)
    264255        """
    265256        n = self.group().ngens()
    266257        if i < 0 or i >= n:
    267258            raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)
    268         x = [0]*int(n)
    269         x[int(i)] = 1
    270         return DualAbelianGroupElement(self, x)
     259        x = [0]*n
     260        if self.gens_orders()[i] != 1:
     261            x[i] = 1
     262        return self.element_class(x, self)
    271263
    272     #def gens(self):
    273     #    """
    274     #    Return the generators for this subgroup.
    275     #   
    276     #    """
    277     #    n = self.group().ngens()
    278     #    return tuple(self.gen(i) for i in range(n))
     264    def gens(self):
     265        """
     266        Return the generators for the group.
     267
     268        OUTPUT:
     269
     270        A tuple of group elements generating the group.
     271
     272        EXAMPLES::
     273
     274            sage: F = AbelianGroup([7,11]).dual_group()
     275            sage: F.gens()
     276            (X0, X1)
     277        """
     278        n = self.group().ngens()
     279        return tuple(self.gen(i) for i in range(n))
    279280   
    280281    def ngens(self):
    281282        """
     
    283284       
    284285        EXAMPLES::
    285286       
    286             sage: F = AbelianGroup(1000)
    287             sage: Fd = DualAbelianGroup(F)
     287            sage: F = AbelianGroup([7]*100)
     288            sage: Fd = F.dual_group()
    288289            sage: Fd.ngens()
    289             1000
    290        
    291         This can be slow for 10000 or more generators.
     290            100
    292291        """
    293292        return self.group().ngens()
    294293
     294    def gens_orders(self):
     295        """
     296        The orders of the generators of the dual group.
     297
     298        OUTPUT:
     299
     300        A tuple of integers.
     301
     302        EXAMPLES::
     303
     304            sage: F = AbelianGroup([5]*1000)
     305            sage: Fd = F.dual_group()
     306            sage: invs = Fd.gens_orders(); len(invs)
     307            1000
     308        """
     309        return self.group().gens_orders()
     310
    295311    def invariants(self):
    296312        """
    297313        The invariants of the dual group.
     314
     315        You should use :meth:`gens_orders` instead.
    298316       
    299317        EXAMPLES::
    300318       
    301             sage: F = AbelianGroup(1000)
    302             sage: Fd = DualAbelianGroup(F)
    303             sage: invs = Fd.invariants(); len(invs)
     319            sage: F = AbelianGroup([5]*1000)
     320            sage: Fd = F.dual_group()
     321            sage: invs = Fd.gens_orders(); len(invs)
    304322            1000
    305        
    306         This can be slow for 10000 or more generators.
    307323        """
    308         return self.group().invariants()
     324        # TODO: deprecate
     325        return self.group().gens_orders()
    309326   
    310327    def __contains__(self,X):
    311328        """
     
    315332       
    316333            sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
    317334            sage: a,b,c,d,e = F.gens()
    318             sage: Fd = DualAbelianGroup(F, names = "ABCDE")
     335            sage: Fd = F.dual_group(names = "ABCDE")
    319336            sage: A,B,C,D,E = Fd.gens()
    320337            sage: A*B^2*D^7 in Fd
    321338            True
     
    329346        EXAMPLES::
    330347       
    331348            sage: G = AbelianGroup([2,3,9])
    332             sage: Gd = DualAbelianGroup(G)
     349            sage: Gd = G.dual_group()
    333350            sage: Gd.order()
    334351            54
    335352        """
     
    343360        EXAMPLES::
    344361       
    345362            sage: G = AbelianGroup([2,3,9])
    346             sage: Gd = DualAbelianGroup(G)
     363            sage: Gd = G.dual_group()
    347364            sage: Gd.is_commutative()
    348365            True
    349366            sage: Gd.is_abelian()
     
    351368        """
    352369        return True
    353370
     371    @cached_method
    354372    def list(self):
    355373        """
    356         Return list of all elements of this group.
     374        Return tuple of all elements of this group.
    357375       
    358376        EXAMPLES::
    359377       
    360             sage: G = AbelianGroup([2,3], names = "ab")
    361             sage: Gd = DualAbelianGroup(G, names = "AB")
     378            sage: G = AbelianGroup([2,3], names="ab")
     379            sage: Gd = G.dual_group(names="AB")
    362380            sage: Gd.list()
    363             [1, B, B^2, A, A*B, A*B^2]
     381            (1, B, B^2, A, A*B, A*B^2)
    364382        """
    365         try:
    366             return list(self.__list)
    367         except AttributeError:
    368             pass
    369383        if not(self.is_finite()):
    370384           raise NotImplementedError, "Group must be finite"
    371         invs = self.invariants()
     385        invs = self.gens_orders()
    372386        T = mrange(invs)
    373387        n = self.order()
    374         L = [DualAbelianGroupElement(self, t) for t in T]
    375         self.__list = L
    376         return list(self.__list)
     388        L = tuple( self(t) for t in T )
     389        return L
    377390     
    378391    def __iter__(self):
    379392        """
     
    381394       
    382395        EXAMPLES::
    383396       
    384             sage: G = AbelianGroup([2,3], names = "ab")
    385             sage: Gd = DualAbelianGroup(G, names = "AB")
     397            sage: G = AbelianGroup([2,3], names="ab")
     398            sage: Gd = G.dual_group(names="AB")
    386399            sage: [X for X in Gd]
    387400            [1, B, B^2, A, A*B, A*B^2]
    388401            sage: N = 43^2-1
    389402            sage: G = AbelianGroup([N],names="a")
    390             sage: Gd = DualAbelianGroup(G,names="A")
     403            sage: Gd = G.dual_group(names="A", base_ring=CC)
    391404            sage: a, = G.gens()
    392405            sage: A, = Gd.gens()
    393406            sage: x = a^(N/4)
  • sage/groups/abelian_gps/dual_abelian_group_element.py

    diff --git a/sage/groups/abelian_gps/dual_abelian_group_element.py b/sage/groups/abelian_gps/dual_abelian_group_element.py
    a b  
    11"""
    22Elements (characters) of the dual group of a finite Abelian group.
    33
    4 AUTHORS:
    5     - David Joyner (2006-07); based on abelian_group_element.py.
    6     - David Joyner (2006-10); modifications suggested by William Stein.
     4To obtain the dual group of a finite Abelian group, use the
     5:meth:`~sage.groups.abelian_gps.abelian_group.dual_group` method::
    76
    8 EXAMPLES:
    9     sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
     7    sage: F = AbelianGroup([2,3,5,7,8], names="abcde")
     8    sage: F
     9    Multiplicative Abelian group isomorphic to C2 x C3 x C5 x C7 x C8
     10
     11    sage: Fd = F.dual_group(names="ABCDE")
     12    sage: Fd
     13    Dual of Abelian Group isomorphic to Z/2Z x Z/3Z x Z/5Z x Z/7Z x Z/8Z
     14    over Cyclotomic Field of order 840 and degree 192
     15
     16The elements of the dual group can be evaluated on elements of the orignial group::
     17
    1018    sage: a,b,c,d,e = F.gens()
    11     sage: Fd = DualAbelianGroup(F, names = "ABCDE")
    1219    sage: A,B,C,D,E = Fd.gens()
    1320    sage: A*B^2*D^7
    1421    A*B^2
    15     sage: A(a)    ## random last few digits
    16     -1.0000000000000000 + 0.00000000000000013834419720915037*I
     22    sage: A(a)
     23    -1
    1724    sage: B(b)
    18     -0.500000000000000 + 0.866025403784439*I
    19     sage: A(a*b)    ## random last few digits
    20     -1.0000000000000000 + 0.00000000000000013834419720915037*I
    21     sage: (A*B*C^2*D^20*E^65).list()
    22     [1, 1, 2, 6, 1]
     25    zeta840^140 - 1
     26    sage: CC(_)     # abs tol 1e-8
     27    -0.499999999999995 + 0.866025403784447*I
     28    sage: A(a*b)
     29    -1
     30    sage: (A*B*C^2*D^20*E^65).exponents()
     31    (1, 1, 2, 6, 1)
    2332    sage: B^(-1)
    2433    B^2
    2534
    26 It is important to note that lists are mutable and the
    27 returned list is not a copy.  As a result, reassignment
    28 of an element of the list changes the object.
     35AUTHORS:
    2936
    30     sage: X = A*B*C^2*D^2*E^-6
    31     sage: X.list()
    32     [1, 1, 2, 2, 2]
    33     sage: X.list()[1] = -1
    34     sage: X
    35     A*B^-1*C^2*D^2*E^2
     37- David Joyner (2006-07); based on abelian_group_element.py.
    3638
     39- David Joyner (2006-10); modifications suggested by William Stein.
     40
     41- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.
     42  Default to cyclotomic base ring.
    3743"""
    3844
    3945###########################################################################
    4046#  Copyright (C) 2006 William Stein <wstein@gmail.com>
    4147#  Copyright (C) 2006 David Joyner  <wdjoyner@gmail.com>
     48#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
    4249#
    4350#  Distributed under the terms of the GNU General Public License (GPL)
    4451#                  http://www.gnu.org/licenses/
     
    4754import operator
    4855
    4956from sage.rings.integer import Integer
    50 from sage.structure.element import MonoidElement
    5157from sage.rings.infinity import infinity
    5258from sage.rings.arith import *
    5359from sage.misc.misc import prod
    5460from sage.misc.functional import exp
    5561from sage.rings.complex_field import is_ComplexField
    56 
     62from sage.groups.abelian_gps.element_base import AbelianGroupElementBase
    5763
    5864def add_strings(x, z=0):
    5965    """
     
    6470    return z.
    6571
    6672    INPUT:
    67         x -- iterable
    68         z -- the "0" that will be returned if x is empty.
     73
     74    - ``x`` -- iterable
     75
     76    - ``z`` -- the ``0`` that will be returned if ``x`` is empty.
    6977       
    7078    OUTPUT:
    71         object
     79
     80    The sum of the elements of ``x``.
     81
     82    EXAMPLES::
     83
     84        sage: from sage.groups.abelian_gps.dual_abelian_group_element import add_strings
     85        sage: add_strings([], z='empty')
     86        'empty'
     87        sage: add_strings(['a', 'b', 'c'])
     88        'abc'
    7289    """
    7390    if len(x) == 0:
    7491        return z
     
    8198
    8299
    83100def is_DualAbelianGroupElement(x):
     101    """
     102    Test whether ``x`` is a dual Abelian group element.
     103
     104    INPUT:
     105
     106    - ``x`` -- anything.
     107
     108    OUTPUT:
     109
     110    Boolean.
     111
     112    EXAMPLES::
     113
     114        sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroupElement
     115        sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")).dual_group()
     116        sage: is_DualAbelianGroupElement(F)
     117        False
     118        sage: is_DualAbelianGroupElement(F.an_element())
     119        True
     120    """
    84121    return isinstance(x, DualAbelianGroupElement)
    85122
    86 class DualAbelianGroupElement(MonoidElement):
    87     def __init__(self, F, X):
     123
     124class DualAbelianGroupElement(AbelianGroupElementBase):
     125    """
     126    Base class for abelian group elements
     127    """
     128
     129    def __call__(self, g):
    88130        """
    89         Create an element X of the DualAbelianGroup of F.
     131        Evaluate ``self`` on a group element ``g``.
    90132
    91         EXAMPLES:
    92             sage: F = AbelianGroup(3,[7,8,9])
    93             sage: Fd = DualAbelianGroup(F,names="ABC")
    94             sage: A,B,C = Fd.gens()
    95             sage: A*B^-1 in Fd
    96             True
     133        OUTPUT:
    97134
    98         """
    99         MonoidElement.__init__(self, F)
    100         self.__repr = None
    101         G = F.group()
    102         n = G.ngens()
    103         if isinstance(X, (int, Integer)) and X == 1:
    104             self.__element_vector = [ 0 for i in range(n) ]
    105         elif isinstance(X, list):
    106             if len(X) != n:
    107                 raise IndexError, \
    108                       "Argument length (= %s) must be %s."%(len(X), n)
    109             self.__element_vector = X
    110         else:
    111             raise TypeError, "Argument X (= %s) is of wrong type."%X
    112              
    113     def list(self):
    114         """
    115         Return (a reference to) the underlying list used to represent
    116         this element.  If this is a word in an abelian group on $n$
    117         generators, then this is a list of nonnegative integers of
    118         length $n$.
     135        An element in
     136        :meth:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class.base_ring`.
    119137
    120         EXAMPLES:
    121             sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
    122             sage: a,b,c,d,e = F.gens()
    123             sage: Ad = DualAbelianGroup(F, names = "ABCDE")
    124             sage: A,B,C,D,E = Ad.gens()
    125             sage: (A*B*C^2*D^20*E^65).list()
    126             [1, 1, 2, 6, 1]
    127             sage: X = A*B*C^2*D^2*E^-6
    128             sage: X.list()
    129             [1, 1, 2, 2, 2]
    130             sage: X.list()[1] = -1
    131             sage: X
    132             A*B^-1*C^2*D^2*E^2
    133         """
    134         return self.__element_vector
     138        EXAMPLES::
    135139
    136     def _repr_(self):
    137         s = ""
    138         A = self.parent()
    139         n = A.ngens()
    140         x = A.variable_names()
    141         v = self.list()
    142         for i in range(n):
    143             if v[i] == 0:
    144                 continue
    145             elif v[i] == 1:
    146                 if len(s) > 0: s += "*"
    147                 s += "%s"%x[i]
    148             else:
    149                 if len(s) > 0: s += "*"
    150                 s += "%s^%s"%(x[i],v[i])
    151         if len(s) == 0: s = "1"
    152         return s
    153 
    154     def __mul__(self, y):
    155         #Same as _mul_ in AbelianGroupElement
    156        
    157         M = self.parent()
    158         n = M.ngens()
    159         invs = M.invariants()
    160         z = M(1)
    161         xelt = self.list()
    162         yelt = y.list()
    163         zelt = [ xelt[i]+yelt[i] for i in range(len(xelt)) ]
    164         if len(invs) >= n:
    165             L =  []
    166             for i in range(len(xelt)):
    167                 if invs[i]!=0:
    168                     L.append(zelt[i]%invs[i])
    169                 if invs[i]==0:
    170                     L.append(zelt[i])
    171             z.__element_vector = L
    172             #print z.__element_vector
    173         if len(invs) < n:
    174             L1 =  []
    175             for i in range(len(invs)):
    176                 if invs[i]!=0:
    177                     L1.append(zelt[i]%invs[i])
    178                 if invs[i]==0:
    179                     L1.append(zelt[i])
    180             L2 =  [ zelt[i] for i in range(len(invs),len(xelt)) ]
    181             z.__element_vector = L1+L2
    182         return M(z.__element_vector)
    183 
    184     def __pow__(self, n):
    185         """
    186         requires that len(invs) = n
    187         """
    188         if not isinstance(n, (int, long, Integer)):
    189             raise TypeError, "Argument n (= %s) must be an integer."%n
    190         n = int(n)
    191         M = self.parent()
    192         N = M.ngens()
    193         invs = M.invariants()
    194         if n < 0: 
    195             L =[n*self.list()[i]%M.gen(i).order() for i in range(M.ngens())]
    196             return prod([M.gen(i)**L[i] for i in range(M.ngens())])
    197             #m = LCM(invs) ## Not very efficient version
    198             #pw = (n)%m
    199             #x = self**pw
    200             #return x
    201         elif n == 0:
    202             return M(1)
    203         elif n == 1:
    204             return self
    205         elif n == 2:
    206             return self * self
    207         k = n//2
    208         return self**k * self**(n-k)
    209 
    210     def __cmp__(self,other):
    211         if (self.list() != other.list()):
    212                 return -1
    213         return 0
    214                        
    215     def order(self):
    216         """
    217         Returns the (finite) order of this element.
    218  
    219         EXAMPLES:
    220             sage: F = AbelianGroup(3,[7,8,9])
    221             sage: Fd = DualAbelianGroup(F)
    222             sage: A,B,C = Fd.gens()
    223             sage: (B*C).order()
    224             72
    225         """
    226         M = self.parent()
    227         #print self, M
    228         if self == M(1):
    229             return Integer(1)
    230         invs = M.invariants()
    231         if self in M.gens():
    232             o = invs[list(M.gens()).index(self)]
    233             if o == 0:
    234                 return infinity
    235             return o
    236         L = list(self.list())
    237         N = LCM([invs[i]/GCD(invs[i],L[i]) for i in range(len(invs)) if L[i]!=0])   ####### error here????
    238         if N == 0:
    239             return infinity
    240         else:
    241             return N
    242 
    243     def __call__(self,g):
    244         """
    245         Computes the value of a character self on a group element
    246         g (g must be an element of self.group())
    247 
    248         EXAMPLES:
    249140            sage: F = AbelianGroup(5, [2,3,5,7,8], names="abcde")
    250141            sage: a,b,c,d,e = F.gens()
    251             sage: Fd = DualAbelianGroup(F, names="ABCDE")
     142            sage: Fd = F.dual_group(names="ABCDE")
    252143            sage: A,B,C,D,E = Fd.gens()
    253144            sage: A*B^2*D^7
    254145            A*B^2
    255             sage: A(a)    ## random last few digits
    256             -1.0000000000000000 + 0.00000000000000013834419720915037*I
    257             sage: B(b)    ## random last few digits
    258             -0.49999999999999983 + 0.86602540378443871*I
    259             sage: A(a*b)    ## random last few digits
    260             -1.0000000000000000 + 0.00000000000000013834419720915037*I
     146            sage: A(a)
     147            -1
     148            sage: B(b)
     149            zeta840^140 - 1
     150            sage: CC(B(b))    # abs tol 1e-8
     151            -0.499999999999995 + 0.866025403784447*I
     152            sage: A(a*b)
     153            -1
    261154        """
    262155        F = self.parent().base_ring()
    263         expsX = list(self.list())
    264         expsg = list(g.list())
    265         invs = self.parent().invariants()
    266         N = LCM(invs)
     156        expsX = self.exponents()
     157        expsg = g.exponents()
     158        order = self.parent().gens_orders()
     159        N = LCM(order)
    267160        if is_ComplexField(F):
    268161            from sage.symbolic.constants import pi
    269162            I = F.gen()
    270163            PI = F(pi)
    271             ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/invs[i]) for i in range(len(expsX))])
     164            ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/order[i]) for i in range(len(expsX))])
    272165            return ans
    273166        ans = F(1)  ## assumes F is the cyclotomic field
    274167        zeta = F.gen()
    275         #print F,zeta
    276168        for i in range(len(expsX)):
    277             inv_noti = N/invs[i]
    278             ans = ans*zeta**(expsX[i]*expsg[i]*inv_noti)
     169            order_noti = N/order[i]
     170            ans = ans*zeta**(expsX[i]*expsg[i]*order_noti)
    279171        return ans
    280172   
    281173    def word_problem(self, words, display=True):
     
    292184        the dual group to the corresponding problem on the group
    293185        itself and uses GAP to solve that.
    294186       
    295         EXAMPLES:
     187        EXAMPLES::
     188
    296189            sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde")
    297             sage: Gd = DualAbelianGroup(G,names="abcde")
     190            sage: Gd = G.dual_group(names="abcde")
    298191            sage: a,b,c,d,e = Gd.gens()
    299192            sage: u = a^3*b*c*d^2*e^5
    300193            sage: v = a^2*b*c^2*d^3*e^3
     
    306199
    307200        The command e.word_problem([u,v,w,x,y],display=True) returns
    308201        the same list but also prints $e = (b^2*c^2*d^3*e^5)^245$.
    309 
    310202        """
    311203        ## First convert the problem to one using AbelianGroups
    312204        import copy
  • new file sage/groups/abelian_gps/element_base.py

    diff --git a/sage/groups/abelian_gps/element_base.py b/sage/groups/abelian_gps/element_base.py
    new file mode 100644
    - +  
     1"""
     2Base class for abelian group elements
     3
     4This is the base class for both
     5:mod:`~sage.groups.abelian_gps.abelian_group_element` and
     6:mod:`~sage.groups.abelian_gps.dual_abelian_group_element`.
     7
     8As always, elements are immutable once constructed.
     9"""
     10
     11
     12###########################################################################
     13#  Copyright (C) 2006 William Stein <wstein@gmail.com>
     14#  Copyright (C) 2006 David Joyner  <wdjoyner@gmail.com>
     15#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
     16#
     17#  Distributed under the terms of the GNU General Public License (GPL)
     18#                  http://www.gnu.org/licenses/
     19###########################################################################
     20
     21from sage.structure.element import MultiplicativeGroupElement
     22from sage.misc.cachefunc import cached_method
     23from sage.rings.arith import GCD, LCM
     24from sage.rings.integer import Integer
     25from sage.rings.integer_ring import ZZ
     26from sage.rings.infinity import infinity
     27
     28
     29class AbelianGroupElementBase(MultiplicativeGroupElement):
     30    """
     31    Base class for abelian group elements
     32
     33    The group element is defined by a tuple whose ``i``-th entry is an
     34    integer in the range from 0 (inclusively) to ``G.gen(i).order()``
     35    (exclusively) if the `i`-th generator is of finite order, and an
     36    arbitrary integer if the `i`-th generator is of infinte order.
     37
     38    INPUT:
     39
     40    - ``exponents`` -- ``1`` or a list/tuple/iterable of integers. The
     41      exponent vector (with respect to the parent generators) defining
     42      the group element.
     43
     44    - ``parent`` -- Abelian group. The parent of the group element.
     45
     46    EXAMPLES::
     47
     48        sage: F = AbelianGroup(3,[7,8,9])
     49        sage: Fd = F.dual_group(names="ABC")
     50        sage: A,B,C = Fd.gens()
     51        sage: A*B^-1 in Fd
     52        True
     53    """
     54
     55    def __init__(self, exponents, parent):
     56        """
     57        Create an element.
     58
     59        EXAMPLES::
     60
     61            sage: F = AbelianGroup(3,[7,8,9])
     62            sage: Fd = F.dual_group(names="ABC")
     63            sage: A,B,C = Fd.gens()
     64            sage: A*B^-1 in Fd
     65            True
     66        """
     67        MultiplicativeGroupElement.__init__(self, parent)
     68        n = parent.ngens()
     69        if exponents == 1:
     70            self._exponents = tuple( ZZ.zero() for i in range(n) )
     71        else:
     72            self._exponents = tuple( ZZ(e) for e in exponents )
     73            if len(self._exponents) != n:
     74                raise IndexError('argument length (= %s) must be %s.'%(len(X), n))
     75
     76    def exponents(self):
     77        """
     78        The exponents of the generators defining the group element.
     79
     80        OUTPUT:
     81
     82        A tuple of integers for an abelian group element. The integer
     83        can be arbitrary if the corresponding generator has infinite
     84        order. If the generator is of finite order, the integer is in
     85        the range from 0 (inclusive) to the order (exclusive).
     86
     87        EXAMPLES::
     88
     89            sage: F.<a,b,c,f> = AbelianGroup([7,8,9,0])
     90            sage: (a^3*b^2*c).exponents()
     91            (3, 2, 1, 0)
     92            sage: F([3, 2, 1, 0])
     93            a^3*b^2*c
     94            sage: (c^42).exponents()
     95            (0, 0, 6, 0)
     96            sage: (f^42).exponents()
     97            (0, 0, 0, 42)
     98        """
     99        return self._exponents
     100
     101    def list(self):
     102        """
     103        Return a copy of the exponent vector.
     104
     105        Use :meth:`exponents` instead.
     106
     107        OUTPUT:
     108
     109        The underlying coordinates used to represent this element.  If
     110        this is a word in an abelian group on `n` generators, then
     111        this is a list of nonnegative integers of length `n`.
     112
     113        EXAMPLES::
     114
     115            sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
     116            sage: a,b,c,d,e = F.gens()
     117            sage: Ad = F.dual_group(names="ABCDE")
     118            sage: A,B,C,D,E = Ad.gens()
     119            sage: (A*B*C^2*D^20*E^65).exponents()
     120            (1, 1, 2, 6, 1)
     121            sage: X = A*B*C^2*D^2*E^-6
     122            sage: X.exponents()
     123            (1, 1, 2, 2, 2)
     124        """
     125        # to be deprecated (really, return a list??). Use exponents() instead.
     126        return list(self._exponents)
     127
     128    def _repr_(self):
     129        """
     130        Return a string representation of ``self``.
     131
     132        OUTPUT:
     133
     134        String.
     135
     136        EXAMPLES::
     137
     138            sage: G = AbelianGroup([2])
     139            sage: G.gen(0)._repr_()
     140            'f'
     141            sage: G.one()._repr_()
     142            '1'
     143        """
     144        s = ""
     145        G = self.parent()
     146        for v_i, x_i in zip(self.exponents(), G.variable_names()):
     147            if v_i == 0:
     148                continue
     149            if len(s) > 0:
     150                s += '*'
     151            if v_i == 1:
     152                s += str(x_i)
     153            else:
     154                s += str(x_i) + '^' + str(v_i)
     155        if s:
     156            return s
     157        else:
     158            return '1'
     159
     160    def __cmp__(self, other):
     161        """
     162        Compare ``self`` and ``other``.
     163
     164        OUTPUT:
     165
     166        ``-1``, ``0``, or ``+1``
     167
     168        EXAMPLES::
     169
     170            sage: G.<a,b> = AbelianGroup([2,3])
     171            sage: cmp(a,b)
     172            1
     173
     174            sage: Gd.<A,B> = G.dual_group()
     175            sage: cmp(A,B)
     176            1
     177        """
     178        return cmp(self._exponents, other._exponents)
     179
     180    @cached_method
     181    def order(self):
     182        """
     183        Return the order of this element.
     184
     185        OUTPUT:
     186
     187        An integer or ``infinity``.
     188
     189        EXAMPLES::
     190
     191            sage: F = AbelianGroup(3,[7,8,9])
     192            sage: Fd = F.dual_group()
     193            sage: A,B,C = Fd.gens()
     194            sage: (B*C).order()
     195            72
     196
     197            sage: F = AbelianGroup(3,[7,8,9]); F
     198            Multiplicative Abelian group isomorphic to C7 x C8 x C9
     199            sage: F.gens()[2].order()
     200            9
     201            sage: a,b,c = F.gens()
     202            sage: (b*c).order()
     203            72
     204            sage: G = AbelianGroup(3,[7,8,9])
     205            sage: type((G.0 * G.1).order())==Integer
     206            True
     207        """
     208        M = self.parent()
     209        order = M.gens_orders()
     210        L = self.exponents()
     211        N = LCM([order[i]/GCD(order[i],L[i]) for i in range(len(order)) if L[i]!=0])
     212        if N == 0:
     213            return infinity
     214        else:
     215            return ZZ(N)
     216
     217    multiplicative_order = order
     218
     219    def _div_(left, right):
     220        """
     221        Divide ``left`` and ``right``
     222
     223        TESTS::
     224
     225            sage: G.<a,b> = AbelianGroup(2)
     226            sage: a/b
     227            a*b^-1
     228            sage: a._div_(b)
     229            a*b^-1
     230        """
     231        G = left.parent()
     232        assert G is right.parent()
     233        exponents = [ (x-y)%order if order!=0 else x-y
     234                      for x, y, order in
     235                      zip(left._exponents, right._exponents, G.gens_orders()) ]
     236        return G.element_class(exponents, G)
     237
     238    def _mul_(left, right):
     239        """
     240        Multiply ``left`` and ``right``
     241
     242        TESTS::
     243
     244            sage: G.<a,b> = AbelianGroup(2)
     245            sage: a*b
     246            a*b
     247            sage: a._mul_(b)
     248            a*b
     249        """
     250        G = left.parent()
     251        assert G is right.parent()
     252        exponents = [ (x+y)%order if order!=0 else x+y
     253                      for x, y, order in
     254                      zip(left._exponents, right._exponents, G.gens_orders()) ]
     255        return G.element_class(exponents, G)
     256
     257    def __pow__(self, n):
     258        """
     259        Exponentiate ``self``
     260
     261        TESTS::
     262
     263            sage: G.<a,b> = AbelianGroup(2)
     264            sage: a^3
     265            a^3
     266        """
     267        m = Integer(n)
     268        if n != m:
     269            raise TypeError('argument n (= '+str(n)+') must be an integer.')
     270        G = self.parent()
     271        exponents = [ (m*e) % order if order!=0 else m*e
     272                      for e,order in zip(self._exponents, G.gens_orders()) ]
     273        return G.element_class(exponents, G)
     274
     275    def inverse(self):
     276        """
     277        Returns the inverse element.
     278
     279        EXAMPLE::
     280
     281            sage: G.<a,b> = AbelianGroup([0,5])
     282            sage: a.inverse()
     283            a^-1
     284            sage: a.__invert__()
     285            a^-1
     286            sage: a^-1
     287            a^-1
     288            sage: ~a
     289            a^-1
     290            sage: (a*b).exponents()
     291            (1, 1)
     292            sage: (a*b).inverse().exponents()
     293            (-1, 4)
     294        """
     295        G = self.parent()
     296        exponents = [ (-e)%order if order!=0 else -e
     297                      for e,order in zip(self._exponents, G.gens_orders()) ]
     298        return G.element_class(exponents, G)
     299
     300    __invert__ = inverse
     301
     302    def is_trivial(self):
     303        """
     304        Test whether ``self`` is the trivial group element ``1``.
     305
     306        OUTPUT:
     307
     308        Boolean.
     309
     310        EXAMPLES::
     311
     312            sage: G.<a,b> = AbelianGroup([0,5])
     313            sage: (a^5).is_trivial()
     314            False
     315            sage: (b^5).is_trivial()
     316            True
     317        """
     318        return all(e==0 for e in self._exponents)
  • new file sage/groups/abelian_gps/values.py

    diff --git a/sage/groups/abelian_gps/values.py b/sage/groups/abelian_gps/values.py
    new file mode 100644
    - +  
     1"""
     2Multiplicative Abelian Groups With Values
     3
     4Often, one ends up with a set that forms an Abelian group. It would be
     5nice if one could return an Abelian group class to encapsulate the
     6data. However,
     7:func:`~sage.groups.abelian_gps.abelian_group.AbelianGroup` is an
     8abstract Abelian group defined by generators and relations. This
     9module implements :class:`AbelianGroupWithValues` that allows the
     10group elements to be decorated with values.
     11
     12An example where this module is used is the unit group of a number
     13field, see :mod:`sage.rings.number_field.unit_group`. The units form a
     14finitely generated Abelian group. We can think of the elements either
     15as abstract Abelian group elements or as particular numbers in the
     16number field. The :func:`AbelianGroupWithValues` keeps track of these
     17associated values.
     18
     19.. warning::
     20
     21    Really, this requires a group homomorphism from the abstract
     22    Abelian group to the set of values. This is only checked if you
     23    pass the ``check=True`` option to :func:`AbelianGroupWithValues`.
     24
     25EXAMPLES:
     26
     27Here is `\ZZ_6` with value `-1` assigned to the generator::
     28
     29    sage: Z6 = AbelianGroupWithValues([-1], [6], names='g')
     30    sage: g = Z6.gen(0)
     31    sage: g.value()
     32    -1
     33    sage: g*g
     34    g^2
     35    sage: (g*g).value()
     36    1
     37    sage: for i in range(7):
     38    ...       print i, g^i, (g^i).value()
     39    0 1 1
     40    1 g -1
     41    2 g^2 1
     42    3 g^3 -1
     43    4 g^4 1
     44    5 g^5 -1
     45    6 1 1
     46
     47The elements come with a coercion embedding into the
     48:meth:`~AbelianGroupWithValues_class.values_group`, so you can use the
     49group elements instead of the values::
     50
     51    sage: CF3.<zeta> = CyclotomicField(3)
     52    sage: Z3.<g> = AbelianGroupWithValues([zeta], [3])
     53    sage: Z3.values_group()
     54    Cyclotomic Field of order 3 and degree 2
     55    sage: g.value()
     56    zeta
     57    sage: CF3(g)
     58    zeta
     59    sage: g + zeta
     60    2*zeta
     61    sage: zeta + g
     62    2*zeta
     63"""
     64
     65##########################################################################
     66#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
     67#
     68#  Distributed under the terms of the GNU General Public License (GPL):
     69#
     70#                  http://www.gnu.org/licenses/
     71##########################################################################
     72
     73
     74from sage.misc.misc import prod
     75from sage.rings.integer import Integer
     76from sage.categories.morphism import Morphism
     77from sage.groups.abelian_gps.abelian_group import AbelianGroup_class, _normalize
     78from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
     79
     80
     81
     82def AbelianGroupWithValues(values, n, gens_orders=None, names='f', check=False, values_group=None):
     83    """
     84    Construct an Abelian group with values associated to the generators.
     85
     86    INPUT:
     87
     88    - ``values`` -- a list/tuple/iterable of values that you want to
     89      associate to the generators.
     90
     91    - ``n`` -- integer (optional). If not specified, will be derived
     92       from ``gens_orders``.
     93
     94    - ``gens_orders`` -- a list of non-negative integers in the form
     95       `[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing
     96       order. This list is padded with zeros if it has length less
     97       than n. The orders of the commuting generators, with `0`
     98       denoting an infinite cyclic factor.
     99
     100    -  ``names`` -- (optional) names of generators
     101
     102    - ``values_group`` -- a parent or ``None`` (default). The common
     103      parent of the values. This might be a group, but can also just
     104      contain the values. For example, if the values are units in a
     105      ring then the ``values_group`` would be the whole ring. If
     106      ``None`` it will be derived from the values.
     107
     108    EXAMPLES::
     109
     110        sage: G = AbelianGroupWithValues([-1], [6])
     111        sage: g = G.gen(0)
     112        sage: for i in range(7):
     113        ...       print i, g^i, (g^i).value()
     114        0 1 1
     115        1 f -1
     116        2 f^2 1
     117        3 f^3 -1
     118        4 f^4 1
     119        5 f^5 -1
     120        6 1 1
     121        sage: G.values_group()
     122        Integer Ring
     123
     124    The group elements come with a coercion embedding into the
     125    :meth:`values_group`, so you can use them like their
     126    :meth:`~sage.groups.abelian_gps.value.AbelianGroupWithValuesElement.value`
     127    ::
     128
     129        sage: G.values_embedding()
     130        Generic morphism:
     131          From: Multiplicative Abelian group isomorphic to C6
     132          To:   Integer Ring
     133        sage: g.value()
     134        -1
     135        sage: 0 + g
     136        -1
     137        sage: 1 + 2*g
     138        -1
     139    """
     140    if check:
     141        raise NotImplementedError('checking that the values are a homomorphism is not implemented')
     142    gens_orders, names = _normalize(n, gens_orders, names)
     143    if values_group is None:
     144        from sage.structure.sequence import Sequence
     145        values_group = Sequence(values).universe()
     146    values = tuple( values_group(val) for val in values )
     147    M = AbelianGroupWithValues_class(gens_orders, names, values, values_group)
     148    return M
     149
     150
     151class AbelianGroupWithValuesEmbedding(Morphism):
     152    """
     153    The morphism embedding the Abelian group with values in its values group.
     154
     155    INPUT:
     156
     157    - ``domain`` -- a :class:`AbelianGroupWithValues_class`
     158
     159    - ``codomain`` -- the values group (need not be in the cateory of
     160      groups, e.g. symbolic ring).
     161
     162    EXAMPLES::
     163
     164        sage: Z4.<g> = AbelianGroupWithValues([I], [4])
     165        sage: embedding = Z4.values_embedding();  embedding
     166        Generic morphism:
     167          From: Multiplicative Abelian group isomorphic to C4
     168          To:   Symbolic Ring
     169        sage: embedding(1)
     170        1
     171        sage: embedding(g)
     172        I
     173        sage: embedding(g^2)
     174        -1
     175    """
     176
     177    def __init__(self, domain, codomain):
     178        """
     179        Construct the morphism
     180
     181        TESTS::
     182
     183            sage: Z4 = AbelianGroupWithValues([I], [4])
     184            sage: from sage.groups.abelian_gps.values import AbelianGroupWithValuesEmbedding
     185            sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group())
     186            Generic morphism:
     187              From: Multiplicative Abelian group isomorphic to C4
     188              To:   Symbolic Ring
     189        """
     190        assert domain.values_group() is codomain
     191        from sage.categories.homset import Hom
     192        Morphism.__init__(self, Hom(domain, codomain))
     193
     194    def _call_(self, x):
     195        """
     196        Return the value associated to ``x``
     197
     198        INPUT:
     199
     200        - ``x`` -- a group element
     201
     202        OUTPUT:
     203
     204        Its value.
     205
     206        EXAMPLES::
     207
     208            sage: Z4.<g> = AbelianGroupWithValues([I], [4])
     209            sage: embedding = Z4.values_embedding()
     210            sage: embedding(g)
     211            I
     212            sage: embedding._call_(g)
     213            I
     214        """
     215        return x.value()
     216
     217
     218class AbelianGroupWithValuesElement(AbelianGroupElement):
     219    """
     220    An element of an Abelian group with values assigned to generators.
     221
     222    INPUT:
     223
     224    - ``exponents`` -- tuple of integers. The exponent vector defining
     225      the group element.
     226
     227    - ``parent`` -- the parent.
     228
     229    - ``value`` -- the value assigned to the group element or ``None``
     230      (default). In the latter case, the value is computed as needed.
     231
     232    EXAMPLES::
     233
     234        sage: F = AbelianGroupWithValues([1,-1], [2,4])
     235        sage: a,b = F.gens()
     236        sage: TestSuite(a*b).run()
     237    """
     238
     239    def __init__(self, exponents, parent, value=None):
     240        """
     241        Create an element
     242
     243        EXAMPLES::
     244
     245            sage: F = AbelianGroupWithValues([1,-1], [2,4])
     246            sage: a,b = F.gens()
     247            sage: a*b^-1 in F
     248            True
     249            sage: (a*b^-1).value()
     250            -1
     251        """
     252        self._value = value
     253        AbelianGroupElement.__init__(self, exponents, parent)
     254
     255    def value(self):
     256        """
     257        Return the value of the group element.
     258
     259        OUTPUT:
     260
     261        The value according to the values for generators, see
     262        :meth:`~AbelianGroupWithValues.gens_values`.
     263
     264        EXAMPLES::
     265
     266            sage: G = AbelianGroupWithValues([5], 1)
     267            sage: G.0.value()
     268            5
     269        """
     270        if self._value is None:
     271            values = self.parent().gens_values()
     272            self._value = prod( v**e for v,e in zip(values, self.exponents()) )
     273        return self._value
     274
     275    def _div_(left, right):
     276        """
     277        Divide ``left`` by ``right``
     278
     279        TESTS::
     280
     281            sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
     282            sage: a._div_(b)
     283            a*b^-1
     284            sage: a/b
     285            a*b^-1
     286            sage: (a/b).value()
     287            5/2
     288        """
     289        m = AbelianGroupElement._div_(left, right)
     290        m._value = left.value() / right.value()
     291        return m
     292
     293    def _mul_(left, right):
     294        """
     295        Multiply ``left`` and ``right``
     296
     297        TESTS::
     298
     299            sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
     300            sage: a._mul_(b)
     301            a*b
     302            sage: a*b
     303            a*b
     304            sage: (a*b).value()
     305            10
     306        """
     307        m = AbelianGroupElement._mul_(left, right)
     308        m._value = left.value() * right.value()
     309        return m
     310
     311    def __pow__(self, n):
     312        """
     313        Exponentiate ``self``
     314
     315        INPUT:
     316
     317        - ``n`` -- integer. The exponent.
     318
     319        TESTS::
     320
     321            sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
     322            sage: a^3
     323            a^3
     324            sage: (a^3).value()
     325            125
     326        """
     327        m = Integer(n)
     328        if n != m:
     329            raise TypeError('argument n (= '+str(n)+') must be an integer.')
     330        pow_self = AbelianGroupElement.__pow__(self, m)
     331        pow_self._value = pow(self.value(), m)
     332        return pow_self
     333
     334    def inverse(self):
     335        """
     336        Return the inverse element.
     337
     338        EXAMPLE::
     339
     340            sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])
     341            sage: a.inverse()
     342            a^-1
     343            sage: a.inverse().value()
     344            1/2
     345            sage: a.__invert__().value()
     346            1/2
     347            sage: (~a).value()
     348            1/2
     349            sage: (a*b).value()
     350            -2
     351            sage: (a*b).inverse().value()
     352            -1/2
     353        """
     354        m = AbelianGroupElement.inverse(self)
     355        m._value = ~self.value()
     356        return m
     357
     358    __invert__ = inverse
     359
     360
     361
     362class AbelianGroupWithValues_class(AbelianGroup_class):
     363    """
     364    The class of an Abelian group with values associated to the generator.
     365
     366    INPUT:
     367
     368    - ``generator_orders`` -- tuple of integers. The orders of the
     369      generators.
     370
     371    - ``names`` -- string or list of strings. The names for the generators.
     372
     373    - ``values`` -- Tuple the same length as the number of
     374      generators. The values assigned to the generators.
     375
     376    - ``values_group`` -- the common parent of the values.
     377
     378    EXAMPLES::
     379
     380        sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])
     381        sage: TestSuite(G).run()
     382    """
     383    Element = AbelianGroupWithValuesElement
     384
     385    def __init__(self, generator_orders, names, values, values_group):
     386        """
     387        The Python constructor
     388
     389        TESTS::
     390
     391            sage: G = AbelianGroupWithValues([2,-1], [0,4]); G
     392            Multiplicative Abelian group isomorphic to Z x C4
     393
     394            sage: cm = sage.structure.element.get_coercion_model()
     395            sage: cm.explain(G, ZZ, operator.add)
     396            Coercion on left operand via
     397                Generic morphism:
     398                  From: Multiplicative Abelian group isomorphic to Z x C4
     399                  To:   Integer Ring
     400            Arithmetic performed after coercions.
     401            Result lives in Integer Ring
     402            Integer Ring
     403        """
     404        self._values = values
     405        self._values_group = values_group
     406        AbelianGroup_class.__init__(self, generator_orders, names)
     407        self._populate_coercion_lists_(embedding=self.values_embedding())
     408        if self.ngens() != len(self._values):
     409            raise ValueError('need one value per generator')
     410
     411    def gen(self, i=0):
     412        """
     413        The `i`-th generator of the abelian group.
     414
     415        INPUT:
     416
     417        - ``i`` -- integer (default: 0). The index of the generator.
     418
     419        OUTPUT:
     420
     421        A group element.
     422
     423        EXAMPLES::
     424
     425            sage: F = AbelianGroupWithValues([1,2,3,4,5], 5,[],names='a')
     426            sage: F.0
     427            a0
     428            sage: F.0.value()
     429            1
     430            sage: F.2
     431            a2
     432            sage: F.2.value()
     433            3
     434
     435            sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
     436            sage: G.gens()
     437            (f0, 1, f2)
     438        """
     439        g = AbelianGroup_class.gen(self, i)
     440        g._value = self._values[i]
     441        return g
     442
     443    def gens_values(self):
     444        """
     445        Return the values associated to the generators.
     446
     447        OUTPUT:
     448
     449        A tuple.
     450
     451        EXAMPLES::
     452
     453            sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
     454            sage: G.gens()
     455            (f0, 1, f2)
     456            sage: G.gens_values()
     457            (-1, 0, 1)
     458        """
     459        return self._values
     460
     461    def values_group(self):
     462        """
     463        The common parent of the values.
     464
     465        The values need to form a multiplicative group, but can be
     466        embedded in a larger structure. For example, if the values are
     467        units in a ring then the :meth:`values_group` would be the
     468        whole ring.
     469
     470        OUTPUT:
     471
     472        The common parent of the values, containing the group
     473        generated by all values.
     474
     475        EXAMPLES::
     476
     477            sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
     478            sage: G.values_group()
     479            Integer Ring
     480
     481            sage: Z4 = AbelianGroupWithValues([I], [4])
     482            sage: Z4.values_group()
     483            Symbolic Ring
     484        """
     485        return self._values_group
     486
     487    def values_embedding(self):
     488        """
     489        Return the embedding of ``self`` in :meth:`values_group`.
     490
     491        OUTPUT:
     492
     493        A morphism.
     494
     495        EXAMPLES::
     496
     497            sage: Z4 = AbelianGroupWithValues([I], [4])
     498            sage: Z4.values_embedding()
     499            Generic morphism:
     500              From: Multiplicative Abelian group isomorphic to C4
     501              To:   Symbolic Ring
     502        """
     503        return AbelianGroupWithValuesEmbedding(self, self.values_group())
  • sage/groups/additive_abelian/additive_abelian_group.py

    diff --git a/sage/groups/additive_abelian/additive_abelian_group.py b/sage/groups/additive_abelian/additive_abelian_group.py
    a b  
    66major differences are in the way elements are printed.
    77"""
    88
    9 from sage.groups.group import AbelianGroup
     9from sage.groups.old import AbelianGroup
    1010from sage.modules.fg_pid.fgp_module import FGP_Module_class
    1111from sage.modules.fg_pid.fgp_element import FGP_Element
    1212from sage.rings.all import ZZ
  • sage/groups/group.pxd

    diff --git a/sage/groups/group.pxd b/sage/groups/group.pxd
    a b  
    1 cimport sage.structure.parent_gens
     1from sage.structure.parent cimport Parent
    22
    3 cdef class Group(sage.structure.parent_gens.ParentWithGens):
     3cdef class Group(Parent):
    44    pass
    55
    66cdef class AbelianGroup(Group):
  • sage/groups/group.pyx

    diff --git a/sage/groups/group.pyx b/sage/groups/group.pyx
    a b  
    1717#                  http://www.gnu.org/licenses/
    1818#*****************************************************************************
    1919
    20 doc="""
    21 Base class for all groups
    22 """
    23 
    2420import random
    2521
    26 from   sage.rings.infinity import infinity
    27 import sage.rings.integer_ring
     22from sage.structure.parent cimport Parent
     23from sage.rings.infinity import infinity
     24from sage.rings.integer_ring import ZZ
    2825
    29 cdef class Group(sage.structure.parent_gens.ParentWithGens):
     26cdef class Group(Parent):
    3027    """
    31     Generic group class
     28    Base class for all groups
     29
     30    TESTS::
     31
     32        sage: from sage.groups.group import Group
     33        sage: G = Group()
     34        sage: TestSuite(G).run()
     35        Failure in _test_an_element:
     36        Traceback (most recent call last):
     37        ...
     38        The following tests failed:
     39        _test_an_element, _test_associativity, _test_elements,
     40        _test_elements_eq, _test_inverse, _test_one,
     41        _test_pickling, _test_prod, _test_some_elements
    3242    """
    33     def __init__(self, category = None):
     43    def __init__(self, gens=None, category=None):
    3444        """
     45        The Python constructor
    3546
    3647        TESTS::
    3748
     
    3950            sage: G = Group()
    4051            sage: G.category()
    4152            Category of groups
    42             sage: G = Group(category = Groups()) # todo: do the same test with some subcategory of Groups when there will exist one
     53            sage: G = Group(category=Groups()) # todo: do the same test with some subcategory of Groups when there will exist one
    4354            sage: G.category()
    4455            Category of groups
    4556            sage: G = Group(category = CommutativeAdditiveGroups())
    4657            Traceback (most recent call last):
    4758            ...
    48             AssertionError: Category of commutative additive groups is not a subcategory of Category of groups
     59            ValueError: Category of commutative additive groups is not a subcategory of Category of groups
    4960
    50          Check for #8119::
     61        Check for #8119::
    5162
    5263            sage: G = SymmetricGroup(2)
    5364            sage: h = hash(G)
     
    5566            sage: h == hash(G)
    5667            True
    5768        """
    58         from sage.categories.basic import Groups
     69        from sage.categories.groups import Groups
    5970        if category is None:
    6071            category = Groups()
    6172        else:
    62             assert category.is_subcategory(Groups()), "%s is not a subcategory of %s"%(category, Groups())
    63 
    64         sage.structure.parent_gens.ParentWithGens.__init__(self,
    65                 sage.rings.integer_ring.ZZ, category = category)
     73            if not category.is_subcategory(Groups()):
     74                raise ValueError("%s is not a subcategory of %s"%(category, Groups()))
     75        Parent.__init__(self, base=ZZ, gens=gens, category=category)
    6676   
    67     #def __call__(self, x): # this gets in the way of the coercion mechanism
    68     #    """
    69     #    Coerce x into this group.
    70     #    """
    71     #    raise NotImplementedError
    72 
    7377    def __contains__(self, x):
    7478        r"""
    75         True if coercion of `x` into self is defined.
     79        Test whether `x` defines a group element.
     80
     81        INPUT:
     82
     83        - ``x`` -- anything.
     84
     85        OUTPUT:
     86
     87        Boolean.
    7688
    7789        EXAMPLES::
    7890
     
    89101            return False
    90102        return True
    91103
    92 #    def category(self):
    93 #        """
    94 #        The category of all groups
    95 #        """
    96 #        import sage.categories.all
    97 #        return sage.categories.all.Groups()
    98 
    99104    def is_atomic_repr(self):
    100105        """
    101106        True if the elements of this group have atomic string
     
    113118
    114119    def is_abelian(self):
    115120        """
    116         Return True if this group is abelian.
     121        Test whether this group is abelian.
    117122
    118123        EXAMPLES::
    119124
     
    128133
    129134    def is_commutative(self):
    130135        r"""
    131         Return True if this group is commutative. This is an alias for
    132         is_abelian, largely to make groups work well with the Factorization
    133         class.
     136        Test whether this group is commutative.
     137
     138        This is an alias for is_abelian, largely to make groups work
     139        well with the Factorization class.
    134140
    135141        (Note for developers: Derived classes should override is_abelian, not
    136142        is_commutative.)
     
    189195        """
    190196        return True
    191197
     198    def _an_element_(self):
     199        """
     200        Return an element
     201
     202        OUTPUT:
     203
     204        An element of the group.
     205
     206        EXAMPLES:
     207
     208            sage: G = AbelianGroup([2,3,4,5])
     209            sage: G.an_element()
     210            f0*f1*f2*f3
     211        """
     212        from sage.misc.misc import prod
     213        return prod(self.gens())
     214
    192215    def random_element(self, bound=None):
    193216        """
    194217        Return a random element of this group.
     
    256279
    257280    def cayley_graph(self, connecting_set=None):
    258281        """
    259         Returns the cayley graph for this finite group, as a Sage DiGraph
    260         object. To plot the graph with with different colors
     282        Return the Cayley graph for this finite group.
     283
     284        INPUT:
    261285       
    262         INPUT::
    263        
    264             `connecting_set` - (optional) list of elements to use for edges,
    265                                default is the stored generators
     286        - ``connecting_set`` -- (optional) list of elements to use for
     287          edges, default is the stored generators
     288
     289        OUTPUT:
     290
     291        The Cayley graph as a Sage DiGraph object. To plot the graph
     292        with with different colors
    266293       
    267294        EXAMPLES::
    268295       
     
    283310            sage: g=PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i])
    284311            sage: g.cayley_graph(connecting_set=[(1,2),(2,3)])
    285312            Digraph on 120 vertices
    286 
    287         ::
    288313       
    289314            sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices()
    290315            [()]
     
    292317        AUTHORS:
    293318
    294319        - Bobby Moretti (2007-08-10)
    295 
    296320        - Robert Miller (2008-05-01): editing
    297321        """
    298322        if connecting_set is None:
    299323            connecting_set = self.gens()
    300324        else:
    301             try:
    302                 for g in connecting_set:
    303                     assert g in self
    304             except AssertionError:
    305                 raise RuntimeError("Each element of the connecting set must be in the group!")
     325            if any(g not in self for g in connecting_set):
     326                raise ValueError("Each element of the connecting set must be in the group!")
    306327            connecting_set = [self(g) for g in connecting_set]
    307328        from sage.graphs.all import DiGraph
    308329        arrows = {}
     
    315336
    316337        return DiGraph(arrows, implementation='networkx')
    317338
    318 cdef class AlgebraicGroup(Group):
    319     """
    320     Generic algebraic group.
    321     """
  • sage/groups/matrix_gps/matrix_group.py

    diff --git a/sage/groups/matrix_gps/matrix_group.py b/sage/groups/matrix_gps/matrix_group.py
    a b  
    7979from sage.categories.finite_groups import FiniteGroups
    8080from sage.structure.parent import Parent
    8181from matrix_group_element import MatrixGroupElement
    82 from sage.groups.group import Group
     82from sage.groups.old import Group
    8383from sage.rings.all import is_Ring, infinity
    8484from sage.rings.finite_rings.constructor import is_FiniteField
    8585from sage.interfaces.gap import gap
  • .pyx

    diff --git a/sage/groups/group.pxd b/sage/groups/old.pxd
    copy from sage/groups/group.pxd
    copy to sage/groups/old.pxd
    diff --git a/sage/groups/group.pyx b/sage/groups/old.pyx
    copy from sage/groups/group.pyx
    copy to sage/groups/old.pyx
    old new  
    11"""
    22Base class for groups
    33"""
    4  
     4
    55#*****************************************************************************
    66#       Copyright (C) 2005 William Stein <wstein@gmail.com>
    77#
     
    3535
    3636        TESTS::
    3737
    38             sage: from sage.groups.group import Group
     38            sage: from sage.groups.old import Group
    3939            sage: G = Group()
    4040            sage: G.category()
    4141            Category of groups
     
    6363
    6464        sage.structure.parent_gens.ParentWithGens.__init__(self,
    6565                sage.rings.integer_ring.ZZ, category = category)
    66    
     66
    6767    #def __call__(self, x): # this gets in the way of the coercion mechanism
    6868    #    """
    6969    #    Coerce x into this group.
     
    7676
    7777        EXAMPLES::
    7878
    79             sage: from sage.groups.group import Group
     79            sage: from sage.groups.old import Group
    8080            sage: G = Group()
    8181            sage: 4 in G               #indirect doctest
    8282            Traceback (most recent call last):
     
    104104
    105105        EXAMPLES::
    106106
    107             sage: from sage.groups.group import Group
     107            sage: from sage.groups.old import Group
    108108            sage: G = Group()
    109109            sage: G.is_atomic_repr()
    110110            False
     
    117117
    118118        EXAMPLES::
    119119
    120             sage: from sage.groups.group import Group
     120            sage: from sage.groups.old import Group
    121121            sage: G = Group()
    122122            sage: G.is_abelian()
    123123            Traceback (most recent call last):
     
    149149
    150150        EXAMPLES::
    151151
    152             sage: from sage.groups.group import Group
     152            sage: from sage.groups.old import Group
    153153            sage: G = Group()
    154154            sage: G.order()
    155155            Traceback (most recent call last):
     
    164164
    165165        EXAMPLES::
    166166
    167             sage: from sage.groups.group import Group
     167            sage: from sage.groups.old import Group
    168168            sage: G = Group()
    169169            sage: G.is_finite()
    170170            Traceback (most recent call last):
     
    172172            NotImplementedError
    173173        """
    174174        return self.order() != infinity
    175        
     175
    176176    def is_multiplicative(self):
    177177        """
    178178        Returns True if the group operation is given by \* (rather than
    179179        +).
    180        
     180
    181181        Override for additive groups.
    182182
    183183        EXAMPLES::
    184184
    185             sage: from sage.groups.group import Group
     185            sage: from sage.groups.old import Group
    186186            sage: G = Group()
    187187            sage: G.is_multiplicative()
    188188            True
     
    195195
    196196        EXAMPLES::
    197197
    198             sage: from sage.groups.group import Group
     198            sage: from sage.groups.old import Group
    199199            sage: G = Group()
    200200            sage: G.random_element()
    201201            Traceback (most recent call last):
     
    211211
    212212        EXAMPLES::
    213213
    214             sage: from sage.groups.group import Group
     214            sage: from sage.groups.old import Group
    215215            sage: G = Group()
    216216            sage: G.quotient(G)
    217217            Traceback (most recent call last):
     
    230230
    231231        EXAMPLES::
    232232
    233             sage: from sage.groups.group import AbelianGroup
     233            sage: from sage.groups.old import AbelianGroup
    234234            sage: G = AbelianGroup()
    235235            sage: G.is_abelian()
    236236            True
     
    247247
    248248        EXAMPLES::
    249249
    250             sage: from sage.groups.group import FiniteGroup
     250            sage: from sage.groups.old import FiniteGroup
    251251            sage: G = FiniteGroup()
    252252            sage: G.is_finite()
    253253            True
     
    258258        """
    259259        Returns the cayley graph for this finite group, as a Sage DiGraph
    260260        object. To plot the graph with with different colors
    261        
     261
    262262        INPUT::
    263        
     263
    264264            `connecting_set` - (optional) list of elements to use for edges,
    265265                               default is the stored generators
    266        
     266
    267267        EXAMPLES::
    268        
     268
    269269            sage: D4 = DihedralGroup(4); D4
    270270            Dihedral group of order 8 as a permutation group
    271271            sage: G = D4.cayley_graph()
     
    285285            Digraph on 120 vertices
    286286
    287287        ::
    288        
     288
    289289            sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices()
    290290            [()]
    291        
     291
    292292        AUTHORS:
    293293
    294         - Bobby Moretti (2007-08-10) 
     294        - Bobby Moretti (2007-08-10)
    295295
    296296        - Robert Miller (2008-05-01): editing
    297297        """
  • sage/groups/pari_group.py

    diff --git a/sage/groups/pari_group.py b/sage/groups/pari_group.py
    a b  
    22PARI Groups
    33"""
    44
    5 import group
     5from sage.groups.old import Group
    66from sage.libs.all import pari_gen
    77from sage.rings.all import Integer
    88from sage.structure.parent import Parent
    99
    10 class PariGroup(group.Group):
     10class PariGroup(Group):
    1111    def __init__(self, x, degree=None):
    1212        """
    1313        EXAMPLES::
  • sage/groups/perm_gps/permgroup.py

    diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
    a b  
    123123from functools import wraps
    124124
    125125from sage.misc.randstate import current_randstate
    126 import sage.groups.group as group
     126import sage.groups.old as group
    127127
    128128from sage.rings.all import QQ, Integer
    129129from sage.interfaces.all import is_ExpectElement
     
    21302130       
    21312131            sage: G = SymmetricGroup(4)
    21322132            sage: G.cohomology(1,2)                            # optional - gap_packages
    2133             Multiplicative Abelian Group isomorphic to C2
     2133            Multiplicative Abelian group isomorphic to C2
    21342134            sage: G = SymmetricGroup(3)
    21352135            sage: G.cohomology(5)                              # optional - gap_packages
    2136             Trivial Abelian Group
     2136            Trivial Abelian group
    21372137            sage: G.cohomology(5,2)                            # optional - gap_packages
    2138             Multiplicative Abelian Group isomorphic to C2
     2138            Multiplicative Abelian group isomorphic to C2
    21392139            sage: G.homology(5,3)                              # optional - gap_packages
    2140             Trivial Abelian Group
     2140            Trivial Abelian group
    21412141            sage: G.homology(5,4)                              # optional - gap_packages
    21422142            Traceback (most recent call last):
    21432143            ...
     
    21802180       
    21812181            sage: G = SymmetricGroup(5)
    21822182            sage: G.cohomology_part(7,2)                   # optional - gap_packages
    2183             Multiplicative Abelian Group isomorphic to C2 x C2 x C2
     2183            Multiplicative Abelian group isomorphic to C2 x C2 x C2
    21842184            sage: G = SymmetricGroup(3)
    21852185            sage: G.cohomology_part(2,3)                   # optional - gap_packages
    2186             Multiplicative Abelian Group isomorphic to C3
     2186            Multiplicative Abelian group isomorphic to C3
    21872187       
    21882188        AUTHORS:
    21892189
     
    22242224       
    22252225            sage: G = SymmetricGroup(5)
    22262226            sage: G.homology(7)                              # optional - gap_packages
    2227             Multiplicative Abelian Group isomorphic to C2 x C2 x C4 x C3 x C5
     2227            Multiplicative Abelian group isomorphic to C2 x C2 x C4 x C3 x C5
    22282228            sage: G.homology(7,2)                              # optional - gap_packages
    2229             Multiplicative Abelian Group isomorphic to C2 x C2 x C2 x C2 x C2
     2229            Multiplicative Abelian group isomorphic to C2 x C2 x C2 x C2 x C2
    22302230            sage: G.homology(7,3)                              # optional - gap_packages
    2231             Multiplicative Abelian Group isomorphic to C3
     2231            Multiplicative Abelian group isomorphic to C3
    22322232            sage: G.homology(7,5)                              # optional - gap_packages
    2233             Multiplicative Abelian Group isomorphic to C5
     2233            Multiplicative Abelian group isomorphic to C5
    22342234       
    22352235        REFERENCES:
    22362236
     
    22622262       
    22632263            sage: G = SymmetricGroup(5)
    22642264            sage: G.homology_part(7,2)                              # optional - gap_packages
    2265             Multiplicative Abelian Group isomorphic to C2 x C2 x C2 x C2 x C4
     2265            Multiplicative Abelian group isomorphic to C2 x C2 x C2 x C2 x C4
    22662266       
    22672267        AUTHORS:
    22682268
  • sage/groups/perm_gps/permgroup_element.pyx

    diff --git a/sage/groups/perm_gps/permgroup_element.pyx b/sage/groups/perm_gps/permgroup_element.pyx
    a b  
    5656
    5757import random
    5858
    59 import sage.groups.group as group
     59import sage.groups.old as group
    6060
    6161include "../../ext/stdsage.pxi"
    6262include "../../ext/interrupt.pxi"
  • sage/groups/perm_gps/permgroup_named.py

    diff --git a/sage/groups/perm_gps/permgroup_named.py b/sage/groups/perm_gps/permgroup_named.py
    a b  
    482482            True
    483483            sage: C = CyclicPermutationGroup(10)
    484484            sage: C.as_AbelianGroup()
    485             Multiplicative Abelian Group isomorphic to C2 x C5
     485            Multiplicative Abelian group isomorphic to C2 x C5
    486486
    487487        TESTS::
    488488
     
    529529        """
    530530        Returns the corresponding Abelian Group instance.
    531531       
    532         EXAMPLES:
     532        EXAMPLES::
     533
    533534            sage: C = CyclicPermutationGroup(8)
    534535            sage: C.as_AbelianGroup()
    535             Multiplicative Abelian Group isomorphic to C8
    536 
     536            Multiplicative Abelian group isomorphic to C8
    537537        """
    538538        n = self.order()
    539539        a = list(factor(n))
  • sage/gsl/dft.py

    diff --git a/sage/gsl/dft.py b/sage/gsl/dft.py
    a b  
    224224            sage: s = IndexedSequence([1,2,3,4,5,6],J)
    225225            sage: s.dft()   # the precision of output is somewhat random and architecture dependent.
    226226            Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I]                       
    227                 indexed by Multiplicative Abelian Group isomorphic to C2 x C3
     227                indexed by Multiplicative Abelian group isomorphic to C2 x C3
    228228            sage: J = CyclicPermutationGroup(6)
    229229            sage: s = IndexedSequence([1,2,3,4,5,6],J)
    230230            sage: s.dft()   # the precision of output is somewhat random and architecture dependent.
  • sage/homology/chain_complex.py

    diff --git a/sage/homology/chain_complex.py b/sage/homology/chain_complex.py
    a b  
    11861186
    11871187        sage: from sage.homology.chain_complex import HomologyGroup
    11881188        sage: G = AbelianGroup(5,[5,5,7,8,9]); G
    1189         Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
     1189        Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9
    11901190        sage: H = HomologyGroup(5,[5,5,7,8,9]); H
    11911191        C5 x C5 x C7 x C8 x C9
    11921192        sage: G == loads(dumps(G))
    11931193        True
    11941194        sage: AbelianGroup(4)
    1195         Multiplicative Abelian Group isomorphic to Z x Z x Z x Z
     1195        Multiplicative Abelian group isomorphic to Z x Z x Z x Z
    11961196        sage: HomologyGroup(4)
    11971197        Z x Z x Z x Z
    11981198        sage: HomologyGroup(100)
     
    12951295
    12961296        sage: from sage.homology.chain_complex import HomologyGroup
    12971297        sage: G = AbelianGroup(5,[5,5,7,8,9]); G
    1298         Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
     1298        Multiplicative Abelian group isomorphic to C5 x C5 x C7 x C8 x C9
    12991299        sage: H = HomologyGroup(5,[5,5,7,8,9]); H
    13001300        C5 x C5 x C7 x C8 x C9
    13011301        sage: AbelianGroup(4)
    1302         Multiplicative Abelian Group isomorphic to Z x Z x Z x Z
     1302        Multiplicative Abelian group isomorphic to Z x Z x Z x Z
    13031303        sage: HomologyGroup(4)
    13041304        Z x Z x Z x Z
    13051305        sage: HomologyGroup(100)
  • sage/interfaces/gap.py

    diff --git a/sage/interfaces/gap.py b/sage/interfaces/gap.py
    a b  
    10831083            max_workspace_size = _get_gap_memory_pool_size_MB()
    10841084        cmd += ' -o ' + str(max_workspace_size)
    10851085        cmd += ' -s ' + str(max_workspace_size)
     1086        cmd += ' -m 64m '   # attempt at a workaround for http://tracker.gap-system.org/issues/224
    10861087        cmd += ' ' + os.path.join(SAGE_EXTCODE,'gap','sage.g')
    10871088        Expect.__init__(self,
    10881089                        name='gap',
  • sage/modular/arithgroup/arithgroup_generic.py

    diff --git a/sage/modular/arithgroup/arithgroup_generic.py b/sage/modular/arithgroup/arithgroup_generic.py
    a b  
    1515################################################################################
    1616
    1717
    18 import sage.groups.group as group
     18import sage.groups.old as group
    1919from sage.rings.all import ZZ
    2020import sage.rings.arith as arith
    2121from sage.misc.cachefunc import cached_method
  • sage/modular/arithgroup/congroup_gammaH.py

    diff --git a/sage/modular/arithgroup/congroup_gammaH.py b/sage/modular/arithgroup/congroup_gammaH.py
    a b  
    134134        sage: sage.modular.arithgroup.congroup_gammaH._normalize_H([-1,7,9], 10)
    135135        [7, 9]
    136136    """
    137     if not isinstance(H, list):
    138         raise TypeError, "H must be a list."
    139137    H = [ZZ(h) for h in H]
    140138    for h in H:
    141139        if gcd(h, level) > 1:
  • sage/modular/cusps_nf.py

    diff --git a/sage/modular/cusps_nf.py b/sage/modular/cusps_nf.py
    a b  
    13231323    k = I.number_field()
    13241324    Uk = k.unit_group()
    13251325    Istar = I.idealstar(2)
    1326     ulist = Uk.gens()
     1326    ulist = Uk.gens_values()
    13271327    elist = [Istar(I.ideallog(u)).order() for u in ulist]
    13281328
    13291329    from sage.misc.mrange import xmrange
  • sage/modular/dirichlet.py

    diff --git a/sage/modular/dirichlet.py b/sage/modular/dirichlet.py
    a b  
    280280            sage: e(7)
    281281            -zeta4
    282282            sage: Integers(60).unit_gens()
    283             [31, 41, 37]
     283            (31, 41, 37)
    284284            sage: e(31)
    285285            -1
    286286            sage: e(41)
     
    16561656        sage: G.gens()
    16571657        (Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1, Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4)
    16581658        sage: G.unit_gens()
    1659         [11, 17]
     1659        (11, 17)
    16601660        sage: G.zeta()
    16611661        zeta4
    16621662        sage: G.zeta_order()
     
    23272327        EXAMPLES::
    23282328       
    23292329            sage: DirichletGroup(37).unit_gens()
    2330             [2]
     2330            (2,)
    23312331            sage: DirichletGroup(20).unit_gens()
    2332             [11, 17]
     2332            (11, 17)
    23332333            sage: DirichletGroup(60).unit_gens()
    2334             [31, 41, 37]
     2334            (31, 41, 37)
    23352335            sage: DirichletGroup(20,QQ).unit_gens()
    2336             [11, 17]
     2336            (11, 17)
    23372337        """
    23382338        return self._integers.unit_gens()
    23392339
  • sage/modular/etaproducts.py

    diff --git a/sage/modular/etaproducts.py b/sage/modular/etaproducts.py
    a b  
    3333from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
    3434from sage.rings.arith import divisors, prime_divisors, is_square, euler_phi, gcd
    3535from sage.rings.all import Integer, IntegerRing, RationalField
    36 from sage.groups.group import AbelianGroup
     36from sage.groups.old import AbelianGroup
    3737from sage.structure.element import MultiplicativeGroupElement
    3838from sage.structure.formal_sum import FormalSum
    3939from sage.rings.finite_rings.integer_mod import Mod
  • sage/modular/local_comp/smoothchar.py

    diff --git a/sage/modular/local_comp/smoothchar.py b/sage/modular/local_comp/smoothchar.py
    a b  
    15051505            # topologically cyclic. I don't know an explicit set of good
    15061506            # generators here, so we let Pari do the work and put up with the
    15071507            # rather arbitrary (nondeterministic?) results.
    1508             return list(self.ideal(c).idealstar(2).gens()) + [s]
     1508            return list(self.ideal(c).idealstar(2).gens_values()) + [s]
    15091509   
    15101510    def exponents(self, c):
    15111511        r"""
     
    15171517            sage: from sage.modular.local_comp.smoothchar import SmoothCharacterGroupRamifiedQuadratic
    15181518            sage: G = SmoothCharacterGroupRamifiedQuadratic(5, 0, QQ)
    15191519            sage: G.exponents(0)
    1520             [0]
     1520            (0,)
    15211521            sage: G.exponents(1)
    1522             [4, 0]
     1522            (4, 0)
    15231523            sage: G.exponents(8)
    1524             [500, 625, 0]
     1524            (500, 625, 0)
    15251525        """   
    15261526        c = ZZ(c)
    15271527        d = ceil(c / 2)
    15281528        p = self.prime()
    15291529        if c == 0:
    1530             return [0]
     1530            return tuple([0])
    15311531        elif c == 1:
    1532             return [p - 1, 0]
     1532            return tuple([p - 1, 0])
    15331533        elif p > 3 or self._unif_sqr == 3 or c <= 3:
    1534             return [p**(d-1)*(p - 1), p**ceil((c - 1)/2), 0]
     1534            return tuple([p**(d-1)*(p - 1), p**ceil((c - 1)/2), 0])
    15351535        else:
    15361536            # awkward case, see above
    1537             return self.ideal(c).idealstar(2).invariants() + [0]
     1537            return self.ideal(c).idealstar(2).gens_orders() + (0,)
    15381538
    15391539    def subgroup_gens(self, level):
    15401540        r"""
  • sage/modular/modsym/p1list_nf.py

    diff --git a/sage/modular/modsym/p1list_nf.py b/sage/modular/modsym/p1list_nf.py
    a b  
    939939            sage: k.<a> = NumberField(x^3 + 11)
    940940            sage: N = k.ideal(5, a + 1)
    941941            sage: P = P1NFList(N)
    942             sage: u = k.unit_group().gens(); u
     942            sage: u = k.unit_group().gens_values(); u
    943943            [-1, 2*a^2 + 4*a - 1]
    944944            sage: P.apply_J_epsilon(4, -1)
    945945            2
     
    951951            sage: k.<a> = NumberField(x^4 + 13*x - 7)
    952952            sage: N = k.ideal(a + 1)
    953953            sage: P = P1NFList(N)
    954             sage: u = k.unit_group().gens(); u
     954            sage: u = k.unit_group().gens_values(); u
    955955            [-1, a^3 + a^2 + a + 12, a^3 + 3*a^2 - 1]
    956956            sage: P.apply_J_epsilon(3, u[2]^2)==P.apply_J_epsilon(P.apply_J_epsilon(3, u[2]),u[2])
    957957            True
  • sage/rings/finite_rings/integer_mod_ring.py

    diff --git a/sage/rings/finite_rings/integer_mod_ring.py b/sage/rings/finite_rings/integer_mod_ring.py
    a b  
    268268            16
    269269            sage: gens = Z16.unit_gens()
    270270            sage: gens
    271             [15, 5]
     271            (15, 5)
    272272            sage: a = gens[0]
    273273            sage: b = gens[1]
    274274            sage: def powa(i): return a**i
     
    454454        EXAMPLES::
    455455       
    456456            sage: Integers(5).multiplicative_subgroups()
    457             ([2], [4], [])
     457            ((2,), (4,), ())
    458458            sage: Integers(15).multiplicative_subgroups()
    459             ([11, 7], [4, 11], [8], [11], [14], [7], [4], [])
     459            ((11, 7), (4, 11), (8,), (11,), (14,), (7,), (4,), ())
    460460            sage: Integers(2).multiplicative_subgroups()
    461             ([],)
     461            ((),)
    462462            sage: len(Integers(341).multiplicative_subgroups())
    463463            80
     464
     465        TESTS::
     466
     467            sage: IntegerModRing(1).multiplicative_subgroups()
     468            ((0,),)
     469            sage: IntegerModRing(2).multiplicative_subgroups()
     470            ((),)
     471            sage: IntegerModRing(3).multiplicative_subgroups()
     472            ((2,), ())
    464473        """
    465         from sage.groups.abelian_gps.abelian_group import AbelianGroup
    466         from sage.misc.misc import mul
     474        from sage.groups.abelian_gps.values import AbelianGroupWithValues
    467475        U = self.unit_gens()
    468         G = AbelianGroup([x.multiplicative_order() for x in U])
    469         rawsubs = G.subgroups()
     476        G = AbelianGroupWithValues(U, [x.multiplicative_order() for x in U], values_group=self)
    470477        mysubs = []
    471         for G in rawsubs:
    472             mysubs.append([])
    473             for s in G.gens():
    474                 mysubs[-1].append(mul([U[i] ** s.list()[i] for i in xrange(len(U))]))
    475         return tuple(mysubs) # make it immutable, so that we can cache
     478        for Gsub in G.subgroups():
     479            mysubs.append(tuple( g.value() for g in Gsub.gens() ))
     480        return tuple(mysubs)
    476481
    477482    def is_finite(self):
    478483        """
     
    641646            ...
    642647            ValueError: multiplicative group of this ring is not cyclic
    643648            sage: Integers(25*3).unit_gens()
    644             [26, 52]
     649            (26, 52)
    645650            sage: Integers(162).unit_gens()
    646             [83]
     651            (83,)
    647652        """
    648653        try:
    649654            return self.__mult_gen
     
    11131118                    return [a]
    11141119            assert False, "p=%s, r=%s, couldn't find generator"%(p,r)
    11151120       
     1121    @cached_method
    11161122    def unit_gens(self):
    11171123        r"""
    11181124        Returns generators for the unit group `(\ZZ/N\ZZ)^*`.
     
    11231129        there will be 0, 1 or 2 generators according to whether 2 divides N to
    11241130        order 1, 2 or `\ge 3`.
    11251131       
    1126         INPUT: (none)
    1127        
    11281132        OUTPUT:
    11291133       
    1130         -  ``list`` - a list of elements of self
     1134        A tuple containing the units of ``self``.
    11311135       
    11321136        EXAMPLES::
    11331137       
    11341138            sage: R = IntegerModRing(18)
    11351139            sage: R.unit_gens()
    1136             [11]
     1140            (11,)
    11371141            sage: R = IntegerModRing(17)
    11381142            sage: R.unit_gens()
    1139             [3]
     1143            (3,)
    11401144            sage: IntegerModRing(next_prime(10^30)).unit_gens()
    1141             [5]
     1145            (5,)
     1146
     1147        TESTS::
     1148
     1149            sage: IntegerModRing(2).unit_gens()
     1150            ()
     1151            sage: IntegerModRing(4).unit_gens()
     1152            (3,)
     1153            sage: IntegerModRing(8).unit_gens()
     1154            (7, 5)
    11421155        """
    1143         try:
    1144             return self.__unit_gens
    1145         except AttributeError:
    1146             self.__unit_gens = []
    11471156        n = self.__order
    11481157        if n == 1:
    1149             self.__unit_gens = [self(1)]
    1150             return self.__unit_gens
     1158            return (self(1),)
     1159        unit_gens = []
    11511160        for p,r in self.factored_order():
    11521161            m = n/(p**r)
    11531162            for g in self.__unit_gens_primepowercase(p, r):
    11541163                x = g.crt(integer_mod.Mod(1,m))
    11551164                if x != 1:
    1156                     self.__unit_gens.append(x)
    1157         return self.__unit_gens
     1165                    unit_gens.append(x)
     1166        return tuple(unit_gens)
    11581167   
    11591168    def unit_group_exponent(self):
    11601169        """
  • sage/rings/number_field/class_group.py

    diff --git a/sage/rings/number_field/class_group.py b/sage/rings/number_field/class_group.py
    a b  
    55An element of a class group is stored as a pair consisting of both an explicit
    66ideal in that ideal class, and a list of exponents giving that ideal class in
    77terms of the generators of the parent class group. These can be accessed with
    8 the ``ideal()`` and ``list()`` methods respectively.
     8the ``ideal()`` and ``exponents()`` methods respectively.
    99
    1010EXAMPLES::
    1111
    1212    sage: K.<a> = NumberField(x^2 + 23)
    1313    sage: I = K.class_group().gen(); I
    1414    Fractional ideal class (2, 1/2*a - 1/2)
    15     sage: J = I * I; J
     15    sage: I.ideal()
     16    Fractional ideal (2, 1/2*a - 1/2)
     17    sage: I.exponents()
     18    (1,)
     19
     20    sage: I.ideal() * I.ideal()
     21    Fractional ideal (4, 1/2*a + 3/2)
     22    sage: (I.ideal() * I.ideal()).reduce_equiv()
     23    Fractional ideal (2, 1/2*a + 1/2)
     24    sage: J = I * I; J    # class group multiplication is automatically reduced
    1625    Fractional ideal class (2, 1/2*a + 1/2)
    17     sage: J.list()
    18     [2]
     26    sage: J.ideal()
     27    Fractional ideal (2, 1/2*a + 1/2)
     28    sage: J.exponents()
     29    (2,)
     30
     31    sage: I * I.ideal()   # ideal classes coerce to their representative ideal
     32    Fractional ideal (4, 1/2*a + 3/2)
     33
    1934    sage: O = K.OK(); O
    2035    Maximal Order in Number Field in a with defining polynomial x^2 + 23
    2136    sage: O*(2, 1/2*a + 1/2)
     
    2641    Fractional ideal (1/2*a - 3/2)
    2742"""
    2843
    29 from sage.groups.abelian_gps.abelian_group import AbelianGroup_class
     44from sage.groups.abelian_gps.values import AbelianGroupWithValues_class, AbelianGroupWithValuesElement
     45from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
    3046from sage.structure.sequence import Sequence
    3147from sage.structure.element import MonoidElement
    32 from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
    33 from sage.groups.group import Group
     48from sage.groups.old import Group
    3449from sage.rings.arith import LCM
     50from sage.rings.all import ZZ
    3551
    36 class ClassGroup(AbelianGroup_class):
    37     r"""
    38     The class group of a number field.
    39     """
    40     def __init__(self, invariants, names, number_field, gens, proof=True):
    41         r"""
    42         Create a class group.
    4352
    44         Note that the error in the test suite below is caused by the fact that
    45         there is no category of additive abelian groups.
    46 
    47         EXAMPLES::
    48 
    49             sage: K.<a> = NumberField(x^2 + 23)
    50             sage: G = K.class_group(); G
    51             Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23
    52 
    53             sage: G.category()
    54             Category of groups
    55             sage: TestSuite(G).run() # see #7945
    56               Failure in _test_category:
    57             ...
    58             The following tests failed: _test_elements
    59         """
    60         AbelianGroup_class.__init__(self, len(invariants), invariants, names)
    61         self._proof_flag = proof
    62         self.__number_field = number_field
    63         self.__gens = Sequence([FractionalIdealClass(self, x) for x in gens], immutable=True,
    64                                universe=self, check=False)
    65 
    66     def __call__(self, *args, **kwds):
    67         r"""
    68         Call method. This exists *purely* to override the old-fashioned
    69         behaviour of the parent AbelianGroup class and ensure that
    70         :meth:`element_constructor` gets called.
    71        
    72         EXAMPLE::
    73        
    74             sage: K.<b> = NumberField(x^2 + 389)
    75             sage: C = K.class_group()
    76             sage: C(K.ideal(b))
    77             Trivial principal fractional ideal class
    78         """
    79         return Group.__call__(self, *args, **kwds)
    80 
    81     def _element_constructor_(self, *args, **kwds):
    82         r"""
    83         Create an element of this class group from the given data. This may be:
    84         an ideal class in this number field; an ideal class in a subfield; or
    85         anything from which an ideal in this number field can be constructed.
    86 
    87         EXAMPLES::
    88 
    89             sage: K.<b> = NumberField(x^2 + 389)
    90             sage: C = K.class_group()
    91             sage: C(K.ideal(b)) # indirect doctest
    92             Trivial principal fractional ideal class
    93             sage: C(K.ideal(59049, b + 35312)) # indirect doctest
    94             Fractional ideal class (59049, b + 35312)
    95             sage: C((59049, b + 35312)) # indirect doctest
    96             Fractional ideal class (59049, b + 35312)
    97             sage: C(59049, b + 35312) # indirect doctest
    98             Fractional ideal class (59049, b + 35312)
    99 
    100             sage: K.<a> = QuadraticField(-23)
    101             sage: L.<b> = K.extension(x^2 - 2)
    102             sage: CK = K.class_group()
    103             sage: CL = L.class_group()
    104             sage: [CL(I).list() for I in CK]
    105             [[0], [2], [4]]
    106         """
    107         if isinstance(args[0], FractionalIdealClass):
    108             return FractionalIdealClass(self, self.__number_field.ideal(args[0].ideal()))
    109         else:
    110             I = self.__number_field.ideal(*args, **kwds)
    111             if I.is_zero(): raise TypeError, "The zero ideal is not a fractional ideal"
    112             return FractionalIdealClass(self, I)
    113 
    114     def gens(self):
    115         r"""
    116         Return generators for the class group.
    117 
    118         EXAMPLES::
    119 
    120             sage: K.<a> = NumberField(x^4 + 23)
    121             sage: K.class_group().gens()   # random gens (platform dependent)
    122             [Fractional ideal class (2, 1/2*a^2 - a + 3/2)]
    123         """
    124         return self.__gens
    125 
    126     def ngens(self):
    127         r"""
    128         Return the number of generators of the class group.
    129 
    130         EXAMPLES::
    131 
    132             sage: C = NumberField(x^2 + x + 23899, 'a').class_group(); C
    133             Class group of order 68 with structure C34 x C2 of Number Field in a with defining polynomial x^2 + x + 23899
    134             sage: C.ngens()
    135             2
    136         """
    137         return len(self.invariants())
    138 
    139     def gen(self, i=0):
    140         r"""
    141         Return the i-th generator for this class group.
    142 
    143         EXAMPLES::
    144 
    145             sage: C = NumberField(x^2 + 120071, 'a').class_group(); C
    146             Class group of order 500 with structure C250 x C2 of Number Field in a with defining polynomial x^2 + 120071
    147             sage: C.gen(0) # random
    148             Fractional ideal class (130, 1/2*a + 137/2)
    149             sage: C.gen(1) # random
    150             Fractional ideal class (7, a)
    151         """
    152         if i < 0 or i >= len(self.__gens):
    153             raise IndexError
    154         return self.__gens[i]
    155 
    156     def __iter__(self):
    157         r"""
    158         Return an iterator of all ideal classes in this class group.
    159 
    160         EXAMPLES::
    161 
    162             sage: K.<a> = NumberField(x^4 + 23)
    163             sage: G = K.class_group()
    164             sage: G
    165             Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^4 + 23
    166             sage: list(G)
    167             [Trivial principal fractional ideal class, Fractional ideal class (2, 1/4*a^3 - 1/4*a^2 + 1/4*a - 1/4), Fractional ideal class (2, 1/2*a^2 + 1/2)]
    168             sage: G.list()
    169             [Trivial principal fractional ideal class, Fractional ideal class (2, 1/4*a^3 - 1/4*a^2 + 1/4*a - 1/4), Fractional ideal class (2, 1/2*a^2 + 1/2)]
    170 
    171         TESTS::
    172 
    173             sage: K.<a> = NumberField(x^2 + 1)
    174             sage: G = K.class_group()
    175             sage: G
    176             Class group of order 1 of Number Field in a with defining polynomial x^2 + 1
    177             sage: list(G)
    178             [Trivial principal fractional ideal class]
    179             sage: G.list()
    180             [Trivial principal fractional ideal class]
    181         """
    182         from sage.misc.mrange import mrange
    183         invs = self.invariants()
    184         T = mrange(invs)
    185         g = self.gens()
    186         for t in T:
    187             I = self(1)
    188             for i, j in enumerate(t):
    189                 I *= g[i]**j
    190             yield I
    191         if not T:
    192             yield self(1)
    193 
    194     def _repr_(self):
    195         r"""
    196         Return string representation of self.
    197 
    198         EXAMPLES::
    199 
    200             sage: C = NumberField(x^2 + 23, 'a').class_group()
    201             sage: C._repr_()
    202             'Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23'       
    203         """
    204         s = 'Class group of order %s '%self.order()
    205         if self.order() > 1:
    206             s += 'with structure %s '%self._group_notation(self.invariants())
    207         s += 'of %s'%self.number_field()
    208         return s
    209 
    210     def number_field(self):
    211         r"""
    212         Return the number field that this class group is attached to.
    213        
    214         EXAMPLES::
    215 
    216             sage: C = NumberField(x^2 + 23, 'w').class_group(); C
    217             Class group of order 3 with structure C3 of Number Field in w with defining polynomial x^2 + 23
    218             sage: C.number_field()
    219             Number Field in w with defining polynomial x^2 + 23
    220         """
    221         return self.__number_field
    222 
    223 
    224 class FractionalIdealClass(AbelianGroupElement):
     53class FractionalIdealClass(AbelianGroupWithValuesElement):
    22554    r"""
    22655    A fractional ideal class in a number field.
    22756   
     
    23160        Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23
    23261        sage: I = G.0; I
    23362        Fractional ideal class (2, 1/2*a - 1/2)
     63        sage: I.ideal()
     64        Fractional ideal (2, 1/2*a - 1/2)
     65
     66        EXAMPLES::
     67
     68            sage: K.<w>=QuadraticField(-23)
     69            sage: OK=K.ring_of_integers()
     70            sage: C=OK.class_group()
     71            sage: P2a,P2b=[P for P,e in (2*OK).factor()]
     72            sage: c = C(P2a); c
     73            Fractional ideal class (2, 1/2*w - 1/2)
     74            sage: c.gens()
     75            (2, 1/2*w - 1/2)
    23476    """
    235     def __init__(self, parent, ideal, element=None):
     77    def __init__(self, element, parent, ideal=None):
    23678        """
    23779        Returns the ideal class of this fractional ideal.
    23880
     
    24284            sage: G(K.ideal(13, a + 4))
    24385            Fractional ideal class (13, 1/2*a + 17/2)
    24486        """
    245         self.__ideal = ideal
    24687        if element is None:
    247             element = map(int, ideal.ideal_class_log(proof=parent._proof_flag))
    248         AbelianGroupElement.__init__(self, parent, element)
     88            element = parent._ideal_log(ideal)
     89        AbelianGroupWithValuesElement.__init__(self, element, parent, ideal)
    24990
    25091    def _repr_(self):
    25192        r"""
     
    261102        """
    262103        if self.is_principal():
    263104            return 'Trivial principal fractional ideal class'
    264         return 'Fractional ideal class %s'%self.__ideal._repr_short()
     105        return 'Fractional ideal class %s'%self._value._repr_short()
    265106
    266107    def _mul_(self, other):
    267108        r"""
    268         Multiplication of two ideal classes.
     109        Multiplication of two (S-)ideal classes.
     110
     111        EXAMPLE::
     112
     113            sage: G = NumberField(x^2 + 23,'a').class_group(); G
     114            Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23
     115            sage: I = G.0; I
     116            Fractional ideal class (2, 1/2*a - 1/2)
     117            sage: I*I # indirect doctest
     118            Fractional ideal class (2, 1/2*a + 1/2)
     119            sage: I*I*I # indirect doctest
     120            Trivial principal fractional ideal class
     121
     122            sage: K.<a> = QuadraticField(-14)
     123            sage: I = K.ideal(2,a)
     124            sage: S = (I,)
     125            sage: CS = K.S_class_group(S)
     126            sage: G = K.ideal(3,a+1)
     127            sage: CS(G)*CS(G)
     128            Trivial S-ideal class
     129        """
     130        m = AbelianGroupElement._mul_(self, other)
     131        m._value = (self.ideal() * other.ideal()).reduce_equiv()
     132        return m
     133
     134    def _div_(self, other):
     135        r"""
     136        Division of two ideal classes.
    269137
    270138        EXAMPLE::
    271139
     
    278146            sage: I*I*I # indirect doctest
    279147            Trivial principal fractional ideal class
    280148        """
    281         m = AbelianGroupElement._mul_(self, other)
    282         return FractionalIdealClass(self.parent(), (self.__ideal * other.__ideal).reduce_equiv(), m.list())
     149        m = AbelianGroupElement._div_(self, other)
     150        m._value = (self.ideal() / other.ideal()).reduce_equiv()
     151        return m
    283152
    284153    def __pow__(self, n):
    285154        r"""
     
    301170        """
    302171        # We use MonoidElement's __pow__ routine, since that does
    303172        # repeated squaring, and hence the ideal gets reduced as
    304         # we go along; actually computing self.__ideal ** n would
     173        # we go along; actually computing self._value ** n would
    305174        # be disastrous.
    306175        n = n % self.order()
    307176        return MonoidElement.__pow__(self, n)
     
    315184            sage: K.<a> = NumberField(x^3 - 3*x + 8); G = K.class_group()
    316185            sage: G(2, a).inverse()
    317186            Fractional ideal class (2, a^2 + 2*a - 1)
    318         """
    319         m = AbelianGroupElement.inverse(self)
    320         return FractionalIdealClass(self.parent(), (~self.__ideal).reduce_equiv(), m.list())
    321 
    322     def __invert__(self):
    323         r"""
    324         Return the multiplicative inverse of this ideal class.
    325        
    326         EXAMPLE::
    327        
    328             sage: K.<a> = NumberField(x^3 - 3*x + 8); G = K.class_group()
    329187            sage: ~G(2, a)
    330188            Fractional ideal class (2, a^2 + 2*a - 1)
    331189        """
    332         return self.inverse()
     190        m = AbelianGroupElement.inverse(self)
     191        m._value = (~self.ideal()).reduce_equiv()
     192        return m
     193
     194    __invert__ = inverse
    333195
    334196    def is_principal(self):
    335197        r"""
     
    359221        EXAMPLES::
    360222
    361223            sage: k.<a> = NumberField(x^2 + 20072); G = k.class_group(); G
    362             Class group of order 76 with structure C38 x C2 of Number Field in a with defining polynomial x^2 + 20072
     224            Class group of order 76 with structure C38 x C2
     225            of Number Field in a with defining polynomial x^2 + 20072
    363226            sage: I = (G.0)^35; I
    364227            Fractional ideal class (41, 1/2*a + 5)
    365228            sage: J = G(I.ideal()^5); J
     
    369232            sage: J == I^5
    370233            True
    371234        """
    372         return self.parent()(self.__ideal.reduce_equiv())
    373 
    374     def order(self):
    375         r"""
    376         Return the order of this ideal class in the class group.
    377 
    378         EXAMPLE::
    379 
    380             sage: K.<w>=QuadraticField(-23)
    381             sage: OK=K.ring_of_integers()
    382             sage: C=OK.class_group()
    383             sage: [c.order() for c in C]
    384             [1, 3, 3]
    385 
    386             sage: k.<a> = NumberField(x^2 + 20072); G = k.class_group(); G
    387             Class group of order 76 with structure C38 x C2 of Number Field in a with defining polynomial x^2 + 20072
    388             sage: [c.order() for c in G.gens()]
    389             [38, 2]
    390 
    391         """
    392         # an old method with a new docstring
    393         return AbelianGroupElement.order(self)
    394 
    395     def multiplicative_order(self):
    396         r"""
    397         Alias for :meth:`order`.
    398        
    399         EXAMPLE::
    400 
    401             sage: K.<w>=QuadraticField(-23)
    402             sage: K.class_group()(K.primes_above(2)[0]).multiplicative_order()
    403             3
    404         """
    405         return self.order()
     235        return self.parent()(self.ideal().reduce_equiv())
    406236
    407237    def ideal(self):
    408238        r"""
     
    419249            sage: c.ideal()
    420250            Fractional ideal (2, 1/2*w - 1/2)
    421251        """
    422         return self.__ideal
     252        return self.value()
    423253
    424254    def gens(self):
    425255        r"""
    426256        Return generators for a representative ideal in this
    427         ideal class.
     257        (S-)ideal class.
    428258
    429</