Ticket #13687: trac_13687_Parent_for_groups.patch

File trac_13687_Parent_for_groups.patch, 200.3 KB (added by Volker Braun, 10 years ago)

Rebased patch

  • doc/de/tutorial/tour_advanced.rst

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1352835583 18000
    # Node ID 9c8926ccf9041d6911d4559b201bb971f2009fc6
    # Parent  742cad9442f7057d12ff5e92e7e821cc3de45051
    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/en/reference/groups.rst

    diff --git a/doc/en/reference/groups.rst b/doc/en/reference/groups.rst
    a b  
    99   sage/groups/group
    1010   sage/groups/generic
    1111   sage/groups/abelian_gps/abelian_group
     12   sage/groups/abelian_gps/values
     13   sage/groups/abelian_gps/dual_abelian_group
     14   sage/groups/abelian_gps/element_base
    1215   sage/groups/abelian_gps/abelian_group_element
     16   sage/groups/abelian_gps/dual_abelian_group_element
    1317   sage/groups/abelian_gps/abelian_group_morphism
    14    sage/groups/abelian_gps/dual_abelian_group
    1518   sage/groups/additive_abelian/additive_abelian_group
    1619   sage/groups/additive_abelian/additive_abelian_wrapper
    1720   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/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/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()
  • module_list.py

    diff --git a/module_list.py b/module_list.py
    a b  
    467467    Extension('sage.groups.group',
    468468              sources = ['sage/groups/group.pyx']),
    469469
     470    Extension('sage.groups.old',
     471              sources = ['sage/groups/old.pyx']),
     472
    470473    Extension('sage.groups.perm_gps.permgroup_element',
    471474              sources = ['sage/groups/perm_gps/permgroup_element.pyx']),
    472475
  • 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/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
     
    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
     
    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
     
    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    if gens_orders is None:
     335        if isinstance(n, (list, tuple)):
     336            gens_orders = n
     337            n = len(n)
     338        else:
     339            gens_orders = []
     340    if len(gens_orders) < n:
     341        gens_orders = [0] * (n - len(gens_orders)) + gens_orders
     342    elif len(gens_orders) > n:
     343        raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')')
     344    gens_orders = tuple(gens_orders)
     345    if isinstance(names, list):
     346        names = tuple(names)
     347    return (gens_orders, names)
     348
     349def AbelianGroup(n, gens_orders=None, names="f"):
    283350    r"""
    284351    Create the multiplicative abelian group in `n` generators
    285     with given invariants (which need not be prime powers).
     352    with given orders of generators (which need not be prime powers).
    286353   
    287354    INPUT:
    288355   
     356    - ``n`` -- integer (optional). If not specified, will be derived
     357       from ``gens_orders``.
    289358   
    290     -  ``n`` - integer
     359    - ``gens_orders`` -- a list of non-negative integers in the form
     360       `[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing
     361       order. This list is padded with zeros if it has length less
     362       than n. The orders of the commuting generators, with `0`
     363       denoting an infinite cyclic factor.
    291364   
    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.
     365    -  ``names`` -- (optional) names of generators
    296366   
    297     -  ``names`` - (optional) names of generators
     367    Alternatively, you can also give input in the form
     368    ``AbelianGroup(gens_orders, names="f")``, where the names keyword
     369    argument must be explicitly named.
    298370   
    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.
     371    OUTPUT:
     372
     373    Abelian group with generators and invariant type. The default name
     374    for generator ``A.i`` is ``fi``, as in GAP.
    308375   
    309376    EXAMPLES::
    310377   
     
    325392        sage: AbelianGroup(5).order()
    326393        +Infinity
    327394   
    328     Notice how `0`'s are padded on.
     395    Notice that `0`'s are prepended if necessary::
    329396   
    330     ::
    331    
    332         sage: AbelianGroup(5, [2,3,4])
     397        sage: G = AbelianGroup(5, [2,3,4]);  G
    333398        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     ::
     399        sage: G.gens_orders()
     400        (0, 0, 2, 3, 4)
     401
     402    The invariant list must not be longer than the number of generators::
    338403   
    339404        sage: AbelianGroup(2, [2,3,4])
    340405        Traceback (most recent call last):
    341406        ...
    342         ValueError: invfac (=[2, 3, 4]) must have length n (=2)
     407        ValueError: gens_orders (=[2, 3, 4]) must have length n (=2)
    343408    """
    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)
     409    gens_orders, names = _normalize(n, gens_orders, names)
     410    M = AbelianGroup_class(gens_orders, names)
    355411    return M
    356412
    357413def is_AbelianGroup(x):
    358414    """
    359     Return True if `x` is an abelian group.
     415    Return True if ``x`` is an Abelian group.
    360416   
    361417    EXAMPLES::
    362418   
     
    371427    return isinstance(x, AbelianGroup_class)
    372428
    373429
    374 class AbelianGroup_class(group.AbelianGroup):
     430class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase):
    375431    """
    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).
     432    The parent for Abelian groups with chosen generator orders.
     433
     434    INPUT:
     435
     436    - ``generator_orders`` -- list of integers. The orders of the
     437      (commuting) generators. Zero denotes an infinite cyclic
     438      generator.
     439
     440    - ``names`` -- names of the group generators (optional).
    379441   
    380442    EXAMPLES::
    381443   
     444        sage: Z2xZ3 = AbelianGroup([2,3])
     445        sage: Z6 = AbelianGroup([6])
     446        sage: Z2xZ3 is Z2xZ3, Z6 is Z6
     447        (True, True)
     448        sage: Z2xZ3 is Z6
     449        False
     450        sage: Z2xZ3 == Z6
     451        True
     452
    382453        sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")); F
    383454        Multiplicative Abelian Group isomorphic to C5 x C5 x C7 x C8 x C9
    384455        sage: F = AbelianGroup(5,[2, 4, 12, 24, 120],names = list("abcde")); F
    385456        Multiplicative Abelian Group isomorphic to C2 x C4 x C12 x C24 x C120
    386457        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]
     458        (2, 4, 12, 24, 120)
    410459
    411460        sage: F.category()
    412461        Category of groups
    413462
     463        sage: G = AbelianGroup([0,5,0,7],names = list("abcd")); G
     464        Multiplicative Abelian Group isomorphic to Z x C5 x Z x C7
     465        sage: TestSuite(G).run()
     466
     467    TESTS::
     468
     469        sage: AbelianGroup([]).gens_orders()
     470        ()
     471        sage: AbelianGroup([1]).gens_orders()
     472        (1,)
     473        sage: AbelianGroup([1,1]).gens_orders()
     474        (1, 1)
     475        sage: AbelianGroup(0).gens_orders()
     476        ()
    414477    """
    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
     478    Element = AbelianGroupElement
    428479
     480    def __init__(self, generator_orders, names):
     481        n = ZZ(len(generator_orders))
    429482        if n < 0:
    430483            raise ValueError, "n (=%s) must be nonnegative."%n
    431 
    432         self.__invariants = invfac
     484        self._gens_orders = tuple(ZZ(i) for i in generator_orders)
    433485
    434486        # *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()
     487        names = self.normalize_names(n, names)
     488        self._assign_names(names)
     489        AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()
    439490
    440     def __call__(self, x):
     491    def _an_element_(self):
    441492        """
    442         Create an element of this abelian group from `x`.
     493        Return a random element
     494
     495        EXAMPLES:
     496
     497            sage: G = AbelianGroup([2,3,4,5])
     498            sage: G.an_element()
     499            f0*f1*f2*f3
     500        """
     501        return prod(self.gens())
     502
     503    def is_isomorphic(left, right):
     504        """
     505        Check whether ``left`` and ``right`` are isomorphic
    443506       
     507        INPUT:
     508
     509        - ``right`` -- anything.
     510
     511        OUTPUT:
     512
     513        Boolean. Whether ``left`` and ``right`` are isomorphic as abelian groups.
     514
    444515        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
    467516
    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        
    477517            sage: G1 = AbelianGroup([2,3,4,5])
    478518            sage: G2 = AbelianGroup([2,3,4,5,1])
    479             sage: G1 < G2
    480             False
    481             sage: G1 > G2
    482             False
    483             sage: G1 == G2
     519            sage: G1.is_isomorphic(G2)
     520            True
     521            sage: G1 == G2    # syntactic sugar
    484522            True
    485523        """
    486524        if not is_AbelianGroup(right):
    487525            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]:
     526        return left.elementary_divisors() == right.elementary_divisors()
     527
     528    __eq__ = is_isomorphic
     529
     530    def __ne__(left, right):
     531        return not left.is_isomorphic(right)
     532
     533    def is_subgroup(left, right):
     534        """
     535        Test whether ``left`` is a subgroup of ``right``.
     536
     537        EXAMPLES::
     538
     539            sage: G = AbelianGroup([2,3,4,5])
     540            sage: G.is_subgroup(G)
     541            True
     542
     543            sage: H = G.subgroup([G.1])
     544            sage: H.is_subgroup(G)
     545            True
     546
     547            sage: G.<a, b> = AbelianGroup(2)
     548            sage: H.<c> = AbelianGroup(1)
     549            sage: H < G
     550            False
     551       """
     552        for l in left.gens():
     553            if l not in right:
    496554                return False
    497555        return True
     556
     557    __le__ = is_subgroup
     558
     559    def __ge__(left, right):
     560        return right.__le__(left)
    498561   
    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):
     562    def __lt__(left, right):
    509563        """
     564        Test whether ``left`` is a strict subgroup of ``right``
     565
    510566        EXAMPLE::
    511567       
    512568            sage: G.<a, b> = AbelianGroup(2)
     
    514570            sage: H < G
    515571            False
    516572        """
    517         return self <= right and self != right
     573        return left <= right and left != right
    518574   
    519     def __gt__(self, right):
    520         return self >= right and self != right
     575    def __gt__(left, right):
     576        return left >= right and left != right
    521577   
    522     def __le__(self, right):
    523         for a in self.gens():
    524             if a not in right:
    525                 return False
    526         return True
     578    def is_trivial(self):
     579        """
     580        Return whether the group is trivial
     581
     582        A group is trivial if it has precisely one element.
     583
     584        EXAMPLES::
     585
     586            sage: AbelianGroup([2, 3]).is_trivial()
     587            False
     588            sage: AbelianGroup([1, 1]).is_trivial()
     589            True
     590        """
     591        return self.elementary_divisors() == ()
    527592
    528593    def __nonzero__(self):
    529594        """
     
    536601            True
    537602            sage: bool(AbelianGroup([]))
    538603            False
     604            sage: bool(AbelianGroup([1,1,1]))
     605            False
    539606        """
    540         return len(self.invariants()) != 0
     607        return not self.is_trivial()
    541608
    542     def dual_group(self):
     609    @cached_method
     610    def dual_group(self, names="X", base_ring=None):
    543611        """
    544612        Returns the dual group.
     613
     614        INPUT:
     615
     616        - ``names`` -- string or list of strings. The generator names
     617          for the dual group.
     618
     619        - ``base_ring`` -- the base ring. If ``None`` (default), then
     620          a suitable cyclotomic field is picked automatically.
    545621       
    546         EXAMPLES:
     622        OUTPUT:
     623
     624        The
     625        :class:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class
     626        <dual abelian group>`
     627
     628        EXAMPLES::
     629
     630            sage: G = AbelianGroup([2])
     631            sage: G.dual_group()
     632            Dual of Abelian Group isomorphic to Z/2Z over Cyclotomic Field of order 2 and degree 1
     633            sage: G.dual_group().gens()
     634            (X,)
     635            sage: G.dual_group(names='Z').gens()
     636            (Z,)
     637
     638            sage: G.dual_group(base_ring=QQ)
     639            Dual of Abelian Group isomorphic to Z/2Z over Rational Field
     640
     641
     642        TESTS::
     643
     644            sage: H = AbelianGroup(1)
     645            sage: H.dual_group()
     646            Traceback (most recent call last):
     647            ...
     648            ValueError: the group must be finite
    547649        """
    548         from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup
    549         return DualAbelianGroup(self)
     650        from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup_class
     651        if not self.is_finite():
     652            raise ValueError('the group must be finite')
     653        if base_ring is None:
     654            from sage.rings.number_field.number_field import CyclotomicField
     655            from sage.rings.arith import LCM
     656            base_ring = CyclotomicField(LCM(self.gens_orders()))
     657        return DualAbelianGroup_class(self, names=names, base_ring=base_ring)
    550658                 
     659    @cached_method
    551660    def elementary_divisors(self):
    552661        r"""
    553662        This returns the elementary divisors of the group, using Pari.
     
    566675            on these ""smaller invariants"" to compute `d_{i-1}`, and so on.
    567676            (Thanks to Robert Miller for communicating this algorithm.)
    568677
     678        OUTPUT:
     679
     680        A tuple of integers.
     681
    569682        EXAMPLES::
    570683       
    571684            sage: G = AbelianGroup(2,[2,3])
    572685            sage: G.elementary_divisors()
    573             [6]
     686            (6,)
    574687            sage: G = AbelianGroup(1, [6])
    575688            sage: G.elementary_divisors()
    576             [6]
     689            (6,)
    577690            sage: G = AbelianGroup(2,[2,6])
    578691            sage: G
    579692            Multiplicative Abelian Group isomorphic to C2 x C6
    580             sage: G.invariants()
    581             [2, 6]
     693            sage: G.gens_orders()
     694            (2, 6)
    582695            sage: G.elementary_divisors()
    583             [2, 6]
     696            (2, 6)
    584697            sage: J = AbelianGroup([1,3,5,12])
    585698            sage: J.elementary_divisors()
    586             [3, 60]
     699            (3, 60)
    587700            sage: G = AbelianGroup(2,[0,6])
    588701            sage: G.elementary_divisors()
    589             [6, 0]
     702            (6, 0)
    590703            sage: AbelianGroup([3,4,5]).elementary_divisors()
    591             [60]
     704            (60,)
    592705        """
    593706        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]
     707        ed = diagonal_matrix(ZZ, self.gens_orders()).elementary_divisors()
     708        return tuple(d for d in ed if d!=1)
    596709
     710    @cached_method
    597711    def exponent(self):
    598712        """
    599713        Return the exponent of this abelian group.
     
    609723            sage: G.exponent()
    610724            12
    611725        """
    612         try:
    613             return self.__exponent
    614         except AttributeError:
    615             self.__exponent = e = lcm(self.invariants())
    616             return e
    617            
     726        return lcm(self.gens_orders())
    618727   
    619728    def identity(self):
    620729        r"""
     
    633742            f0
    634743        """
    635744        return self(1)
    636 
    637745   
    638746    def _group_notation(self, eldv):
    639747        v = []
     
    652760       
    653761            sage: F = AbelianGroup(10, [2]*10)
    654762            sage: F._latex_()
    655             '$\\mathrm{AbelianGroup}( 10, [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] )$'
     763            '$\\mathrm{AbelianGroup}( 10, (2, 2, 2, 2, 2, 2, 2, 2, 2, 2) )$'
    656764        """
    657         s = "$\mathrm{AbelianGroup}( %s, %s )$"%(len(self.invariants()), self.invariants())
     765        s = "$\mathrm{AbelianGroup}( %s, %s )$"%(self.ngens(), self.gens_orders())
    658766        return s
    659767
    660768    def _gap_init_(self):
     
    669777            sage: gap(G)
    670778            Group( [ f1, f2, f3 ] )
    671779       
    672         Only works for finite groups.
    673        
    674         ::
     780        Only works for finite groups::
    675781       
    676782            sage: G = AbelianGroup(3,[0,3,4],names="abc"); G
    677783            Multiplicative Abelian Group isomorphic to Z x C3 x C4
     
    683789        # TODO: Use the package polycyclic has AbelianPcpGroup, which can handle
    684790        # the infinite case but it is a GAP package not GPL'd.
    685791        # 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()
     792        # return 'AbelianPcpGroup(%s)'%list(self.invariants())
    688793        if not self.is_finite():
    689             raise TypeError, "abelian groups in GAP are finite, but self is infinite"
    690         return 'AbelianGroup(%s)'%self.invariants()
     794            raise TypeError('abelian groups in GAP are finite, but self is infinite')
     795        return 'AbelianGroup(%s)'%list(self.gens_orders())
    691796
    692797    def gen(self, i=0):
    693798        """
     
    700805            a0
    701806            sage: F.2
    702807            a2
    703             sage: F.invariants()
    704             [0, 0, 0, 0, 0]
     808            sage: F.gens_orders()
     809            (0, 0, 0, 0, 0)
     810
     811            sage: G = AbelianGroup([2,1,3])
     812            sage: G.gens()
     813            (f0, 1, f2)
    705814        """
    706         n = self.__ngens
     815        n = self.ngens()
    707816        if i < 0 or i >= n:
    708817            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)
     818        x = [0]*n
     819        if self._gens_orders[i] != 1:
     820            x[i] = 1
     821        return self.element_class(x, self)
     822
     823    def gens(self):
     824        """
     825        Return the generators of the group.
     826
     827        OUTPUT:
     828
     829        A tuple of group elements. The generators according to the
     830        chosen :meth:`gens_orders`.
     831
     832        EXAMPLES::
     833
     834            sage: F = AbelianGroup(5,[3,2],names='abcde')
     835            sage: F.gens()
     836            (a, b, c, d, e)
     837            sage: [ g.order() for g in F.gens() ]
     838            [+Infinity, +Infinity, +Infinity, 3, 2]
     839        """
     840        return tuple( self.gen(i) for i in range(self.ngens()) )
     841
     842    def gens_orders(self):
     843        """
     844        Return the orders of the cyclic factors that this group has
     845        been defined with.
     846
     847        Use :meth:`elementary_divisors` if you are looking for an
     848        invariant of the group.
     849
     850        OUTPUT:
     851
     852        A tuple of integers.
     853
     854        EXAMPLES::
     855
     856            sage: Z2xZ3 = AbelianGroup([2,3])
     857            sage: Z2xZ3.gens_orders()
     858            (2, 3)
     859            sage: Z2xZ3.elementary_divisors()
     860            (6,)
     861
     862            sage: Z6 = AbelianGroup([6])
     863            sage: Z6.gens_orders()
     864            (6,)
     865            sage: Z6.elementary_divisors()
     866            (6,)
     867
     868            sage: Z2xZ3.is_isomorphic(Z6)
     869            True
     870            sage: Z2xZ3 is Z6
     871            False
     872
     873        TESTS::
     874
     875            sage: F = AbelianGroup(3, [2], names='abc')
     876            sage: map(type, F.gens_orders())
     877            [<type 'sage.rings.integer.Integer'>,
     878             <type 'sage.rings.integer.Integer'>,
     879             <type 'sage.rings.integer.Integer'>]
     880        """
     881        return self._gens_orders
    712882
    713883    def invariants(self):
    714884        """
    715         Return a copy of the list of invariants of this group.
    716        
    717         It is safe to modify the returned list.
     885        Return the orders of the cyclic factors that this group has
     886        been defined with.
     887
     888        For historical reasons this has been called invariants in
     889        Sage, even though they are not necessarily the invariant
     890        factors of the group. Use :meth:`gens_orders` instead::
     891
     892            sage: J = AbelianGroup([2,0,3,2,4]);  J
     893            Multiplicative Abelian Group isomorphic to C2 x Z x C3 x C2 x C4
     894            sage: J.invariants()    # deprecated
     895            (2, 0, 3, 2, 4)
     896            sage: J.gens_orders()   # use this instead
     897            (2, 0, 3, 2, 4)
     898            sage: for i in range(J.ngens()):
     899            ...       print i, J.gen(i), J.gen(i).order()     # or use this
     900            0 f0 2
     901            1 f1 +Infinity
     902            2 f2 3
     903            3 f3 2
     904            4 f4 4
     905
     906        Use :meth:`elementary_divisors` if you are looking for an
     907        invariant of the group.
     908
     909        OUTPUT:
     910
     911        A tuple of integers. Zero means infinite cyclic factor.
    718912       
    719913        EXAMPLES::
    720914       
    721915            sage: J = AbelianGroup([2,3])
    722916            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
     917            (2, 3)
     918            sage: J.elementary_divisors()
     919            (6,)
     920
     921        TESTS::
     922
     923            sage: F = AbelianGroup(3, [2], names='abc')
     924            sage: map(type, F.gens_orders())
     925            [<type 'sage.rings.integer.Integer'>,
     926             <type 'sage.rings.integer.Integer'>,
     927             <type 'sage.rings.integer.Integer'>]
    731928        """
    732         return list(self.__invariants)
     929        # TODO: deprecate
     930        return self.gens_orders()
    733931
    734932    def is_cyclic(self):
    735933        """
     
    738936        EXAMPLES::
    739937       
    740938            sage: J = AbelianGroup([2,3])
    741             sage: J.invariants()
    742             [2, 3]
     939            sage: J.gens_orders()
     940            (2, 3)
    743941            sage: J.elementary_divisors()
    744             [6]
     942            (6,)
    745943            sage: J.is_cyclic()
    746944            True
    747945            sage: G = AbelianGroup([6])
    748             sage: G.invariants()
    749             [6]
     946            sage: G.gens_orders()
     947            (6,)
    750948            sage: G.is_cyclic()
    751949            True
    752950            sage: H = AbelianGroup([2,2])
    753             sage: H.invariants()
    754             [2, 2]
     951            sage: H.gens_orders()
     952            (2, 2)
    755953            sage: H.is_cyclic()
    756954            False
    757955            sage: H = AbelianGroup([2,4])
    758956            sage: H.elementary_divisors()
    759             [2, 4]
     957            (2, 4)
    760958            sage: H.is_cyclic()
    761959            False
    762960            sage: H.permutation_group().is_cyclic()
     
    774972        """
    775973        return len(self.elementary_divisors()) <= 1
    776974
     975    @cached_method
    777976    def ngens(self):
    778977        """
    779978        The number of free generators of the abelian group.
     
    784983            sage: F.ngens()
    785984            10000
    786985        """
    787         return self.__ngens
     986        return len(self.gens_orders())
    788987
     988    @cached_method
    789989    def order(self):
    790990        """
    791991        Return the order of this group.
     
    799999            sage: G.order()
    8001000            +Infinity
    8011001        """
    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    
     1002        from sage.rings.all import infinity
     1003        length = prod(self.gens_orders())
     1004        if length == 0:
     1005            return infinity
     1006        return length
     1007
    8141008    def permutation_group(self):
    8151009        r"""
    8161010        Return the permutation group isomorphic to this abelian group.
     
    8301024        s = 'Image(IsomorphismPermGroup(%s))'%self._gap_init_()
    8311025        return PermutationGroup(gap_group=s)
    8321026
    833 
    8341027    def is_commutative(self):
    8351028        """
    8361029        Return True since this group is commutative.
     
    8471040
    8481041    def random_element(self):
    8491042        """
    850         Return a random element of this group. (Renamed random to
    851         random_element.)
     1043        Return a random element of this group.
    8521044       
    8531045        EXAMPLES::
    8541046       
    8551047            sage: G = AbelianGroup([2,3,9])
    856             sage: G.random_element()
     1048            sage: G.random_element()   # random output
    8571049            f0*f1^2*f2
    8581050        """
    8591051        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 
     1052        result = self.one()
     1053        for g in self.gens():
     1054            order = g.order()
     1055            if order not in ZZ:
     1056                order = 42  # infinite order; randomly chosen maximum
     1057            result *= g**(randint(0,order))
     1058        return result
    8681059
    8691060    def _repr_(self):
    870         eldv = self.invariants()
     1061        """
     1062        Return a string representation of ``self``.
     1063        """
     1064        eldv = self.gens_orders()
    8711065        if len(eldv) == 0:
    8721066            return "Trivial Abelian Group"
    8731067        g = self._group_notation(eldv)
    8741068        return "Multiplicative Abelian Group isomorphic to " + g
    8751069
    876 
    8771070    def subgroup(self, gensH, names="f"):
    8781071        """
    8791072         Create a subgroup of this group. The "big" group must be defined
     
    8811074         
    8821075         INPUT:
    8831076         
    884          
    885          -  ``gensH`` - list of elements which are products of
    886             the generators of the ambient abelian group G = self
    887          
     1077         - ``gensH`` -- list of elements which are products of the
     1078            generators of the ambient abelian group G = self
    8881079         
    8891080         EXAMPLES::
    8901081         
     
    8931084             sage: H = G.subgroup([a*b,a]); H
    8941085             Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    8951086             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
    896              generated by [a*b, a]
     1087             generated by a*b, a
    8971088             sage: H < G
    8981089             True
    8991090             sage: F = G.subgroup([a,b^2])
    9001091             sage: F
    9011092             Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    9021093             Multiplicative Abelian Group isomorphic to C2 x C3 x C4
    903              generated by [a, b^2]
     1094             generated by a, b^2
    9041095             sage: F.gens()
    905              [a, b^2]
     1096             (a, b^2)
    9061097             sage: F = AbelianGroup(5,[30,64,729],names = list("abcde"))
    9071098             sage: a,b,c,d,e = F.gens()
    9081099             sage: F.subgroup([a,b])
    9091100             Multiplicative Abelian Group isomorphic to Z x Z, which is
    9101101             the subgroup of Multiplicative Abelian Group isomorphic to
    911              Z x Z x C30 x C64 x C729 generated by [a, b]
     1102             Z x Z x C30 x C64 x C729 generated by a, b
    9121103             sage: F.subgroup([c,e])
    9131104             Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
    9141105             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]
     1106             Group isomorphic to Z x Z x C30 x C64 x C729 generated by c, e
    9171107         """
    918         if not isinstance(gensH, (list, tuple)):
    919             raise TypeError, "gensH = (%s) must be a list or tuple"%(gensH)
    920          
    9211108        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."
     1109        gensH = tuple(gensH)
     1110        if isinstance(names, list):
     1111            names = tuple(names)
     1112        for h in gensH:
     1113            if h not in G:
     1114                raise TypeError('Subgroup generators must belong to the given group.')
    9251115        return AbelianGroup_subgroup(self, gensH, names)
    9261116
    9271117    def list(self):
     
    9421132            [1]
    9431133        """
    9441134        try:
    945             return list(self.__list)
     1135            return list(self._list)
    9461136        except AttributeError:
    9471137            pass
    9481138        if not(self.is_finite()):
    9491139           raise NotImplementedError, "Group must be finite"
    950         self.__list = list(self.__iter__())
    951         return list(self.__list)
     1140        self._list = list(self.__iter__())
     1141        return list(self._list)
    9521142     
    9531143    def __iter__(self):
    9541144        """
     
    9771167            sage: list(G)
    9781168            [1]
    9791169        """
    980         invs = self.invariants()
     1170        invs = self.gens_orders()
    9811171        for t in mrange(invs):
    982             yield AbelianGroupElement(self, t)
    983 
     1172            yield self(t)
    9841173
    9851174    def subgroups(self, check=False):
    9861175        r"""
     
    10111200
    10121201            sage: AbelianGroup([2,3]).subgroups()
    10131202            [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],
     1203             Multiplicative Abelian Group isomorphic to C2 x C3
     1204             generated by f0*f1^2,
    10161205             Multiplicative Abelian Group isomorphic to C2, which is the subgroup of
    1017             Multiplicative Abelian Group isomorphic to C2 x C3
    1018             generated by [f0],
     1206             Multiplicative Abelian Group isomorphic to C2 x C3
     1207             generated by f0,
    10191208             Multiplicative Abelian Group isomorphic to C3, which is the subgroup of
    1020             Multiplicative Abelian Group isomorphic to C2 x C3
    1021             generated by [f1],
     1209             Multiplicative Abelian Group isomorphic to C2 x C3
     1210             generated by f1,
    10221211             Trivial Abelian Group, which is the subgroup of
    1023             Multiplicative Abelian Group isomorphic to C2 x C3
    1024             generated by []]
     1212             Multiplicative Abelian Group isomorphic to C2 x C3
     1213             generated by 1]
    10251214
    10261215            sage: len(AbelianGroup([2,4,8]).subgroups())
    10271216            81
    10281217
     1218        TESTS::
     1219
     1220            sage: AbelianGroup([]).subgroups()
     1221            [Trivial Abelian Group]
    10291222        """
    10301223        if not self.is_finite(): raise ValueError, "Group must be finite"
    10311224        from sage.misc.misc import verbose
    10321225
    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([])]
     1226        if self.is_trivial():
     1227            return [self]
     1228        if self.ngens() == 1:
     1229            n = self.gen(0).order()
     1230            return [ self.subgroup([self.gen(0)**i]) for i in divisors(n) ]
    10411231
     1232        v = self.gens_orders()
    10421233        A = AbelianGroup(v[:-1])
    10431234        x = v[-1]
    10441235
     
    10461237
    10471238        subgps = []
    10481239        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
     1240            verbose("G = subgp generated by %s" % list(G.gens()))
     1241            verbose("invariants are:", [t.order() for t in G.gens()])
    10511242            for H in divisors(x):
    10521243                # H = the subgroup of *index* H.
    10531244                its = [xrange(0, H, H/gcd(H, G.gen(i).order())) for i in xrange(len(G.gens()))]
     
    10871278            sage: G.subgroup( [ G([1,0]), G([1,2]) ])
    10881279            Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
    10891280            Multiplicative Abelian Group isomorphic to C4 x C4
    1090             generated by [f0, f0*f1^2]
     1281            generated by f0, f0*f1^2
    10911282            sage: AbelianGroup([4,4]).subgroup_reduced( [ [1,0], [1,2] ])
    10921283            Multiplicative Abelian Group isomorphic to C2 x C4, which is the subgroup of
    10931284            Multiplicative Abelian Group isomorphic to C4 x C4
    1094             generated by [f1^2, f0]
     1285            generated by f1^2, f0
    10951286        """
    10961287        from sage.matrix.constructor import matrix
    10971288        d = self.ngens()
     
    11021293            # can't happen?
    11031294            print "Vectors not LI: ", elts
    11041295            raise e
    1105         rel_lattice = X.span([X.gen(i) * self.invariants()[i] for i in xrange(d)])
     1296        rel_lattice = X.span([X.gen(i) * self.gens_orders()[i] for i in xrange(d)])
    11061297        isect = elt_lattice.intersection(rel_lattice)
    11071298        mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ)
    11081299        D,U,V = mat.smith_form()
    11091300        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])
     1301        return self.subgroup([self([x[0][i] % self.gens_orders()[i]
     1302                                    for i in xrange(d)]) for x in new_basis if x[1] != 1])
    11111303
    11121304class AbelianGroup_subgroup(AbelianGroup_class):
    11131305    """
     
    11281320            sage: F.subgroup([a^3,b])
    11291321            Multiplicative Abelian Group isomorphic to Z x Z, which is the subgroup of
    11301322            Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
    1131             generated by [a^3, b]           
    1132        
    1133         ::
     1323            generated by a^3, b
    11341324       
    11351325            sage: F.subgroup([c])
    11361326            Multiplicative Abelian Group isomorphic to C2 x C3 x C5, which is the subgroup of
    11371327            Multiplicative Abelian Group isomorphic to Z x Z x C30 x C64 x C729
    1138             generated by [c]
    1139        
    1140         ::
     1328            generated by c
    11411329       
    11421330            sage: F.subgroup([a,c])
    11431331            Multiplicative Abelian Group isomorphic to C2 x C3 x C5 x
    11441332            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         ::
     1333            isomorphic to Z x Z x C30 x C64 x C729 generated by a, c
    11481334       
    11491335            sage: F.subgroup([a,b*c])
    11501336            Multiplicative Abelian Group isomorphic to Z x Z, which is
    11511337            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         ::
     1338            Z x Z x C30 x C64 x C729 generated by a, b*c
    11551339       
    11561340            sage: F.subgroup([b*c,d])
    11571341            Multiplicative Abelian Group isomorphic to C64 x Z, which
    11581342            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         ::
     1343            to Z x Z x C30 x C64 x C729 generated by b*c, d
    11621344       
    11631345            sage: F.subgroup([a*b,c^6,d],names = list("xyz"))
    11641346            Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
    11651347            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         ::
     1348            isomorphic to Z x Z x C30 x C64 x C729 generated by a*b,
     1349            c^6, d
    11701350       
    11711351            sage: H.<x,y,z> = F.subgroup([a*b, c^6, d]); H
    11721352            Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
    11731353            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         ::
     1354            isomorphic to Z x Z x C30 x C64 x C729 generated by a*b,
     1355            c^6, d
    11781356       
    11791357            sage: G = F.subgroup([a*b,c^6,d],names = list("xyz")); G
    11801358            Multiplicative Abelian Group isomorphic to C5 x C64 x Z,
    11811359            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]
     1360            isomorphic to Z x Z x C30 x C64 x C729 generated by a*b,
     1361            c^6, d
    11841362            sage: x,y,z = G.gens()
    11851363            sage: x.order()
    11861364            +Infinity
     
    11931371            sage: A.subgroup([a,b])
    11941372            Multiplicative Abelian Group isomorphic to C3 x C5, which is the subgroup of
    11951373            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1196             generated by [a, b]
     1374            generated by a, b
    11971375            sage: A.subgroup([a,b,c,d^2,e])
    11981376            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8, which is the subgroup of
    11991377            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1200             generated by [a, b, c, d^2, e]
     1378            generated by a, b, c, d^2, e
    12011379            sage: A.subgroup([a,b,c,d^2,e^2])
    12021380            Multiplicative Abelian Group isomorphic to C3 x C4 x C5 x C5 x C7, which is the subgroup of
    12031381            Multiplicative Abelian Group isomorphic to C3 x C5 x C5 x C7 x C8
    1204             generated by [a, b, c, d^2, e^2]
     1382            generated by a, b, c, d^2, e^2
    12051383            sage: B = A.subgroup([a^3,b,c,d,e^2]); B
    12061384            Multiplicative Abelian Group isomorphic to C4 x C5 x C5 x C7, which is the subgroup of
    12071385            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]
     1386            generated by b, c, d, e^2
     1387            sage: B.gens_orders()
     1388            (4, 5, 5, 7)
    12111389            sage: A = AbelianGroup(4,[1009, 2003, 3001, 4001], names = "abcd")
    12121390            sage: a,b,c,d = A.gens()
    12131391            sage: B = A.subgroup([a^3,b,c,d])
    1214             sage: B.invariants()
    1215             [1009, 2003, 3001, 4001]
     1392            sage: B.gens_orders()
     1393            (1009, 2003, 3001, 4001)
    12161394            sage: A.order()
    12171395            24266473210027
    12181396            sage: B.order()
     
    12231401            Multiplicative Abelian Group isomorphic to C3 x C7 x C16 x
    12241402            C2003 x C3001 x C4001, which is the subgroup of
    12251403            Multiplicative Abelian Group isomorphic to C1008 x C2003 x
    1226             C3001 x C4001 generated by [a^3, b, c, d]
     1404            C3001 x C4001 generated by a^3, b, c, d
    12271405       
    12281406        Infinite groups can also be handled::
    12291407       
     
    12321410            sage: F = G.subgroup([a,b^2,c]); F
    12331411            Multiplicative Abelian Group isomorphic to C2 x C3 x Z,
    12341412            which is the subgroup of Multiplicative Abelian Group
    1235             isomorphic to C3 x C4 x Z generated by [a, b^2, c]
     1413            isomorphic to C3 x C4 x Z generated by a, b^2, c
    12361414       
    1237         ::
    1238        
    1239             sage: F.invariants()
    1240             [2, 3, 0]
     1415            sage: F.gens_orders()
     1416            (2, 3, 0)
    12411417            sage: F.gens()
    1242             [a, b^2, c]
     1418            (a, b^2, c)
    12431419            sage: F.order()
    12441420            +Infinity
    12451421        """
    12461422        from sage.interfaces.all import gap
    12471423        if not isinstance(ambient, AbelianGroup_class):
    12481424            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
     1425        if not isinstance(gens, tuple):
     1426            raise TypeError, "gens (=%s) must be a tuple"%gens
    12511427           
    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
     1428        self._ambient_group = ambient
     1429        Hgens = tuple(x for x in gens if x != ambient.one())  ## in case someone puts 1 in the list of generators
     1430        self._gens = Hgens
    12551431        m = len(gens)
    12561432        ell = len(ambient.gens())
    1257         ambient_invs = ambient.invariants()
     1433        ambient_invs = ambient.gens_orders()
    12581434        invsf = [x for x in ambient_invs if x > 0]    ## fixes the problem with
    12591435        invs0 = [x for x in ambient_invs if x == 0]   ## the infinite parts
    12601436        Ggens = list(ambient.variable_names())
     
    12641440            Ggens0 = [x for x in ambient.variable_names() if
    12651441                        ambient_invs[Ggens.index(x)] == 0]
    12661442            ##     ^^ only look at "finite" names
    1267             Gf = AbelianGroup_class(len(invsf), invsf, names = Gfgens)
     1443            Gf = AbelianGroup(invsf, names=Gfgens)
    12681444            s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_()
    12691445            gap.eval(s1)
    12701446            Hgensf = [x for x in Hgens if len(set(Ggens0).intersection(set(list(str(x)))))==0]
     
    12741450            for i in range(len(Gfgens)):
    12751451               cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i]
    12761452               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
     1453        else:  # invs0==[]:
     1454            Hgensf = Hgens
     1455            Hgens0 = []  # added for consistency
     1456            G = ambient
     1457            s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_()
     1458            gap.eval(s1)
     1459            for i in range(len(Ggens)):
     1460                cmd = '%s := gens[%s]'%(Ggens[i], i+1)
     1461                #print i,"  \n",cmd
     1462                gap.eval(cmd)
     1463        s2 = "gensH:=%s"%list(Hgensf) #### remove from this the ones <--> 0 invar
    12881464        gap.eval(s2)
    12891465        s3 = 'H:=Subgroup(G,gensH)'
    12901466        gap.eval(s3)
    12911467        # a GAP command which returns the "invariants" of the
    12921468        # subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)),
    12931469        # works if G is the subgroup declared as a AbelianPcpGroup
    1294         self.__abinvs = eval(gap.eval("AbelianInvariants(H)"))
    1295         invs = self.__abinvs
     1470        self._abinvs = eval(gap.eval("AbelianInvariants(H)"))
     1471        invs = self._abinvs
    12961472        #print s3, invs
    12971473        if Hgens0 != []:
    12981474            for x in Hgens0:
    12991475               invs.append(0)
    13001476        #print Hgensf, invs, invs0
    1301         AbelianGroup_class.__init__(self, len(invs), invs, names)
     1477        AbelianGroup_class.__init__(self, invs, names)
    13021478
    13031479    def __contains__(self, x):
    13041480        """
    1305         Return True if `x` is an element of this subgroup.
     1481        Test whether ``x`` is an element of this subgroup.
    13061482       
    13071483        EXAMPLES::
    13081484       
     
    13181494        if x.parent() is self:
    13191495            return True
    13201496        elif x in self.ambient_group():
    1321             amb_inv = self.ambient_group().invariants()
     1497            amb_inv = self.ambient_group().gens_orders()
    13221498            for a in xrange(len(amb_inv)):
    13231499                if amb_inv[a] == 0 and x.list()[a] != 0:
    1324                     for g in self.__gens:
     1500                    for g in self._gens:
    13251501                        if g.list()[a] == 0:
    13261502                            continue
    13271503                        if abs(x.list()[a]%g.list()[a]) < abs(x.list()[a]):
     
    13321508                        if x.list()[a] == 0:
    13331509                            break
    13341510                elif x.list()[a] != 0:
    1335                     for g in self.__gens:
     1511                    for g in self._gens:
    13361512                        if g.list()[a] == 0:
    13371513                            continue
    13381514                        if abs(x.list()[a]%g.list()[a])%abs(amb_inv[a]) < x.list()[a]%abs(amb_inv[a]):
     
    13451521        """
    13461522        Return the ambient group related to self.
    13471523        """
    1348         return self.__ambient_group
     1524        return self._ambient_group
    13491525
    1350     def __eq__(self, right):
     1526    def equals(left, right):
    13511527        """
    1352         ::
     1528        Check whether ``left`` and ``right`` are the same subgroup.
     1529
     1530        INPUT:
     1531
     1532        - ``right`` -- anything.
     1533
     1534        OUTPUT:
     1535
     1536        Boolean. Whether ``left`` and ``right`` are isomorphic as abelian groups.
     1537
     1538        EXAMPLES::
    13531539       
    13541540            sage: G = AbelianGroup(3, [2,3,4], names="abc"); G
    13551541            Multiplicative Abelian Group isomorphic to C2 x C3 x C4
     
    13571543            sage: F=G.subgroup([a,b^2]); F
    13581544            Multiplicative Abelian Group isomorphic to C2 x C3, which is the subgroup of
    13591545            Multiplicative Abelian Group isomorphic to C2 x C3 x C4
    1360             generated by [a, b^2]
     1546            generated by a, b^2
    13611547            sage: F<G
    13621548            True
    13631549       
    1364         ::
    1365        
    13661550            sage: A = AbelianGroup(1, [6])
    13671551            sage: A.subgroup(list(A.gens())) == A
    13681552            True
    13691553       
    1370         ::
    1371        
    13721554            sage: G.<a,b> = AbelianGroup(2)
    13731555            sage: A = G.subgroup([a])
    13741556            sage: B = G.subgroup([b])
    1375             sage: A == B
     1557            sage: A.equals(B)
    13761558            False
     1559            sage: A == B        # sames as A.equals(B)
     1560            False
     1561            sage: A.is_isomorphic(B)
     1562            True
    13771563        """
    1378         if not is_AbelianGroup(right):
    1379             return -1
    1380         return self <= right and right <= self
    1381    
     1564        left_ambient = left.ambient_group()
     1565        try:
     1566            right_ambient = right.ambient_group()
     1567        except AttributeError:
     1568            try:
     1569                return right.__eq__(left)
     1570            except AttributeError:
     1571                return False
     1572        if left_ambient is not right_ambient:
     1573            return False
     1574        return left <= right and right <= left
     1575
     1576    __eq__ = equals
     1577
    13821578    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())
     1579        """
     1580        Return a string representation
     1581
     1582        EXAMPLES::
     1583
     1584            sage: G.<a,b> = AbelianGroup(2)
     1585            sage: A = G.subgroup([a])
     1586            sage: A._repr_()
     1587            'Multiplicative Abelian Group isomorphic to Z, which is the subgroup of\nMultiplicative Abelian Group isomorphic to Z x Z\ngenerated by a'
     1588       """
     1589        s = AbelianGroup_class._repr_(self)
     1590        s += ', which is the subgroup of\n'
     1591        s += self.ambient_group()._repr_()
     1592        s += '\ngenerated by '
     1593        if self.is_trivial():
     1594            s += '1'
     1595        else:
     1596            s += ', '.join(map(str, self.gens()))
     1597        return s
    13871598       
    13881599    def invs(self):
    13891600        """
     
    13921603        G = self.ambient_group()
    13931604        invsG = G.invariants()
    13941605        Hgap = self._gap_init_()
     1606        raise Exception # WTF?
    13951607       
    1396 
    13971608    def gens(self):
    13981609        """
    13991610        Return the generators for this subgroup.
    14001611        """
    1401         return self.__gens
     1612        return self._gens
    14021613
    14031614    def gen(self, n):
    14041615        """
     
    14111622            sage: A.gen(0)
    14121623            a
    14131624        """
    1414         return self.__gens[n]
     1625        return self._gens[n]
    14151626
  • 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"""
     
    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 
    310135    def random_element(self):
    311136        """
    312137        Return a random element of this dual group.
     
    318143        for i in range(len(gens)):
    319144            g = g*gens[i]**(random(gens[i].order()))
    320145        return g
    321    
    322 
    323146
    324147    def word_problem(self, words):
    325148        """
     
    351174            [[x, 1], [y, 1]]
    352175            sage: prod([x^i for x,i in v]) == y*x
    353176            True
    354 
    355177        """
    356178        from sage.groups.abelian_gps.abelian_group import AbelianGroup, word_problem
    357179        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  
    108108        G_domain = G.subgroup(genss)
    109109        if G_domain.order() != G.order():
    110110            raise TypeError, "Sorry, the list %s must generate G."%genss
    111         self.domain_invs = G.invariants()
    112         self.codomaininvs = H.invariants()
     111        # self.domain_invs = G.gens_orders()
     112        # self.codomaininvs = H.gens_orders()
    113113        self.domaingens = genss
    114114        self.codomaingens = imgss
    115115        #print genss, imgss
  • 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 *
    25 
    26 from abelian_group import AbelianGroup,is_AbelianGroup,AbelianGroup_class,AbelianGroup_subgroup, word_problem
    27 
    28 from abelian_group_element import AbelianGroupElement,is_AbelianGroupElement
     23#from dual_abelian_group import DualAbelianGroup
     24from abelian_group import AbelianGroup, is_AbelianGroup, word_problem
     25from values import AbelianGroupWithValues
    2926
    3027from abelian_group_morphism import is_AbelianGroupMorphism,AbelianGroupMap,AbelianGroupMorphism_id,AbelianGroupMorphism,AbelianGroupMorphism
    3128
  • 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)    ## random
     33    -1.0000000000000000 + 0.00000000000000013834419720915037*I
     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)    ## random
     40    -1.0000000000000000 + 0.00000000000000013834419720915037*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        return self._group
    142135   
    143136    def base_ring(self):
     137        """
     138        Return the scalars over which the group is dualized.
     139
     140            sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
     141            sage: Fd = F.dual_group(base_ring=CC)
     142            sage: Fd.base_ring()
     143            Complex Field with 53 bits of precision
     144        """
    144145        return self._base_ring
    145146   
    146147    def __str__(self):
     
    149150       
    150151        EXAMPLES::
    151152       
    152                    sage: F = AbelianGroup(3,[5,64,729],names = list("abc"))
    153                    sage: Fd = DualAbelianGroup(F)
     153            sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))
     154            sage: Fd = F.dual_group(base_ring=CC)
    154155            sage: print Fd
    155                    DualAbelianGroup( AbelianGroup ( 3, [5, 64, 729] ) )
     156            DualAbelianGroup( AbelianGroup ( 3, (5, 64, 729) ) )
    156157        """
    157         s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.invariants())
     158        s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.gens_orders())
    158159        return s
    159160
    160161    def _repr_(self):
     
    162163        EXAMPLES::
    163164       
    164165            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))
     166            sage: Fd = F.dual_group(names='ABCDE', base_ring=CyclotomicField(2*5*7*8*9))
    166167            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')
     168            Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
     169            over Cyclotomic Field of order 5040 and degree 1152
     170            sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)
    169171            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
     172            Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
     173            over Complex Field with 53 bits of precision
    171174        """
    172175        G = self.group()
    173         eldv = G.invariants()
     176        eldv = G.gens_orders()
    174177        gp = ""
    175178        for x in eldv:
    176179            if x!=0:
    177180                gp = gp + "Z/%sZ x "%x
    178181            if x==0:
    179182                gp = gp + "Z x "
    180         gp = gp[:-2]
    181         s = "Dual of Abelian Group isomorphic to "+gp+" over %s"%self.base_ring()
     183        gp = gp[:-2].strip()
     184        s = 'Dual of Abelian Group isomorphic to ' + gp + ' over ' + str(self.base_ring())
    182185        return s
    183186
    184187    def _latex_(self):
     
    188191        EXAMPLES::
    189192       
    190193            sage: F = AbelianGroup(3, [2]*3)
    191             sage: Fd = DualAbelianGroup(F)
     194            sage: Fd = F.dual_group()
    192195            sage: Fd._latex_() 
    193             '$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, [2, 2, 2] ) )$'
     196            '$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, (2, 2, 2) ) )$'
    194197        """
    195         s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.invariants())
     198        s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.gens_orders())
    196199        return s
    197200
    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                                
    215201    def random_element(self):
    216202        """
    217203        Return a random element of this dual group.
     
    219205        EXAMPLES::
    220206       
    221207            sage: G = AbelianGroup([2,3,9])
    222             sage: Gd = DualAbelianGroup(G)
     208            sage: Gd = G.dual_group(base_ring=CC)
    223209            sage: Gd.random_element()
    224210            X0*X1^2*X2
    225211            sage: N = 43^2-1
    226212            sage: G = AbelianGroup([N],names="a")
    227             sage: Gd = DualAbelianGroup(G,names="A")
     213            sage: Gd = G.dual_group(names="A", base_ring=CC)
    228214            sage: a, = G.gens()
    229215            sage: A, = Gd.gens()
    230216            sage: x = a^(N/4); y = a^(N/3); z = a^(N/14)
     
    240226            g = g*gens[i]**(randint(1,gens[i].order()))
    241227        return g
    242228
    243     def random(self):
    244         """
    245         Deprecated. Use self.random_element() instead.
    246         """
    247         raise NotImplementedError, "Deprecated: use random_element() instead"
    248 
    249 
    250229    def gen(self, i=0):
    251230        """
    252231        The `i`-th generator of the abelian group.
     
    254233        EXAMPLES::
    255234       
    256235            sage: F = AbelianGroup(3,[1,2,3],names='a')
    257             sage: Fd = DualAbelianGroup(F, names="A")
     236            sage: Fd = F.dual_group(names="A")
    258237            sage: Fd.0
    259             A0
     238            1
    260239            sage: Fd.1
    261240            A1
    262             sage: Fd.invariants()
    263             [2, 3]
     241            sage: Fd.gens_orders()
     242            (1, 2, 3)
    264243        """
    265244        n = self.group().ngens()
    266245        if i < 0 or i >= n:
    267246            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)
     247        x = [0]*n
     248        if self.gens_orders()[i] != 1:
     249            x[i] = 1
     250        return self.element_class(x, self)
    271251
    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))
     252    def gens(self):
     253        """
     254        Return the generators for this subgroup.
     255
     256        """
     257        n = self.group().ngens()
     258        return tuple(self.gen(i) for i in range(n))
    279259   
    280260    def ngens(self):
    281261        """
     
    283263       
    284264        EXAMPLES::
    285265       
    286             sage: F = AbelianGroup(1000)
    287             sage: Fd = DualAbelianGroup(F)
     266            sage: F = AbelianGroup([7]*100)
     267            sage: Fd = F.dual_group()
    288268            sage: Fd.ngens()
    289             1000
    290        
    291         This can be slow for 10000 or more generators.
     269            100
    292270        """
    293271        return self.group().ngens()
    294272
     273    def gens_orders(self):
     274        """
     275        The orders of the generators of the dual group.
     276
     277        OUTPUT:
     278
     279        A tuple of integers.
     280
     281        EXAMPLES::
     282
     283            sage: F = AbelianGroup([5]*1000)
     284            sage: Fd = F.dual_group()
     285            sage: invs = Fd.gens_orders(); len(invs)
     286            1000
     287        """
     288        return self.group().gens_orders()
     289
    295290    def invariants(self):
    296291        """
    297292        The invariants of the dual group.
     293
     294        You should use :meth:`gens_orders` instead.
    298295       
    299296        EXAMPLES::
    300297       
    301             sage: F = AbelianGroup(1000)
    302             sage: Fd = DualAbelianGroup(F)
    303             sage: invs = Fd.invariants(); len(invs)
     298            sage: F = AbelianGroup([5]*1000)
     299            sage: Fd = F.dual_group()
     300            sage: invs = Fd.gens_orders(); len(invs)
    304301            1000
    305        
    306         This can be slow for 10000 or more generators.
    307302        """
    308         return self.group().invariants()
     303        # TODO: deprecate
     304        return self.group().gens_orders()
    309305   
    310306    def __contains__(self,X):
    311307        """
     
    315311       
    316312            sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
    317313            sage: a,b,c,d,e = F.gens()
    318             sage: Fd = DualAbelianGroup(F, names = "ABCDE")
     314            sage: Fd = F.dual_group(names = "ABCDE")
    319315            sage: A,B,C,D,E = Fd.gens()
    320316            sage: A*B^2*D^7 in Fd
    321317            True
     
    329325        EXAMPLES::
    330326       
    331327            sage: G = AbelianGroup([2,3,9])
    332             sage: Gd = DualAbelianGroup(G)
     328            sage: Gd = G.dual_group()
    333329            sage: Gd.order()
    334330            54
    335331        """
     
    343339        EXAMPLES::
    344340       
    345341            sage: G = AbelianGroup([2,3,9])
    346             sage: Gd = DualAbelianGroup(G)
     342            sage: Gd = G.dual_group()
    347343            sage: Gd.is_commutative()
    348344            True
    349345            sage: Gd.is_abelian()
     
    351347        """
    352348        return True
    353349
     350    @cached_method
    354351    def list(self):
    355352        """
    356         Return list of all elements of this group.
     353        Return tuple of all elements of this group.
    357354       
    358355        EXAMPLES::
    359356       
    360             sage: G = AbelianGroup([2,3], names = "ab")
    361             sage: Gd = DualAbelianGroup(G, names = "AB")
     357            sage: G = AbelianGroup([2,3], names="ab")
     358            sage: Gd = G.dual_group(names="AB")
    362359            sage: Gd.list()
    363             [1, B, B^2, A, A*B, A*B^2]
     360            (1, B, B^2, A, A*B, A*B^2)
    364361        """
    365         try:
    366             return list(self.__list)
    367         except AttributeError:
    368             pass
    369362        if not(self.is_finite()):
    370363           raise NotImplementedError, "Group must be finite"
    371         invs = self.invariants()
     364        invs = self.gens_orders()
    372365        T = mrange(invs)
    373366        n = self.order()
    374         L = [DualAbelianGroupElement(self, t) for t in T]
    375         self.__list = L
    376         return list(self.__list)
     367        L = tuple( self(t) for t in T )
     368        return L
    377369     
    378370    def __iter__(self):
    379371        """
     
    381373       
    382374        EXAMPLES::
    383375       
    384             sage: G = AbelianGroup([2,3], names = "ab")
    385             sage: Gd = DualAbelianGroup(G, names = "AB")
     376            sage: G = AbelianGroup([2,3], names="ab")
     377            sage: Gd = G.dual_group(names="AB")
    386378            sage: [X for X in Gd]
    387379            [1, B, B^2, A, A*B, A*B^2]
    388380            sage: N = 43^2-1
    389381            sage: G = AbelianGroup([N],names="a")
    390             sage: Gd = DualAbelianGroup(G,names="A")
     382            sage: Gd = G.dual_group(names="A", base_ring=CC)
    391383            sage: a, = G.gens()
    392384            sage: A, = Gd.gens()
    393385            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
    1522    sage: A(a)    ## random last few digits
    16     -1.0000000000000000 + 0.00000000000000013834419720915037*I
     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(_)    ## random last few digits
     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
     
    83100def is_DualAbelianGroupElement(x):
    84101    return isinstance(x, DualAbelianGroupElement)
    85102
    86 class DualAbelianGroupElement(MonoidElement):
    87     def __init__(self, F, X):
     103
     104class DualAbelianGroupElement(AbelianGroupElementBase):
     105    """
     106    Base class for abelian group elements
     107    """
     108
     109    def __call__(self, g):
    88110        """
    89         Create an element X of the DualAbelianGroup of F.
     111        Evaluate ``self`` on a group element ``g``.
    90112
    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
     113        OUTPUT:
    97114
    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$.
     115        An element in
     116        :meth:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class.base_ring`.
    119117
    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
     118        EXAMPLES::
    135119
    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:
    249120            sage: F = AbelianGroup(5, [2,3,5,7,8], names="abcde")
    250121            sage: a,b,c,d,e = F.gens()
    251             sage: Fd = DualAbelianGroup(F, names="ABCDE")
     122            sage: Fd = F.dual_group(names="ABCDE")
    252123            sage: A,B,C,D,E = Fd.gens()
    253124            sage: A*B^2*D^7
    254125            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
     126            sage: A(a)
     127            -1
     128            sage: B(b)
     129            zeta840^140 - 1
     130            sage: CC(B(b))      ## random last few digits
     131            -0.499999999999995 + 0.866025403784447*I
     132            sage: A(a*b)
     133            -1
    261134        """
    262135        F = self.parent().base_ring()
    263         expsX = list(self.list())
    264         expsg = list(g.list())
    265         invs = self.parent().invariants()
    266         N = LCM(invs)
     136        expsX = self.exponents()
     137        expsg = g.exponents()
     138        order = self.parent().gens_orders()
     139        N = LCM(order)
    267140        if is_ComplexField(F):
    268141            from sage.symbolic.constants import pi
    269142            I = F.gen()
    270143            PI = F(pi)
    271             ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/invs[i]) for i in range(len(expsX))])
     144            ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/order[i]) for i in range(len(expsX))])
    272145            return ans
    273146        ans = F(1)  ## assumes F is the cyclotomic field
    274147        zeta = F.gen()
    275         #print F,zeta
    276148        for i in range(len(expsX)):
    277             inv_noti = N/invs[i]
    278             ans = ans*zeta**(expsX[i]*expsg[i]*inv_noti)
     149            order_noti = N/order[i]
     150            ans = ans*zeta**(expsX[i]*expsg[i]*order_noti)
    279151        return ans
    280152   
    281153    def word_problem(self, words, display=True):
     
    292164        the dual group to the corresponding problem on the group
    293165        itself and uses GAP to solve that.
    294166       
    295         EXAMPLES:
     167        EXAMPLES::
     168
    296169            sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde")
    297             sage: Gd = DualAbelianGroup(G,names="abcde")
     170            sage: Gd = G.dual_group(names="abcde")
    298171            sage: a,b,c,d,e = Gd.gens()
    299172            sage: u = a^3*b*c*d^2*e^5
    300173            sage: v = a^2*b*c^2*d^3*e^3
     
    306179
    307180        The command e.word_problem([u,v,w,x,y],display=True) returns
    308181        the same list but also prints $e = (b^2*c^2*d^3*e^5)^245$.
    309 
    310182        """
    311183        ## First convert the problem to one using AbelianGroups
    312184        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, or a tuple
     83        of base ring elements for an element of the dual abelian
     84        group.
     85
     86        EXAMPLES::
     87
     88            sage: F.<a,b,c,f> = AbelianGroup([7,8,9,0])
     89            sage: (a^3*b^2*c).exponents()
     90            (3, 2, 1, 0)
     91            sage: F([3, 2, 1, 0])
     92            a^3*b^2*c
     93            sage: (c^42).exponents()
     94            (0, 0, 6, 0)
     95            sage: (f^42).exponents()
     96            (0, 0, 0, 42)
     97        """
     98        return self._exponents
     99
     100    def list(self):
     101        """
     102        Return a copy of the exponent vector.
     103
     104        Use :meth:`exponents` instead.
     105
     106        OUTPUT:
     107
     108        The underlying coordinates used to represent this element.  If
     109        this is a word in an abelian group on `n` generators, then
     110        this is a list of nonnegative integers of length `n`.
     111
     112        EXAMPLES::
     113
     114            sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")
     115            sage: a,b,c,d,e = F.gens()
     116            sage: Ad = F.dual_group(names="ABCDE")
     117            sage: A,B,C,D,E = Ad.gens()
     118            sage: (A*B*C^2*D^20*E^65).exponents()
     119            (1, 1, 2, 6, 1)
     120            sage: X = A*B*C^2*D^2*E^-6
     121            sage: X.exponents()
     122            (1, 1, 2, 2, 2)
     123        """
     124        # to be deprecated (really, return a list??). Use exponents() instead.
     125        return list(self._exponents)
     126
     127    def _repr_(self):
     128        """
     129        Return a string representation of ``self``.
     130
     131        OUTPUT:
     132
     133        String.
     134
     135        EXAMPLES::
     136
     137            sage: G = AbelianGroup([2])
     138            sage: G.gen(0)._repr_()
     139            'f'
     140            sage: G.one()._repr_()
     141            '1'
     142        """
     143        s = ""
     144        G = self.parent()
     145        for v_i, x_i in zip(self.exponents(), G.variable_names()):
     146            if v_i == 0:
     147                continue
     148            if len(s) > 0:
     149                s += '*'
     150            if v_i == 1:
     151                s += str(x_i)
     152            else:
     153                s += str(x_i) + '^' + str(v_i)
     154        if s:
     155            return s
     156        else:
     157            return '1'
     158
     159    def __cmp__(self, other):
     160        """
     161        Compare ``self`` and ``other``.
     162
     163        OUTPUT:
     164
     165        ``-1``, ``0``, or ``+1``
     166
     167        EXAMPLES::
     168
     169            sage: G.<a,b> = AbelianGroup([2,3])
     170            sage: cmp(a,b)
     171            1
     172
     173            sage: Gd.<A,B> = G.dual_group()
     174            sage: cmp(A,B)
     175            1
     176        """
     177        return cmp(self._exponents, other._exponents)
     178
     179    @cached_method
     180    def order(self):
     181        """
     182        Return the order of this element.
     183
     184        OUTPUT:
     185
     186        An integer or ``infinity``.
     187
     188        EXAMPLES::
     189
     190            sage: F = AbelianGroup(3,[7,8,9])
     191            sage: Fd = F.dual_group()
     192            sage: A,B,C = Fd.gens()
     193            sage: (B*C).order()
     194            72
     195
     196            sage: F = AbelianGroup(3,[7,8,9]); F
     197            Multiplicative Abelian Group isomorphic to C7 x C8 x C9
     198            sage: F.gens()[2].order()
     199            9
     200            sage: a,b,c = F.gens()
     201            sage: (b*c).order()
     202            72
     203            sage: G = AbelianGroup(3,[7,8,9])
     204            sage: type((G.0 * G.1).order())==Integer
     205            True
     206        """
     207        M = self.parent()
     208        order = M.gens_orders()
     209        L = self.exponents()
     210        N = LCM([order[i]/GCD(order[i],L[i]) for i in range(len(order)) if L[i]!=0])
     211        if N == 0:
     212            return infinity
     213        else:
     214            return ZZ(N)
     215
     216    multiplicative_order = order
     217
     218    def _div_(left, right):
     219        """
     220        Divide ``left`` and ``right``
     221
     222        TESTS::
     223
     224            sage: G.<a,b> = AbelianGroup(2)
     225            sage: a/b
     226            a*b^-1
     227        """
     228        G = left.parent()
     229        assert G is right.parent()
     230        exponents = [ (x-y)%order if order!=0 else x-y
     231                      for x, y, order in
     232                      zip(left._exponents, right._exponents, G.gens_orders()) ]
     233        return G.element_class(exponents, G)
     234
     235    def _mul_(left, right):
     236        """
     237        Multiply ``left`` and ``right``
     238
     239        TESTS::
     240
     241            sage: G.<a,b> = AbelianGroup(2)
     242            sage: a*b
     243            a*b
     244        """
     245        G = left.parent()
     246        assert G is right.parent()
     247        exponents = [ (x+y)%order if order!=0 else x+y
     248                      for x, y, order in
     249                      zip(left._exponents, right._exponents, G.gens_orders()) ]
     250        return G.element_class(exponents, G)
     251
     252    def __pow__(self, n):
     253        """
     254        Exponentiate ``self``
     255
     256        TESTS::
     257
     258            sage: G.<a,b> = AbelianGroup(2)
     259            sage: a^3
     260            a^3
     261        """
     262        m = Integer(n)
     263        if n != m:
     264            raise TypeError('argument n (= '+str(n)+') must be an integer.')
     265        G = self.parent()
     266        exponents = [ (m*e) % order if order!=0 else m*e
     267                      for e,order in zip(self._exponents, G.gens_orders()) ]
     268        return G.element_class(exponents, G)
     269
     270    def inverse(self):
     271        """
     272        Returns the inverse element.
     273
     274        EXAMPLE::
     275
     276            sage: G.<a,b> = AbelianGroup([0,5])
     277            sage: a.inverse()
     278            a^-1
     279            sage: a.__invert__()
     280            a^-1
     281            sage: a^-1
     282            a^-1
     283            sage: ~a
     284            a^-1
     285            sage: (a*b).exponents()
     286            (1, 1)
     287            sage: (a*b).inverse().exponents()
     288            (-1, 4)
     289        """
     290        G = self.parent()
     291        exponents = [ (-e)%order if order!=0 else -e
     292                      for e,order in zip(self._exponents, G.gens_orders()) ]
     293        return G.element_class(exponents, G)
     294
     295    __invert__ = inverse
  • 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, :mod:`abelian_group` is an abstract Abelian group
     7defined by generators and relations. This module implements
     8:class:`AbelianGroupWithValues` that allows the group elements to be
     9decorated with values.
     10
     11An example where this module is used is the unit group of a number
     12field, see :mod:`sage.rings.number_field.unit_group`. The units form a
     13finitely generated Abelian group. We can think of the elements either
     14as abstract Abelian group elements or as particular numbers in the
     15number field. The :func:`AbelianGroupWithValues` keeps track of these
     16associated values.
     17
     18.. warning::
     19
     20    Really, this requires a group homomorphism from the abstract
     21    Abelian group to the set of values. This is only checked if you
     22    pass the ``check=True`` option to :func:`AbelianGroupWithValues`.
     23
     24EXAMPLES:
     25
     26Here is `\ZZ_6` with value `-1` assigned to the generator::
     27
     28    sage: Z6 = AbelianGroupWithValues([-1], [6], names='g')
     29    sage: g = Z6.gen(0)
     30    sage: g.value()
     31    -1
     32    sage: g*g
     33    g^2
     34    sage: (g*g).value()
     35    1
     36    sage: for i in range(7):
     37    ...       print i, g^i, (g^i).value()
     38    0 1 1
     39    1 g -1
     40    2 g^2 1
     41    3 g^3 -1
     42    4 g^4 1
     43    5 g^5 -1
     44    6 1 1
     45
     46The elements come with a coercion embedding into the
     47:meth:`values_group`, so you can use the group elements instead of the
     48values::
     49
     50    sage: CF3.<zeta> = CyclotomicField(3)
     51    sage: Z3.<g> = AbelianGroupWithValues([zeta], [3])
     52    sage: Z3.values_group()
     53    Cyclotomic Field of order 3 and degree 2
     54    sage: g.value()
     55    zeta
     56    sage: CF3(g)
     57    zeta
     58    sage: g + zeta
     59    2*zeta
     60    sage: zeta + g
     61    2*zeta
     62"""
     63
     64##########################################################################
     65#  Copyright (C) 2012 Volker Braun  <vbraun.name@gmail.com>
     66#
     67#  Distributed under the terms of the GNU General Public License (GPL):
     68#
     69#                  http://www.gnu.org/licenses/
     70##########################################################################
     71
     72
     73from sage.misc.misc import prod
     74from sage.rings.integer import Integer
     75from sage.categories.morphism import CallMorphism
     76from sage.groups.abelian_gps.abelian_group import AbelianGroup_class, _normalize
     77from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
     78
     79
     80
     81def AbelianGroupWithValues(values, n, gens_orders=None, names='f', check=False, values_group=None):
     82    """
     83    Construct an Abelian group with values associated to the generators.
     84
     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 group or ``None`` (default). The group
     103      that the values live in. If ``None`` it will be derived from the
     104      values.
     105
     106    EXAMPLES::
     107
     108        sage: G = AbelianGroupWithValues([-1], [6])
     109        sage: g = G.gen(0)
     110        sage: for i in range(7):
     111        ...       print i, g^i, (g^i).value()
     112        0 1 1
     113        1 f -1
     114        2 f^2 1
     115        3 f^3 -1
     116        4 f^4 1
     117        5 f^5 -1
     118        6 1 1
     119    """
     120    if check:
     121        raise NotImplementedError('checking that the values are a homomorphism is not implemented')
     122    gens_orders, names = _normalize(n, gens_orders, names)
     123    if values_group is None:
     124        from sage.structure.sequence import Sequence
     125        values_group = Sequence(values).universe()
     126    values = tuple( values_group(val) for val in values )
     127    M = AbelianGroupWithValues_class(gens_orders, names, values, values_group)
     128    return M
     129
     130
     131class AbelianGroupWithValuesEmbedding(CallMorphism):
     132    """
     133    The morphism embedding the Abelian group with values in its values group.
     134
     135    INPUT:
     136
     137    - ``domain`` -- a :class:`AbelianGroupWithValues_class`
     138
     139    - ``codomain`` -- the values group (need not be in the cateory of
     140      groups, e.g. symbolic ring).
     141
     142    EXAMPLES::
     143
     144        sage: Z4.<g> = AbelianGroupWithValues([I], [4])
     145        sage: embedding = Z4.values_embedding();  embedding
     146        Call morphism:
     147          From: Multiplicative Abelian Group isomorphic to C4
     148          To:   Symbolic Ring
     149        sage: embedding(1)
     150        1
     151        sage: embedding(g)
     152        I
     153        sage: embedding(g^2)
     154        -1
     155    """
     156
     157    def __init__(self, domain, codomain):
     158        """
     159        Construct the morphism
     160
     161        TESTS::
     162
     163            sage: Z4 = AbelianGroupWithValues([I], [4])
     164            sage: from sage.groups.abelian_gps.values import AbelianGroupWithValuesEmbedding
     165            sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group())
     166            Call morphism:
     167              From: Multiplicative Abelian Group isomorphic to C4
     168              To:   Symbolic Ring
     169        """
     170        assert domain.values_group() is codomain
     171        from sage.categories.homset import Hom
     172        CallMorphism.__init__(self, Hom(domain, codomain))
     173
     174    def _call_(self, x):
     175        """
     176        Return the value associated to ``x``
     177
     178        INPUT:
     179
     180        - ``x`` -- a group element
     181
     182        OUTPUT:
     183
     184        Its value.
     185
     186        EXAMPLES::
     187
     188            sage: Z4.<g> = AbelianGroupWithValues([I], [4])
     189            sage: embedding = Z4.values_embedding()
     190            sage: embedding(g)
     191            I
     192            sage: embedding._call_(g)
     193            I
     194        """
     195        return x.value()
     196
     197
     198class AbelianGroupWithValuesElement(AbelianGroupElement):
     199    """
     200    An element of an Abelian group with values assigned to generators.
     201
     202    INPUT:
     203
     204    - ``exponents`` -- tuple of integers. The exponent vector defining
     205      the group element.
     206
     207    - ``parent`` -- the parent.
     208
     209    - ``value`` -- the value assigned to the group element or ``None``
     210      (default). In the latter case, the value is computed as needed.
     211
     212    EXAMPLES::
     213
     214        sage: F = AbelianGroupWithValues([1,-1], [2,4])
     215        sage: a,b = F.gens()
     216        sage: TestSuite(a*b).run()
     217    """
     218
     219    def __init__(self, exponents, parent, value=None):
     220        """
     221        Create an element
     222
     223        EXAMPLES::
     224
     225            sage: F = AbelianGroupWithValues([1,-1], [2,4])
     226            sage: a,b = F.gens()
     227            sage: a*b^-1 in F
     228            True
     229            sage: (a*b^-1).value()
     230            -1
     231        """
     232        self._value = value
     233        AbelianGroupElement.__init__(self, exponents, parent)
     234
     235    def value(self):
     236        """
     237        Return the value of the group element.
     238
     239        OUTPUT:
     240
     241        The value according to the values for generators, see
     242        :meth:`~AbelianGroupWithValues.gens_values`.
     243
     244        EXAMPLES::
     245
     246            sage: G = AbelianGroupWithValues([5], 1)
     247            sage: G.0.value()
     248            5
     249        """
     250        if self._value is None:
     251            values = self.parent().gens_values()
     252            self._value = prod( v**e for v,e in zip(values, self.exponents()) )
     253        return self._value
     254
     255    def _div_(left, right):
     256        """
     257        Divide ``left`` by ``right``
     258
     259        TESTS::
     260
     261            sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
     262            sage: a._div_(b)
     263            a*b^-1
     264            sage: a/b
     265            a*b^-1
     266            sage: (a/b).value()
     267            5/2
     268        """
     269        m = AbelianGroupElement._div_(left, right)
     270        m._value = left.value() / right.value()
     271        return m
     272
     273    def _mul_(left, right):
     274        """
     275        Multiply ``left`` and ``right``
     276
     277        TESTS::
     278
     279            sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
     280            sage: a._mul_(b)
     281            a*b
     282            sage: a*b
     283            a*b
     284            sage: (a*b).value()
     285            10
     286        """
     287        m = AbelianGroupElement._mul_(left, right)
     288        m._value = left.value() * right.value()
     289        return m
     290
     291    def __pow__(self, n):
     292        """
     293        Exponentiate ``self``
     294
     295        INPUT:
     296
     297        - ``n`` -- integer. The exponent.
     298
     299        TESTS::
     300
     301            sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)
     302            sage: a^3
     303            a^3
     304            sage: (a^3).value()
     305            125
     306        """
     307        m = Integer(n)
     308        if n != m:
     309            raise TypeError('argument n (= '+str(n)+') must be an integer.')
     310        pow_self = AbelianGroupElement.__pow__(self, m)
     311        pow_self._value = pow(self.value(), m)
     312        return pow_self
     313
     314    def inverse(self):
     315        """
     316        Return the inverse element.
     317
     318        EXAMPLE::
     319
     320            sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])
     321            sage: a.inverse()
     322            a^-1
     323            sage: a.inverse().value()
     324            1/2
     325            sage: a.__invert__().value()
     326            1/2
     327            sage: (~a).value()
     328            1/2
     329            sage: (a*b).value()
     330            -2
     331            sage: (a*b).inverse().value()
     332            -1/2
     333        """
     334        m = AbelianGroupElement.inverse(self)
     335        m._value = ~self.value()
     336        return m
     337
     338    __invert__ = inverse
     339
     340
     341
     342class AbelianGroupWithValues_class(AbelianGroup_class):
     343    """
     344    The class of an Abelian group with values associated to the generator.
     345
     346    INPUT:
     347
     348    - ``generator_orders`` -- tuple of integers. The orders of the
     349      generators.
     350
     351    - ``names`` -- string or list of strings. The names for the generators.
     352
     353    - ``values`` -- Tuple the same length as the number of
     354      generators. The values assigned to the generators.
     355
     356    - ``values_group`` -- the common parent of the values.
     357
     358    EXAMPLES::
     359
     360        sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])
     361        sage: TestSuite(G).run()
     362    """
     363    Element = AbelianGroupWithValuesElement
     364
     365    def __init__(self, generator_orders, names, values, values_group):
     366        """
     367        The Python constructor
     368
     369        TESTS::
     370
     371            sage: G = AbelianGroupWithValues([2,-1], [0,4]); G
     372            Multiplicative Abelian Group isomorphic to Z x C4
     373
     374            sage: cm = sage.structure.element.get_coercion_model()
     375            sage: cm.explain(G, ZZ, operator.add)
     376            Coercion on left operand via
     377                Call morphism:
     378                  From: Multiplicative Abelian Group isomorphic to Z x C4
     379                  To:   Integer Ring
     380            Arithmetic performed after coercions.
     381            Result lives in Integer Ring
     382            Integer Ring
     383        """
     384        self._values = values
     385        self._values_group = values_group
     386        AbelianGroup_class.__init__(self, generator_orders, names)
     387        self._populate_coercion_lists_(embedding=self.values_embedding())
     388        if self.ngens() != len(self._values):
     389            raise ValueError('need one value per generator')
     390
     391    def gen(self, i=0):
     392        """
     393        The `i`-th generator of the abelian group.
     394
     395        INPUT:
     396
     397        - ``i`` -- integer (default: 0). The index of the generator.
     398
     399        OUTPUT:
     400
     401        A group element.
     402
     403        EXAMPLES::
     404
     405            sage: F = AbelianGroupWithValues([1,2,3,4,5], 5,[],names='a')
     406            sage: F.0
     407            a0
     408            sage: F.0.value()
     409            1
     410            sage: F.2
     411            a2
     412            sage: F.2.value()
     413            3
     414
     415            sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
     416            sage: G.gens()
     417            (f0, 1, f2)
     418        """
     419        g = AbelianGroup_class.gen(self, i)
     420        g._value = self._values[i]
     421        return g
     422
     423    def gens_values(self):
     424        """
     425        Return the values associated to the generators.
     426
     427        OUTPUT:
     428
     429        A tuple.
     430
     431        EXAMPLES::
     432
     433            sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
     434            sage: G.gens()
     435            (f0, 1, f2)
     436            sage: G.gens_values()
     437            (-1, 0, 1)
     438        """
     439        return self._values
     440
     441    def values_group(self):
     442        """
     443        The common parent of the values.
     444
     445        OUTPUT:
     446
     447        The values need to form a multiplicative group. This
     448
     449        EXAMPLES::
     450
     451            sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])
     452            sage: G.values_group()
     453            Integer Ring
     454
     455            sage: Z4 = AbelianGroupWithValues([I], [4])
     456            sage: Z4.values_group()
     457            Symbolic Ring
     458        """
     459        return self._values_group
     460
     461    def values_embedding(self):
     462        """
     463        Return the embedding of ``self`` in :meth:`values_group`.
     464
     465        OUTPUT:
     466
     467        A morphism.
     468
     469        EXAMPLES::
     470
     471            sage: Z4 = AbelianGroupWithValues([I], [4])
     472            sage: Z4.values_embedding()
     473            Call morphism:
     474              From: Multiplicative Abelian Group isomorphic to C4
     475              To:   Symbolic Ring
     476        """
     477        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
    32     """
    33     def __init__(self, category = None):
     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
     42   """
     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())
     
    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:
    6273            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)
     74        Parent.__init__(self, base=ZZ, gens=gens, category=category)
    6675   
    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 
    7376    def __contains__(self, x):
    7477        r"""
    75         True if coercion of `x` into self is defined.
     78        Test whether `x` defines a group element.
     79
     80        INPUT:
     81
     82        - ``x`` -- anything.
     83
     84        OUTPUT:
     85
     86        Boolean.
    7687
    7788        EXAMPLES::
    7889
     
    89100            return False
    90101        return True
    91102
    92 #    def category(self):
    93 #        """
    94 #        The category of all groups
    95 #        """
    96 #        import sage.categories.all
    97 #        return sage.categories.all.Groups()
    98 
    99103    def is_atomic_repr(self):
    100104        """
    101105        True if the elements of this group have atomic string
     
    113117
    114118    def is_abelian(self):
    115119        """
    116         Return True if this group is abelian.
     120        Test whether this group is abelian.
    117121
    118122        EXAMPLES::
    119123
     
    128132
    129133    def is_commutative(self):
    130134        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.
     135        Test whether this group is commutative.
     136
     137        This is an alias for is_abelian, largely to make groups work
     138        well with the Factorization class.
    134139
    135140        (Note for developers: Derived classes should override is_abelian, not
    136141        is_commutative.)
     
    256261
    257262    def cayley_graph(self, connecting_set=None):
    258263        """
    259         Returns the cayley graph for this finite group, as a Sage DiGraph
    260         object. To plot the graph with with different colors
     264        Return the Cayley graph for this finite group.
     265
     266        INPUT:
    261267       
    262         INPUT::
    263        
    264             `connecting_set` - (optional) list of elements to use for edges,
    265                                default is the stored generators
     268        - ``connecting_set`` -- (optional) list of elements to use for
     269          edges, default is the stored generators
     270
     271        OUTPUT:
     272
     273        The Cayley graph as a Sage DiGraph object. To plot the graph
     274        with with different colors
    266275       
    267276        EXAMPLES::
    268277       
     
    283292            sage: g=PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i])
    284293            sage: g.cayley_graph(connecting_set=[(1,2),(2,3)])
    285294            Digraph on 120 vertices
    286 
    287         ::
    288295       
    289296            sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices()
    290297            [()]
     
    292299        AUTHORS:
    293300
    294301        - Bobby Moretti (2007-08-10)
    295 
    296302        - Robert Miller (2008-05-01): editing
    297303        """
    298304        if connecting_set is None:
     
    315321
    316322        return DiGraph(arrows, implementation='networkx')
    317323
    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
  • new file sage/groups/old.pxd

    diff --git a/sage/groups/old.pxd b/sage/groups/old.pxd
    new file mode 100644
    - +  
     1cimport sage.structure.parent_gens
     2
     3cdef class Group(sage.structure.parent_gens.ParentWithGens):
     4    pass
     5
     6cdef class AbelianGroup(Group):
     7    pass
     8
     9cdef class FiniteGroup(Group):
     10    pass
     11
     12cdef class AlgebraicGroup(Group):
     13    pass
     14
  • new file sage/groups/old.pyx

    diff --git a/sage/groups/old.pyx b/sage/groups/old.pyx
    new file mode 100644
    - +  
     1"""
     2Base class for groups
     3"""
     4
     5#*****************************************************************************
     6#       Copyright (C) 2005 William Stein <wstein@gmail.com>
     7#
     8#  Distributed under the terms of the GNU General Public License (GPL)
     9#
     10#    This code is distributed in the hope that it will be useful,
     11#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13#    General Public License for more details.
     14#
     15#  The full text of the GPL is available at:
     16#
     17#                  http://www.gnu.org/licenses/
     18#*****************************************************************************
     19
     20doc="""
     21Base class for all groups
     22"""
     23
     24import random
     25
     26from   sage.rings.infinity import infinity
     27import sage.rings.integer_ring
     28
     29cdef class Group(sage.structure.parent_gens.ParentWithGens):
     30    """
     31    Generic group class
     32    """
     33    def __init__(self, category = None):
     34        """
     35
     36        TESTS::
     37
     38            sage: from sage.groups.old import Group
     39            sage: G = Group()
     40            sage: G.category()
     41            Category of groups
     42            sage: G = Group(category = Groups()) # todo: do the same test with some subcategory of Groups when there will exist one
     43            sage: G.category()
     44            Category of groups
     45            sage: G = Group(category = CommutativeAdditiveGroups())
     46            Traceback (most recent call last):
     47            ...
     48            AssertionError: Category of commutative additive groups is not a subcategory of Category of groups
     49
     50         Check for #8119::
     51
     52            sage: G = SymmetricGroup(2)
     53            sage: h = hash(G)
     54            sage: G.rename('S2')
     55            sage: h == hash(G)
     56            True
     57        """
     58        from sage.categories.basic import Groups
     59        if category is None:
     60            category = Groups()
     61        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)
     66
     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
     73    def __contains__(self, x):
     74        r"""
     75        True if coercion of `x` into self is defined.
     76
     77        EXAMPLES::
     78
     79            sage: from sage.groups.old import Group
     80            sage: G = Group()
     81            sage: 4 in G               #indirect doctest
     82            Traceback (most recent call last):
     83            ...
     84            NotImplementedError
     85        """
     86        try:
     87            self(x)
     88        except TypeError:
     89            return False
     90        return True
     91
     92#    def category(self):
     93#        """
     94#        The category of all groups
     95#        """
     96#        import sage.categories.all
     97#        return sage.categories.all.Groups()
     98
     99    def is_atomic_repr(self):
     100        """
     101        True if the elements of this group have atomic string
     102        representations. For example, integers are atomic but polynomials
     103        are not.
     104
     105        EXAMPLES::
     106
     107            sage: from sage.groups.old import Group
     108            sage: G = Group()
     109            sage: G.is_atomic_repr()
     110            False
     111        """
     112        return False
     113
     114    def is_abelian(self):
     115        """
     116        Return True if this group is abelian.
     117
     118        EXAMPLES::
     119
     120            sage: from sage.groups.old import Group
     121            sage: G = Group()
     122            sage: G.is_abelian()
     123            Traceback (most recent call last):
     124            ...
     125            NotImplementedError
     126        """
     127        raise NotImplementedError
     128
     129    def is_commutative(self):
     130        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.
     134
     135        (Note for developers: Derived classes should override is_abelian, not
     136        is_commutative.)
     137
     138        EXAMPLE::
     139
     140            sage: SL(2, 7).is_commutative()
     141            False
     142        """
     143        return self.is_abelian()
     144
     145    def order(self):
     146        """
     147        Returns the number of elements of this group, which is either a
     148        positive integer or infinity.
     149
     150        EXAMPLES::
     151
     152            sage: from sage.groups.old import Group
     153            sage: G = Group()
     154            sage: G.order()
     155            Traceback (most recent call last):
     156            ...
     157            NotImplementedError
     158        """
     159        raise NotImplementedError
     160
     161    def is_finite(self):
     162        """
     163        Returns True if this group is finite.
     164
     165        EXAMPLES::
     166
     167            sage: from sage.groups.old import Group
     168            sage: G = Group()
     169            sage: G.is_finite()
     170            Traceback (most recent call last):
     171            ...
     172            NotImplementedError
     173        """
     174        return self.order() != infinity
     175
     176    def is_multiplicative(self):
     177        """
     178        Returns True if the group operation is given by \* (rather than
     179        +).
     180
     181        Override for additive groups.
     182
     183        EXAMPLES::
     184
     185            sage: from sage.groups.old import Group
     186            sage: G = Group()
     187            sage: G.is_multiplicative()
     188            True
     189        """
     190        return True
     191
     192    def random_element(self, bound=None):
     193        """
     194        Return a random element of this group.
     195
     196        EXAMPLES::
     197
     198            sage: from sage.groups.old import Group
     199            sage: G = Group()
     200            sage: G.random_element()
     201            Traceback (most recent call last):
     202            ...
     203            NotImplementedError
     204        """
     205        raise NotImplementedError
     206
     207    def quotient(self, H):
     208        """
     209        Return the quotient of this group by the normal subgroup
     210        `H`.
     211
     212        EXAMPLES::
     213
     214            sage: from sage.groups.old import Group
     215            sage: G = Group()
     216            sage: G.quotient(G)
     217            Traceback (most recent call last):
     218            ...
     219            NotImplementedError
     220        """
     221        raise NotImplementedError
     222
     223cdef class AbelianGroup(Group):
     224    """
     225    Generic abelian group.
     226    """
     227    def is_abelian(self):
     228        """
     229        Return True.
     230
     231        EXAMPLES::
     232
     233            sage: from sage.groups.old import AbelianGroup
     234            sage: G = AbelianGroup()
     235            sage: G.is_abelian()
     236            True
     237        """
     238        return True
     239
     240cdef class FiniteGroup(Group):
     241    """
     242    Generic finite group.
     243    """
     244    def is_finite(self):
     245        """
     246        Return True.
     247
     248        EXAMPLES::
     249
     250            sage: from sage.groups.old import FiniteGroup
     251            sage: G = FiniteGroup()
     252            sage: G.is_finite()
     253            True
     254        """
     255        return True
     256
     257    def cayley_graph(self, connecting_set=None):
     258        """
     259        Returns the cayley graph for this finite group, as a Sage DiGraph
     260        object. To plot the graph with with different colors
     261
     262        INPUT::
     263
     264            `connecting_set` - (optional) list of elements to use for edges,
     265                               default is the stored generators
     266
     267        EXAMPLES::
     268
     269            sage: D4 = DihedralGroup(4); D4
     270            Dihedral group of order 8 as a permutation group
     271            sage: G = D4.cayley_graph()
     272            sage: show(G, color_by_label=True, edge_labels=True)
     273            sage: A5 = AlternatingGroup(5); A5
     274            Alternating group of order 5!/2 as a permutation group
     275            sage: G = A5.cayley_graph()
     276            sage: G.show3d(color_by_label=True, edge_size=0.01, edge_size2=0.02, vertex_size=0.03)
     277            sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, vertex_colors={(1,1,1):G.vertices()}, bgcolor=(0,0,0), color_by_label=True, xres=700, yres=700, iterations=200) # long time (less than a minute)
     278            sage: G.num_edges()
     279            120
     280            sage: G = A5.cayley_graph(connecting_set=[A5.gens()[0]])
     281            sage: G.num_edges()
     282            60
     283            sage: g=PermutationGroup([(i+1,j+1) for i in range(5) for j in range(5) if j!=i])
     284            sage: g.cayley_graph(connecting_set=[(1,2),(2,3)])
     285            Digraph on 120 vertices
     286
     287        ::
     288
     289            sage: s1 = SymmetricGroup(1); s = s1.cayley_graph(); s.vertices()
     290            [()]
     291
     292        AUTHORS:
     293
     294        - Bobby Moretti (2007-08-10)
     295
     296        - Robert Miller (2008-05-01): editing
     297        """
     298        if connecting_set is None:
     299            connecting_set = self.gens()
     300        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!")
     306            connecting_set = [self(g) for g in connecting_set]
     307        from sage.graphs.all import DiGraph
     308        arrows = {}
     309        for x in self:
     310            arrows[x] = {}
     311            for g in connecting_set:
     312                xg = x*g # cache the multiplication
     313                if not xg == x:
     314                    arrows[x][xg] = g
     315
     316        return DiGraph(arrows, implementation='networkx')
     317
     318cdef class AlgebraicGroup(Group):
     319    """
     320    Generic algebraic group.
     321    """
  • 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
  • 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/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  
    1414    Fractional ideal class (2, 1/2*a - 1/2)
    1515    sage: J = I * I; J
    1616    Fractional ideal class (2, 1/2*a + 1/2)
    17     sage: J.list()
    18     [2]
     17    sage: J.exponents()
     18    (2,)
    1919    sage: O = K.OK(); O
    2020    Maximal Order in Number Field in a with defining polynomial x^2 + 23
    2121    sage: O*(2, 1/2*a + 1/2)
     
    3030from sage.structure.sequence import Sequence
    3131from sage.structure.element import MonoidElement
    3232from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
    33 from sage.groups.group import Group
     33from sage.groups.old import Group
    3434from sage.rings.arith import LCM
    3535
    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.
    43 
    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
    22236
    22337
    22438class FractionalIdealClass(AbelianGroupElement):
     
    23246        sage: I = G.0; I
    23347        Fractional ideal class (2, 1/2*a - 1/2)
    23448    """
    235     def __init__(self, parent, ideal, element=None):
     49    def __init__(self, element, parent, ideal=None):
    23650        """
    23751        Returns the ideal class of this fractional ideal.
    23852
     
    24256            sage: G(K.ideal(13, a + 4))
    24357            Fractional ideal class (13, 1/2*a + 17/2)
    24458        """
    245         self.__ideal = ideal
     59        self._ideal = ideal
    24660        if element is None:
    24761            element = map(int, ideal.ideal_class_log(proof=parent._proof_flag))
    248         AbelianGroupElement.__init__(self, parent, element)
     62        AbelianGroupElement.__init__(self, element, parent)
    24963
    25064    def _repr_(self):
    25165        r"""
     
    26175        """
    26276        if self.is_principal():
    26377            return 'Trivial principal fractional ideal class'
    264         return 'Fractional ideal class %s'%self.__ideal._repr_short()
     78        return 'Fractional ideal class %s'%self._ideal._repr_short()
    26579
    26680    def _mul_(self, other):
    26781        r"""
     
    27993            Trivial principal fractional ideal class
    28094        """
    28195        m = AbelianGroupElement._mul_(self, other)
    282         return FractionalIdealClass(self.parent(), (self.__ideal * other.__ideal).reduce_equiv(), m.list())
     96        m._ideal = (self._ideal * other._ideal).reduce_equiv()
     97        return m
    28398
    28499    def __pow__(self, n):
    285100        r"""
     
    301116        """
    302117        # We use MonoidElement's __pow__ routine, since that does
    303118        # repeated squaring, and hence the ideal gets reduced as
    304         # we go along; actually computing self.__ideal ** n would
     119        # we go along; actually computing self._ideal ** n would
    305120        # be disastrous.
    306121        n = n % self.order()
    307122        return MonoidElement.__pow__(self, n)
     
    315130            sage: K.<a> = NumberField(x^3 - 3*x + 8); G = K.class_group()
    316131            sage: G(2, a).inverse()
    317132            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()
    329133            sage: ~G(2, a)
    330134            Fractional ideal class (2, a^2 + 2*a - 1)
    331135        """
    332         return self.inverse()
     136        m = AbelianGroupElement.inverse(self)
     137        m._ideal = (~self._ideal).reduce_equiv()
     138        return m
     139
     140    __invert__ = inverse
    333141
    334142    def is_principal(self):
    335143        r"""
     
    369177            sage: J == I^5
    370178            True
    371179        """
    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()
     180        return self.parent()(self._ideal.reduce_equiv())
    406181
    407182    def ideal(self):
    408183        r"""
     
    419194            sage: c.ideal()
    420195            Fractional ideal (2, 1/2*w - 1/2)
    421196        """
    422         return self.__ideal
     197        return self._ideal
    423198
    424199    def gens(self):
    425200        r"""
     
    440215        return self.ideal().gens()
    441216
    442217
     218
     219class SFractionalIdealClass(FractionalIdealClass):
     220    r"""
     221    An S-fractional ideal class in a number field for a tuple of primes S.
     222
     223    TESTS::
     224
     225        sage: K.<a> = QuadraticField(-14)
     226        sage: I = K.ideal(2,a)
     227        sage: S = (I,)
     228        sage: CS = K.S_class_group(S)
     229        sage: J = K.ideal(7,a)
     230        sage: G = K.ideal(3,a+1)
     231        sage: CS(I).order()
     232        1
     233        sage: CS(J).order()
     234        1
     235        sage: CS(G).order()
     236        2
     237    """
     238    Element = FractionalIdealClass
     239
     240    def __init__(self, element, parent, ideal=None):
     241        r"""
     242        Returns the S-ideal class of this fractional ideal.
     243
     244        EXAMPLES::
     245
     246            sage: K.<a> = QuadraticField(-14)
     247            sage: I = K.ideal(2,a)
     248            sage: S = (I,)
     249            sage: CS = K.S_class_group(S)
     250            sage: J = K.ideal(7,a)
     251            sage: G = K.ideal(3,a+1)
     252            sage: CS(I)
     253            Trivial S-ideal class
     254            sage: CS(J)
     255            Trivial S-ideal class
     256            sage: CS(G)
     257            Fractional S-ideal class (3, a + 1)
     258        """
     259        self._ideal = ideal
     260        if element is None:
     261            element = ideal.S_ideal_class_log(parent.S())
     262        AbelianGroupElement.__init__(self, element, parent)
     263
     264    def _repr_(self):
     265        r"""
     266        Returns a string representation of the S-ideal class of this fractional ideal.
     267
     268        EXAMPLE::
     269
     270            sage: K.<a> = QuadraticField(-14)
     271            sage: I = K.ideal(2,a)
     272            sage: J = K.ideal(3, a + 2)
     273            sage: S = (I,)
     274            sage: CS = K.S_class_group(S)
     275            sage: CS(J)
     276            Fractional S-ideal class (3, a + 2)
     277            sage: CS(J^2)
     278            Trivial S-ideal class
     279        """
     280        if not any(self.exponents()):
     281            return 'Trivial S-ideal class'
     282        return 'Fractional S-ideal class %s' % self._ideal._repr_short()
     283
     284    def ideal(self):
     285        r"""
     286        Returns a representative ideal for this S-ideal class.
     287
     288        EXAMPLES::
     289
     290            sage: K.<a> = QuadraticField(-14)
     291            sage: I = K.ideal(2,a)
     292            sage: S = (I,)
     293            sage: CS = K.S_class_group(S)
     294            sage: J = K.ideal(7,a)
     295            sage: G = K.ideal(3,a+1)
     296            sage: CS(I).ideal()
     297            Fractional ideal (2, a)
     298            sage: CS(J).ideal()
     299            Fractional ideal (7, a)
     300            sage: CS(G).ideal()
     301            Fractional ideal (3, a + 1)
     302        """
     303        return self._ideal
     304
     305    def _mul_(self, other):
     306        r"""
     307        Multiplies together two S-ideal classes.
     308
     309        EXAMPLES::
     310
     311            sage: K.<a> = QuadraticField(-14)
     312            sage: I = K.ideal(2,a)
     313            sage: S = (I,)
     314            sage: CS = K.S_class_group(S)
     315            sage: G = K.ideal(3,a+1)
     316            sage: CS(G)*CS(G)
     317            Trivial S-ideal class
     318        """
     319        m = AbelianGroupElement._mul_(self, other)
     320        m._ideal = (self.ideal() * other.ideal()).reduce_equiv()
     321        return m
     322
     323    def inverse(self):
     324        r"""
     325        Finds the inverse of the given S-ideal class.
     326
     327        EXAMPLES::
     328
     329            sage: K.<a> = QuadraticField(-14)
     330            sage: I = K.ideal(2,a)
     331            sage: S = (I,)
     332            sage: CS = K.S_class_group(S)
     333            sage: G = K.ideal(3,a+1)
     334            sage: CS(G).inverse()
     335            Fractional S-ideal class (3, a + 2)
     336        """
     337        m = AbelianGroupElement.inverse(self)
     338        m._ideal = self.parent().number_field().class_group()(self.ideal()).inverse().ideal()
     339        return m
     340
     341
     342
     343class ClassGroup(AbelianGroup_class):
     344    r"""
     345    The class group of a number field.
     346    """
     347    Element = FractionalIdealClass
     348
     349    def __init__(self, gens_orders, names, number_field, gens, proof=True):
     350        r"""
     351        Create a class group.
     352
     353        Note that the error in the test suite below is caused by the fact that
     354        there is no category of additive abelian groups.
     355
     356        EXAMPLES::
     357
     358            sage: K.<a> = NumberField(x^2 + 23)
     359            sage: G = K.class_group(); G
     360            Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23
     361
     362            sage: G.category()
     363            Category of groups
     364            sage: TestSuite(G).run()
     365        """
     366        AbelianGroup_class.__init__(self, gens_orders, names)
     367        self._proof_flag = proof
     368        self.__number_field = number_field
     369        self.__gens = Sequence([self(x) for x in gens], immutable=True,
     370                               universe=self, check=False)
     371
     372    def _element_constructor_(self, *args, **kwds):
     373        r"""
     374        Create an element of this class group from the given data. This may be:
     375        an ideal class in this number field; an ideal class in a subfield; or
     376        anything from which an ideal in this number field can be constructed.
     377
     378        EXAMPLES::
     379
     380            sage: K.<b> = NumberField(x^2 + 389)
     381            sage: C = K.class_group()
     382            sage: C(K.ideal(b)) # indirect doctest
     383            Trivial principal fractional ideal class
     384            sage: C(K.ideal(59049, b + 35312)) # indirect doctest
     385            Fractional ideal class (59049, b + 35312)
     386            sage: C((59049, b + 35312)) # indirect doctest
     387            Fractional ideal class (59049, b + 35312)
     388            sage: C(59049, b + 35312) # indirect doctest
     389            Fractional ideal class (59049, b + 35312)
     390
     391            sage: K.<a> = QuadraticField(-23)
     392            sage: L.<b> = K.extension(x^2 - 2)
     393            sage: CK = K.class_group()
     394            sage: CL = L.class_group()
     395            sage: [CL(I).exponents() for I in CK]
     396            [(0,), (2,), (4,)]
     397        """
     398        if isinstance(args[0], FractionalIdealClass):
     399            return self.element_class(None, self, self.__number_field.ideal(args[0].ideal()))
     400        else:
     401            I = self.__number_field.ideal(*args, **kwds)
     402            if I.is_zero(): raise TypeError, "The zero ideal is not a fractional ideal"
     403            return self.element_class(None, self, I)
     404
     405    def gens(self):
     406        r"""
     407        Return generators for the class group.
     408
     409        EXAMPLES::
     410
     411            sage: K.<a> = NumberField(x^4 + 23)
     412            sage: K.class_group().gens()   # random gens (platform dependent)
     413            [Fractional ideal class (2, 1/2*a^2 - a + 3/2)]
     414
     415            sage: C = NumberField(x^2 + x + 23899, 'a').class_group(); C
     416            Class group of order 68 with structure C34 x C2 of Number Field
     417            in a with defining polynomial x^2 + x + 23899
     418            sage: C.gens()
     419            [Fractional ideal class (23, a + 14), Fractional ideal class (5, a + 3)]
     420            sage: C.ngens()
     421            2
     422        """
     423        return self.__gens
     424
     425    def gen(self, i=0):
     426        r"""
     427        Return the i-th generator for this class group.
     428
     429        EXAMPLES::
     430
     431            sage: C = NumberField(x^2 + 120071, 'a').class_group(); C
     432            Class group of order 500 with structure C250 x C2 of Number Field in a with defining polynomial x^2 + 120071
     433            sage: C.gen(0) # random
     434            Fractional ideal class (130, 1/2*a + 137/2)
     435            sage: C.gen(1) # random
     436            Fractional ideal class (7, a)
     437        """
     438        return self.__gens[i]
     439
     440    def __iter__(self):
     441        r"""
     442        Return an iterator of all ideal classes in this class group.
     443
     444        EXAMPLES::
     445
     446            sage: K.<a> = NumberField(x^4 + 23)
     447            sage: G = K.class_group()
     448            sage: G
     449            Class group of order 3 with structure C3 of Number Field
     450            in a with defining polynomial x^4 + 23
     451            sage: list(G)
     452            [Trivial principal fractional ideal class,
     453             Fractional ideal class (2, 1/4*a^3 - 1/4*a^2 + 1/4*a - 1/4),
     454             Fractional ideal class (2, 1/2*a^2 + 1/2)]
     455            sage: G.list()
     456            [Trivial principal fractional ideal class,
     457             Fractional ideal class (2, 1/4*a^3 - 1/4*a^2 + 1/4*a - 1/4),
     458             Fractional ideal class (2, 1/2*a^2 + 1/2)]
     459
     460        TESTS::
     461
     462            sage: K.<a> = NumberField(x^2 + 1)
     463            sage: G = K.class_group()
     464            sage: G
     465            Class group of order 1 of Number Field in a with defining polynomial x^2 + 1
     466            sage: list(G)
     467            [Trivial principal fractional ideal class]
     468            sage: G.list()
     469            [Trivial principal fractional ideal class]
     470        """
     471        from sage.misc.mrange import mrange
     472        orders = self.gens_orders()
     473        T = mrange(orders)
     474        g = self.gens()
     475        for t in T:
     476            I = self(1)
     477            for i, j in enumerate(t):
     478                I *= g[i]**j
     479            yield I
     480        if not T:
     481            yield self(1)
     482
     483    def _repr_(self):
     484        r"""
     485        Return string representation of self.
     486
     487        EXAMPLES::
     488
     489            sage: C = NumberField(x^2 + 23, 'a').class_group()
     490            sage: C._repr_()
     491            'Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23'
     492        """
     493        s = 'Class group of order %s '%self.order()
     494        if self.order() > 1:
     495            s += 'with structure %s '%self._group_notation(self.gens_orders())
     496        s += 'of %s'%self.number_field()
     497        return s
     498
     499    def number_field(self):
     500        r"""
     501        Return the number field that this class group is attached to.
     502
     503        EXAMPLES::
     504
     505            sage: C = NumberField(x^2 + 23, 'w').class_group(); C
     506            Class group of order 3 with structure C3 of Number Field in w with defining polynomial x^2 + 23
     507            sage: C.number_field()
     508            Number Field in w with defining polynomial x^2 + 23
     509        """
     510        return self.__number_field
     511
     512
     513
     514
     515
    443516class SClassGroup(ClassGroup):
    444517    r"""
    445518    The S-class group of a number field.
    446519    """
     520    Element = SFractionalIdealClass
    447521
    448     def __init__(self, invariants, names, number_field, gens, S, proof=True):
     522    def __init__(self, gens_orders, names, number_field, gens, S, proof=True):
    449523        r"""
    450524        Create an S-class group.
    451525
     
    460534            sage: K.S_class_group([K.ideal(13, a + 8)])
    461535            S-class group of order 4 with structure C2 x C2 of Number Field in a with defining polynomial x^2 + 105
    462536        """
    463         AbelianGroup_class.__init__(self, len(invariants), invariants, names)
     537        AbelianGroup_class.__init__(self, gens_orders, names)
    464538        self._proof_flag = proof
    465539        self.__number_field = number_field
    466540        self.__S = S
    467         self.__gens = Sequence([SFractionalIdealClass(self, x) for x in gens], immutable=True,
     541        self.__gens = Sequence([self(x) for x in gens], immutable=True,
    468542                               universe=self, check=False)
    469543
    470544    def S(self):
     
    488562        """
    489563        return self.__S
    490564
    491     def __call__(self, *args, **kwds):
    492         r"""
    493         Call method.
    494        
    495         EXAMPLES::
    496        
    497             sage: K.<a> = QuadraticField(-14)
    498             sage: I = K.ideal(2,a)                 
    499             sage: S = (I,)
    500             sage: CS = K.S_class_group(S)
    501             sage: J = K.ideal(7,a)
    502             sage: G = K.ideal(3,a+1)
    503             sage: CS(I)
    504             Trivial S-ideal class
    505             sage: CS(J)
    506             Trivial S-ideal class
    507             sage: CS(G)
    508             Fractional S-ideal class (3, a + 1)
    509         """
    510         return Group.__call__(self, *args, **kwds)
    511 
    512565    def _element_constructor_(self, *args, **kwds):
    513566        r"""
    514567        Create an element of this class group from the given data.
     
    529582            Fractional S-ideal class (3, a + 1)
    530583        """
    531584        if isinstance(args[0], FractionalIdealClass):
    532             return SFractionalIdealClass(self, args[0].ideal())
     585            return self.element_class(None, self, args[0].ideal())
    533586        else:
    534587            I = self.number_field().ideal(*args, **kwds)
    535588            if I.is_zero(): raise TypeError, "The zero ideal is not a fractional ideal"
    536             return SFractionalIdealClass(self, I)
     589            return self.element_class(None, self, I)
    537590
    538591    def gens(self):
    539592        r"""
     
    562615            sage: CS.gen(1) # random
    563616            Fractional S-ideal class (31, a + 24)
    564617        """
    565         if i < 0 or i >= len(self.__gens):
    566             raise IndexError
    567618        return self.__gens[i]
    568619
    569620    def _repr_(self):
     
    579630        """
    580631        s = 'S-class group of order %s ' % self.order()
    581632        if self.order() > 1:
    582             s += 'with structure %s ' % self._group_notation(self.invariants())
     633            s += 'with structure %s ' % self._group_notation(self.gens_orders())
    583634        s += 'of %s' % self.number_field()
    584635        return s
    585636
     
    595646            Number Field in a with defining polynomial x^2 + 14
    596647        """
    597648        return self.__number_field
    598 
    599 
    600 class SFractionalIdealClass(FractionalIdealClass):
    601     r"""
    602     An S-fractional ideal class in a number field for a tuple of primes S.
    603     """
    604 
    605     def __init__(self, parent, ideal, element=None):
    606         r"""
    607         Returns the S-ideal class of this fractional ideal.
    608 
    609         EXAMPLES::
    610        
    611             sage: K.<a> = QuadraticField(-14)
    612             sage: I = K.ideal(2,a)                 
    613             sage: S = (I,)
    614             sage: CS = K.S_class_group(S)
    615             sage: J = K.ideal(7,a)
    616             sage: G = K.ideal(3,a+1)
    617             sage: CS(I)
    618             Trivial S-ideal class
    619             sage: CS(J)
    620             Trivial S-ideal class
    621             sage: CS(G)
    622             Fractional S-ideal class (3, a + 1)
    623         """
    624         self.__ideal = ideal
    625         if element is None:
    626             element = ideal.S_ideal_class_log(parent.S())
    627         AbelianGroupElement.__init__(self, parent, element)
    628 
    629     def _repr_(self):
    630         r"""
    631         Returns a string representation of the S-ideal class of this fractional ideal.
    632 
    633         EXAMPLE::
    634        
    635             sage: K.<a> = QuadraticField(-14)
    636             sage: I = K.ideal(2,a)                 
    637             sage: J = K.ideal(3, a + 2)
    638             sage: S = (I,)
    639             sage: CS = K.S_class_group(S)
    640             sage: CS(J)
    641             Fractional S-ideal class (3, a + 2)
    642             sage: CS(J^2)
    643             Trivial S-ideal class
    644         """
    645         if not any(self.list()):
    646             return 'Trivial S-ideal class'
    647         return 'Fractional S-ideal class %s' % self.__ideal._repr_short()
    648 
    649     def ideal(self):
    650         r"""
    651         Returns a representative ideal for this S-ideal class.
    652 
    653         EXAMPLES::
    654        
    655             sage: K.<a> = QuadraticField(-14)
    656             sage: I = K.ideal(2,a)                 
    657             sage: S = (I,)
    658             sage: CS = K.S_class_group(S)
    659             sage: J = K.ideal(7,a)
    660             sage: G = K.ideal(3,a+1)
    661             sage: CS(I).ideal()
    662             Fractional ideal (2, a)
    663             sage: CS(J).ideal()
    664             Fractional ideal (7, a)
    665             sage: CS(G).ideal()
    666             Fractional ideal (3, a + 1)
    667         """
    668         return self.__ideal
    669 
    670     def order(self):
    671         r"""
    672         Finds the order of the given S-ideal class.
    673        
    674         EXAMPLES::
    675        
    676             sage: K.<a> = QuadraticField(-14)
    677             sage: I = K.ideal(2,a)                 
    678             sage: S = (I,)
    679             sage: CS = K.S_class_group(S)
    680             sage: J = K.ideal(7,a)
    681             sage: G = K.ideal(3,a+1)
    682             sage: CS(I).order()
    683             1
    684             sage: CS(J).order()
    685             1
    686             sage: CS(G).order()
    687             2
    688         """
    689         return LCM([e.additive_order() for e in self.list()])
    690 
    691     def _mul_(self, other):
    692         r"""
    693         Multiplies together two S-ideal classes.
    694        
    695         EXAMPLES::
    696        
    697             sage: K.<a> = QuadraticField(-14)
    698             sage: I = K.ideal(2,a)                 
    699             sage: S = (I,)
    700             sage: CS = K.S_class_group(S)
    701             sage: G = K.ideal(3,a+1)
    702             sage: CS(G)*CS(G)
    703             Trivial S-ideal class
    704         """
    705 
    706         m = AbelianGroupElement._mul_(self, other)
    707         return SFractionalIdealClass(self.parent(), (self.ideal() * other.ideal()).reduce_equiv(), m.list())
    708 
    709     def inverse(self):
    710         r"""
    711         Finds the inverse of the given S-ideal class.
    712        
    713         EXAMPLES::
    714        
    715             sage: K.<a> = QuadraticField(-14)
    716             sage: I = K.ideal(2,a)                 
    717             sage: S = (I,)
    718             sage: CS = K.S_class_group(S)
    719             sage: G = K.ideal(3,a+1)
    720             sage: CS(G).inverse()
    721             Fractional S-ideal class (3, a + 2)
    722         """
    723         m = AbelianGroupElement.inverse(self)
    724         inv_ideal = self.parent().number_field().class_group()(self.ideal()).inverse().ideal()
    725         return SFractionalIdealClass(self.parent(), inv_ideal , m.list())
  • sage/rings/number_field/number_field.py

    diff --git a/sage/rings/number_field/number_field.py b/sage/rings/number_field/number_field.py
    a b  
    32673267        except AttributeError:
    32683268            self.__class_group = {}
    32693269        k = self.pari_bnf(proof)
    3270         cycle_structure = [ZZ(c) for c in k.bnf_get_cyc()]
     3270        cycle_structure = tuple( ZZ(c) for c in k.bnf_get_cyc() )
    32713271
    32723272        # Gens is a list of ideals (the generators)
    3273         gens = [self.ideal(hnf) for hnf in k.bnf_get_gen()]
     3273        gens = tuple( self.ideal(hnf) for hnf in k.bnf_get_gen() )
    32743274       
    32753275        G = ClassGroup(cycle_structure, names, self, gens, proof=proof)       
    32763276        self.__class_group[proof, names] = G
     
    33503350            Slist = zip([g.ideal() for g in C.gens()], C.invariants())
    33513351        else:
    33523352            Slist = self._S_class_group_and_units(tuple(S), proof=proof)[1]
    3353         return SClassGroup([s[1] for s in Slist], names, self, [s[0] for s in Slist], S)
     3353        return SClassGroup(tuple(s[1] for s in Slist), names, self,
     3354                           tuple(s[0] for s in Slist), tuple(S))
    33543355
    33553356    def S_units(self, S, proof=True):
    33563357        """
     
    34323433        S_pari = [p.pari_prime() for p in S]
    34333434       
    34343435        result = K_pari.bnfsunit(S_pari)
    3435         units = map(self, result[0]) + self.unit_group().gens()
     3436        units = map(self, result[0]) + self.unit_group().gens_values()
    34363437       
    34373438        pari_cyc = result[4][1]
    34383439        pari_gens = result[4][2]
     
    51925193            sage: U = K.unit_group(); U
    51935194            Unit group with structure C10 x Z of Number Field in a with defining polynomial x^4 - 10*x^3 + 100*x^2 - 375*x + 1375
    51945195            sage: U.gens()
     5196            (u0, u1)
     5197            sage: U.gens_values()
    51955198            [-7/275*a^3 + 1/11*a^2 - 9/11*a - 1, 6/275*a^3 - 9/55*a^2 + 14/11*a - 2]
    51965199            sage: U.invariants()
    5197             [10, 0]
     5200            (10, 0)
    51985201            sage: [u.multiplicative_order() for u in U.gens()]
    51995202            [10, +Infinity]
    52005203
     
    52095212            sage: U = K.unit_group(proof=False)
    52105213            sage: U
    52115214            Unit group with structure C2 x Z x Z x Z x Z x Z x Z x Z x Z of Number Field in a with defining polynomial x^17 + 3
    5212             sage: U.gens()  # result not independently verified
     5215            sage: U.gens()
     5216            (u0, u1, u2, u3, u4, u5, u6, u7, u8)
     5217            sage: U.gens_values()  # result not independently verified
    52135218            [-1, a^9 + a - 1, a^16 - a^15 + a^14 - a^12 + a^11 - a^10 - a^8 + a^7 - 2*a^6 + a^4 - 3*a^3 + 2*a^2 - 2*a + 1, 2*a^16 - a^14 - a^13 + 3*a^12 - 2*a^10 + a^9 + 3*a^8 - 3*a^6 + 3*a^5 + 3*a^4 - 2*a^3 - 2*a^2 + 3*a + 4, a^15 + a^14 + 2*a^11 + a^10 - a^9 + a^8 + 2*a^7 - a^5 + 2*a^3 - a^2 - 3*a + 1, a^16 + a^15 + a^14 + a^13 + a^12 + a^11 + a^10 + a^9 + a^8 + a^7 + a^6 + a^5 + a^4 + a^3 + a^2 - 2, 2*a^16 - 3*a^15 + 3*a^14 - 3*a^13 + 3*a^12 - a^11 + a^9 - 3*a^8 + 4*a^7 - 5*a^6 + 6*a^5 - 4*a^4 + 3*a^3 - 2*a^2 - 2*a + 4, a^15 - a^12 + a^10 - a^9 - 2*a^8 + 3*a^7 + a^6 - 3*a^5 + a^4 + 4*a^3 - 3*a^2 - 2*a + 2, 2*a^16 + a^15 - a^11 - 3*a^10 - 4*a^9 - 4*a^8 - 4*a^7 - 5*a^6 - 7*a^5 - 8*a^4 - 6*a^3 - 5*a^2 - 6*a - 7]
    52145219        """
    52155220        try:
  • sage/rings/number_field/number_field_ideal.py

    diff --git a/sage/rings/number_field/number_field_ideal.py b/sage/rings/number_field/number_field_ideal.py
    a b  
    21622162        G = self.idealstar(2)
    21632163   
    21642164        invs = G.invariants()
    2165         g = G.gens()
     2165        g = G.gens_values()
    21662166        n = G.ngens()
    21672167   
    21682168        from sage.matrix.all import Matrix, diagonal_matrix
     
    24552455            Multiplicative Abelian Group isomorphic to C24 x C4
    24562456            sage: G.gens()
    24572457            (f0, f1)
     2458
    24582459            sage: G = A.idealstar(2)
    2459             sage: all([G.gens()[i] in k for i in range(G.ngens())])
     2460            sage: G.gens()
     2461            (f0, f1)
     2462            sage: G.gens_values()
     2463            (-a^2 + 2*a, 2*a^2 + 2*a - 2)
     2464            sage: all([G.gen(i).value() in k for i in range(G.ngens())])
    24602465            True
    24612466
     2467        TESTS::
     2468
     2469            sage: k.<a> = NumberField(x^2 + 1)
     2470            sage: k.ideal(a+1).idealstar(2)
     2471            Trivial Abelian Group
     2472
    24622473        ALGORITHM: Uses Pari function ``idealstar``
    24632474        """
    24642475        k = self.number_field()
     
    24682479            G = self._pari_bid_(flag)
    24692480        inv = [ZZ(c) for c in G.bid_get_cyc()]
    24702481
    2471         from sage.groups.abelian_gps.abelian_group import AbelianGroup
    2472         AG = AbelianGroup(len(inv), inv)
    24732482        if flag == 2 or flag == 0:
     2483            from sage.groups.abelian_gps.values import AbelianGroupWithValues
    24742484            g = G.bid_get_gen()
    2475             AG._gens = tuple(map(k, g))
     2485            AG = AbelianGroupWithValues(tuple(map(k, g)), inv, values_group=k)
     2486        else:
     2487            from sage.groups.abelian_gps.abelian_group import AbelianGroup
     2488            AG = AbelianGroup(inv)
    24762489        return AG
    24772490
    24782491    def ideallog(self, x, gens=None, check=True):
     
    25122525            sage: A = k.ideal(5)
    25132526            sage: G = A.idealstar(2)
    25142527            sage: l = A.ideallog(a^2 +3)
    2515             sage: r = prod([G.gens()[i]**l[i] for i in range(len(l))])
     2528            sage: r = G(l).value()
    25162529            sage: (a^2 + 3) - r in A
    25172530            True
    25182531            sage: A.small_residue(r) # random
  • sage/rings/number_field/unit_group.py

    diff --git a/sage/rings/number_field/unit_group.py b/sage/rings/number_field/unit_group.py
    a b  
    1010
    1111The first generator is a primitive root of unity in the field::
    1212
    13     sage: UK.gens()  # random
     13    sage: UK.gens()
     14    (u0, u1)
     15    sage: UK.gens_values()  # random
    1416    [-1/12*a^3 + 1/6*a, 1/24*a^3 + 1/4*a^2 - 1/12*a - 1]
    15     sage: UK.gens()[0]
     17    sage: UK.gen(0).value()
    1618    -1/12*a^3 + 1/6*a
     19
     20    sage: UK.gen(0)
     21    u0
     22    sage: UK.gen(0) + K.one()   # coerce abstract generator into number field
     23    -1/12*a^3 + 1/6*a + 1
     24
    1725    sage: [u.multiplicative_order() for u in UK.gens()]
    1826    [4, +Infinity]
    19 
    2027    sage: UK.rank()
    2128    1
    2229    sage: UK.ngens()
     
    3542    sage: UK.fundamental_units() # random
    3643    [1/24*a^3 + 1/4*a^2 - 1/12*a - 1]
    3744    sage: UK.torsion_generator()
     45    u0
     46    sage: _.value()
    3847    -1/12*a^3 + 1/6*a
    3948    sage: UK.zeta_order()
    4049    4
     
    4756    sage: u = UK.exp([13,10]); u # random
    4857    -41/8*a^3 - 55/4*a^2 + 41/4*a + 55
    4958    sage: UK.log(u)
    50     [1, 10]
     59    (1, 10)
    5160    sage: u = UK.fundamental_units()[0]
    52     sage: [UK.log(u^k) == [0,k] for k in range(10)]
     61    sage: [UK.log(u^k) == (0,k) for k in range(10)]
    5362    [True, True, True, True, True, True, True, True, True, True]
    54     sage: all([UK.log(u^k) == [0,k] for k in range(10)])
     63    sage: all([UK.log(u^k) == (0,k) for k in range(10)])
    5564    True
    5665
    5766    sage: K.<a> = NumberField(x^5-2,'a')
     
    6675    sage: L.<a, b> = NumberField([x^2 + x + 1, x^4 + 1])
    6776    sage: UL = L.unit_group(); UL
    6877    Unit group with structure C24 x Z x Z x Z of Number Field in a with defining polynomial x^2 + x + 1 over its base field
    69     sage: UL.gens() # random
     78    sage: UL.gens_values() # random
    7079    [-b^3*a - b^3, -b^3*a + b, (-b^3 - b^2 - b)*a - b - 1, (-b^3 - 1)*a - b^2 + b - 1]
    7180    sage: UL.zeta_order()
    7281    24
     
    108117#                  http://www.gnu.org/licenses/
    109118#*****************************************************************************
    110119
    111 from sage.groups.abelian_gps.abelian_group import AbelianGroup_class
    112 from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
    113 
     120from sage.groups.abelian_gps.values import AbelianGroupWithValues_class
    114121from sage.structure.sequence import Sequence
    115122from sage.structure.proof.proof import get_flag
    116123from sage.libs.all import pari
    117124from sage.misc.misc import prod
    118125from sage.rings.integer_ring import ZZ
    119126
    120 class UnitGroup(AbelianGroup_class):
     127class UnitGroup(AbelianGroupWithValues_class):
    121128    """
    122129    The unit group of a number field.
     130
     131    TESTS::
     132
     133        sage: x = polygen(QQ)
     134        sage: K.<a> = NumberField(x^4 + 23)
     135        sage: UK = K.unit_group()
     136        sage: UK.an_element()
     137        u0*u1
     138        sage: _.value()
     139        -1/4*a^3 - 7/4*a^2 - 17/4*a - 19/4
     140
     141        sage: x = polygen(QQ)
     142        sage: K.<a> = NumberField(x^4 + 23)
     143        sage: K.unit_group().gens_values() # random
     144        [-1, 1/4*a^3 - 7/4*a^2 + 17/4*a - 19/4]
     145
     146        sage: x = polygen(QQ)
     147        sage: U = NumberField(x^2 + x + 23899, 'a').unit_group(); U
     148        Unit group with structure C2 of Number Field in a with defining polynomial x^2 + x + 23899
     149        sage: U.ngens()
     150        1
     151
     152        sage: K.<z> = CyclotomicField(13)
     153        sage: UK = K.unit_group()
     154        sage: UK.ngens()
     155        6
     156        sage: UK.gen(0) # random
     157        -z^11
     158        sage: UK.gen(1) # random
     159        z^5 + z^3
     160        sage: UK.gen(2) # random
     161        z^6 + z^5
     162        sage: UK.gen(3) # random
     163        z^9 + z^7 + z^5
     164        sage: UK.gen(4) # random
     165        z^9 + z^5 + z^4 + 1
     166        sage: UK.gen(5) # random
     167        z^5 + z
    123168    """
     169    # This structure is not a parent in the usual sense. The
     170    # "elements" are NumberFieldElement_absolute. Instead, they should
     171    # derive from AbelianGroupElement and coerce into
     172    # NumberFieldElement_absolute.
     173
    124174    def __init__(self, number_field, proof=True):
    125175        """
    126176        Create a unit group of a number field.
     
    141191            sage: UK = K.unit_group(); UK
    142192            Unit group with structure C2 x Z of Number Field in a with defining polynomial x^2 - 38
    143193            sage: UK.gens()
     194            (u0, u1)
     195            sage: UK.gens_values()
    144196            [-1, 6*a - 37]
    145197
    146198            sage: K.<a> = QuadraticField(-3)
    147199            sage: UK = K.unit_group(); UK
    148200            Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3
    149201            sage: UK.gens()
     202            (u,)
     203            sage: UK.gens_values()
    150204            [-1/2*a + 1/2]
    151205
    152206            sage: K.<z> = CyclotomicField(13)
    153207            sage: UK = K.unit_group(); UK
    154208            Unit group with structure C26 x Z x Z x Z x Z x Z of Cyclotomic Field of order 13 and degree 12
    155             sage: UK.gens() # random
     209            sage: UK.gens()
     210            (u0, u1, u2, u3, u4, u5)
     211            sage: UK.gens_values() # random
    156212            [-z^11, z^5 + z^3, z^6 + z^5, z^9 + z^7 + z^5, z^9 + z^5 + z^4 + 1, z^5 + z]
    157213            """
    158214        proof = get_flag(proof, "number_field")
     
    174230
    175231        # Store the actual generators (torsion first):
    176232        gens = [z] + fu
    177         self.__nfu = len(fu)
    178         self.__gens = Sequence(gens, immutable=True, universe=self, check=False)
     233        values = Sequence(gens, immutable=True, universe=self, check=False)
    179234        # Construct the abtract group: