Ticket #9244: trac_9244_ver4.patch

File trac_9244_ver4.patch, 16.0 KB (added by David Loeffler, 13 years ago)

replaces all previous attempts

  • sage/rings/number_field/class_group.py

    # HG changeset patch
    # User David Loeffler <d.loeffler.01@cantab.net>
    # Date 1277453061 -3600
    # Node ID 9d33ffed40c71cf3199bfb91e2ca83ee2523da0f
    # Parent  8dec8b43ccca5f104b1e280cb33c8f4c2c1b8f85
    #9244: technical improvements to number field class groups
    
    diff -r 8dec8b43ccca -r 9d33ffed40c7 sage/rings/number_field/class_group.py
    a b  
    1 """
     1r"""
    22Class Groups of Number Fields
    33
     4An element of a class group is stored as a pair consisting of both an explicit
     5ideal in that ideal class, and a list of exponents giving that ideal class in
     6terms of the generators of the parent class group. These can be accessed with
     7the ``ideal()`` and ``list()`` methods respectively.
     8
    49EXAMPLES::
    510
    611    sage: K.<a> = NumberField(x^2 + 23)
     
    813    Fractional ideal class (2, 1/2*a - 1/2)
    914    sage: J = I * I; J
    1015    Fractional ideal class (2, 1/2*a + 1/2)
     16    sage: J.list()
     17    [2]
    1118    sage: O = K.OK(); O
    1219    Maximal Order in Number Field in a with defining polynomial x^2 + 23
    1320    sage: O*(2, 1/2*a + 1/2)
     
    1926"""
    2027
    2128from sage.groups.abelian_gps.abelian_group import AbelianGroup_class
    22 
    2329from sage.structure.sequence import Sequence
    24 
    25 from sage.structure.element import MultiplicativeGroupElement
     30from sage.structure.element import MonoidElement
     31from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement
     32from sage.groups.group import Group
    2633
    2734class ClassGroup(AbelianGroup_class):
    28     """
     35    r"""
    2936    The class group of a number field.
    3037    """
    31     def __init__(self, invariants, names, number_field, gens):
    32         """
     38    def __init__(self, invariants, names, number_field, gens, proof=True):
     39        r"""
    3340        Create a class group.
    3441
     42        Note that the error in the test suite below is caused by the fact that
     43        there is no category of additive abelian groups.
     44
    3545        EXAMPLES::
    3646
    3747            sage: K.<a> = NumberField(x^2 + 23)
     
    4151            sage: G.category()
    4252            Category of groups
    4353            sage: TestSuite(G).run() # see #7945
    44             Failure in _test_an_element:
    45               ...
    46             AssertionError: self.an_element() is not in self
     54              Failure in _test_category:
    4755            ...
    48             The following tests failed: _test_an_element, _test_elements, _test_elements_eq, _test_inverse, _test_some_elements
     56            The following tests failed: _test_elements
    4957        """
     58        AbelianGroup_class.__init__(self, len(invariants), invariants, names)
     59        self._proof_flag = proof
    5060        self.__number_field = number_field
    51         self.__gens = Sequence([FractionalIdealClass(x, self) for x in gens], immutable=True,
     61        self.__gens = Sequence([FractionalIdealClass(self, x) for x in gens], immutable=True,
    5262                               universe=self, check=False)
    53         AbelianGroup_class.__init__(self, len(invariants), invariants, names)
    5463
    5564    def __call__(self, *args, **kwds):
     65        r"""
     66        Call method. This exists *purely* to override the old-fashioned
     67        behaviour of the parent AbelianGroup class and ensure that
     68        :meth:`element_constructor` gets called.
     69       
     70        EXAMPLE::
     71       
     72            sage: K.<b> = NumberField(x^2 + 389)
     73            sage: C = K.class_group()
     74            sage: C(K.ideal(b))
     75            Trivial principal fractional ideal class
    5676        """
     77        return Group.__call__(self, *args, **kwds)
     78
     79    def _element_constructor_(self, *args, **kwds):
     80        r"""
     81        Create an element of this class group from the given data. This may be:
     82        an ideal class in this number field; an ideal class in a subfield; or
     83        anything from which an ideal in this number field can be constructed.
    5784
    5885        EXAMPLES::
    5986
    6087            sage: K.<b> = NumberField(x^2 + 389)
    6188            sage: C = K.class_group()
    62             sage: C(K.ideal(b))
     89            sage: C(K.ideal(b)) # indirect doctest
    6390            Trivial principal fractional ideal class
    64             sage: C(K.ideal(59049, b + 35312))
     91            sage: C(K.ideal(59049, b + 35312)) # indirect doctest
    6592            Fractional ideal class (59049, b + 35312)
    66             sage: C((59049, b + 35312))
     93            sage: C((59049, b + 35312)) # indirect doctest
    6794            Fractional ideal class (59049, b + 35312)
    68             sage: C(59049, b + 35312)
     95            sage: C(59049, b + 35312) # indirect doctest
    6996            Fractional ideal class (59049, b + 35312)
     97
     98            sage: K.<a> = QuadraticField(-23)
     99            sage: L.<b> = K.extension(x^2 - 2)
     100            sage: CK = K.class_group()
     101            sage: CL = L.class_group()
     102            sage: [CL(I).list() for I in CK]
     103            [[0], [2], [4]]
    70104        """
    71         return FractionalIdealClass(self.__number_field.ideal(*args, **kwds), self)
    72 
    73     def _coerce_impl(self, x):
    74         """
    75         Canonical coercion of x into this class group.
    76 
    77         EXAMPLES::
    78 
    79        
    80         """
    81         return self(x)
     105        if isinstance(args[0], FractionalIdealClass):
     106            return FractionalIdealClass(self, self.__number_field.ideal(args[0].ideal()))
     107        else:
     108            I = self.__number_field.ideal(*args, **kwds)
     109            if I.is_zero(): raise TypeError, "The zero ideal is not a fractional ideal"
     110            return FractionalIdealClass(self, I)
    82111
    83112    def gens(self):
    84         """
     113        r"""
    85114        Return generators for the class group.
    86115
    87116        EXAMPLES::
     
    93122        return self.__gens
    94123
    95124    def ngens(self):
    96         """
     125        r"""
    97126        Return the number of generators of the class group.
    98127
    99128        EXAMPLES::
     
    103132            sage: C.ngens()
    104133            2
    105134        """
    106         return len(self.__gens)
     135        return len(self.invariants())
    107136
    108137    def gen(self, i=0):
    109         """
     138        r"""
    110139        Return the i-th generator for this class group.
    111140
    112141        EXAMPLES::
    113142
    114143            sage: C = NumberField(x^2 + 120071, 'a').class_group(); C
    115144            Class group of order 500 with structure C250 x C2 of Number Field in a with defining polynomial x^2 + 120071
    116             sage: C.gen(0)
     145            sage: C.gen(0) # random
    117146            Fractional ideal class (130, 1/2*a + 137/2)
    118             sage: C.gen(1)
     147            sage: C.gen(1) # random
    119148            Fractional ideal class (7, a)
    120149        """
    121150        if i < 0 or i >= len(self.__gens):
     
    139168            [Trivial principal fractional ideal class, Fractional ideal class (2, 1/2*a^2 + a - 1/2), Fractional ideal class (2, 1/2*a^2 + 1/2)] # 32-bit
    140169            [Trivial principal fractional ideal class, Fractional ideal class (2, 1/2*a^2 - a + 3/2), Fractional ideal class (2, 1/2*a^2 + 1/2)] # 64-bit
    141170
    142         TESTS:
     171        TESTS::
     172
    143173            sage: K.<a> = NumberField(x^2 + 1)
    144174            sage: G = K.class_group()
    145175            sage: G
     
    148178            [Trivial principal fractional ideal class]
    149179            sage: G.list()
    150180            [Trivial principal fractional ideal class]
    151 
    152             sage: C = NumberField(x^2 + x + 23899, 'a').class_group(); C
    153             Class group of order 68 with structure C34 x C2 of Number Field in a with defining polynomial x^2 + x + 23899
    154             sage: len(list(C.__iter__()))
    155             68
    156181        """
    157182        from sage.misc.mrange import mrange
    158183        invs = self.invariants()
     
    167192            yield self(1)
    168193
    169194    def _repr_(self):
    170         """
     195        r"""
    171196        Return string representation of self.
    172197
    173198        EXAMPLES::
     
    182207            self.number_field())
    183208
    184209    def number_field(self):
    185         """
     210        r"""
    186211        Return the number field that this class group is attached to.
    187212       
    188213        EXAMPLES::
     
    195220        return self.__number_field
    196221
    197222
    198 class FractionalIdealClass(MultiplicativeGroupElement):
    199     """
     223class FractionalIdealClass(AbelianGroupElement):
     224    r"""
    200225    A fractional ideal class in a number field.
    201226   
    202227    EXAMPLES::
     
    205230        Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23
    206231        sage: I = G.0; I
    207232        Fractional ideal class (2, 1/2*a - 1/2)
    208         sage: I*I
    209         Fractional ideal class (2, 1/2*a + 1/2)
    210         sage: I*I*I
    211         Trivial principal fractional ideal class
    212233    """
    213     def __init__(self, ideal, class_group):
     234    def __init__(self, parent, ideal, element=None):
    214235        """
    215236        Returns the ideal class of this fractional ideal.
     237
     238        EXAMPLE::
     239
     240            sage: K.<a> = NumberField(x^2 + 23,'a'); G = K.class_group()
     241            sage: G(K.ideal(13, a + 4))
     242            Fractional ideal class (13, a + 4)
    216243        """
    217244        self.__ideal = ideal
    218         MultiplicativeGroupElement.__init__(self, class_group)
     245        if element is None:
     246            element = ideal._ideal_class_log(proof = parent._proof_flag)
     247        AbelianGroupElement.__init__(self, parent, element)
    219248
    220249    def _repr_(self):
    221         """
     250        r"""
    222251        Return string representation of this fractional ideal class.
     252
     253         EXAMPLE::
     254
     255            sage: K.<a> = NumberField(x^2 + 23,'a'); G = K.class_group()
     256            sage: G(K.ideal(13, a + 4))._repr_()
     257            'Fractional ideal class (13, a + 4)'
     258            sage: G(K.ideal(59, a+6))._repr_()
     259            'Trivial principal fractional ideal class'
    223260        """
    224261        if self.is_principal():
    225             return 'Trivial principal fractional ideal class' #%self.__ideal.number_field()
    226         return 'Fractional ideal class %s'%self.__ideal._repr_short() #, self.__ideal.number_field())
    227 
    228     def __cmp__(self, other):
    229         q = self.__ideal / other.__ideal
    230         if q.is_principal():
    231             return 0
    232         return cmp(self.__ideal, other.__ideal)
     262            return 'Trivial principal fractional ideal class'
     263        return 'Fractional ideal class %s'%self.__ideal._repr_short()
    233264
    234265    def _mul_(self, other):
    235         return self.parent()((self.__ideal * other.__ideal).reduce_equiv())
     266        r"""
     267        Multiplication of two ideal classes.
     268
     269        EXAMPLE::
     270
     271            sage: G = NumberField(x^2 + 23,'a').class_group(); G
     272            Class group of order 3 with structure C3 of Number Field in a with defining polynomial x^2 + 23
     273            sage: I = G.0; I
     274            Fractional ideal class (2, 1/2*a - 1/2)
     275            sage: I*I # indirect doctest
     276            Fractional ideal class (2, 1/2*a + 1/2)
     277            sage: I*I*I # indirect doctest
     278            Trivial principal fractional ideal class
     279        """
     280        m = AbelianGroupElement._mul_(self, other)
     281        return FractionalIdealClass(self.parent(), (self.__ideal * other.__ideal).reduce_equiv(), m.list())
     282
     283    def __pow__(self, n):
     284        r"""
     285        Raise this element to the power n.
     286       
     287        EXAMPLE::
     288       
     289            sage: K.<a> = NumberField(x^3 - 3*x + 8)
     290            sage: C=K.class_group()
     291            sage: c = C(2, a)
     292            sage: c^2
     293            Fractional ideal class (2, a^2 + 2*a - 1)
     294            sage: c^3
     295            Trivial principal fractional ideal class
     296            sage: c^1000
     297            Fractional ideal class (2, a)
     298        """
     299        # We use MonoidElement's __pow__ routine, since that does
     300        # repeated squaring, and hence the ideal gets reduced as
     301        # we go along; actually computing self.__ideal ** n would
     302        # be disastrous.
     303        n = n % self.order()
     304        return MonoidElement.__pow__(self, n)
     305
     306    def inverse(self):
     307        r"""
     308        Return the multiplicative inverse of this ideal class.
     309       
     310        EXAMPLE::
     311       
     312            sage: K.<a> = NumberField(x^3 - 3*x + 8); G = K.class_group()
     313            sage: G(2, a).inverse()
     314            Fractional ideal class (2, a^2 + 2*a - 1)
     315        """
     316        m = AbelianGroupElement.inverse(self)
     317        return FractionalIdealClass(self.parent(), (~self.__ideal).reduce_equiv(), m.list())
     318
     319    def __invert__(self):
     320        r"""
     321        Return the multiplicative inverse of this ideal class.
     322       
     323        EXAMPLE::
     324       
     325            sage: K.<a> = NumberField(x^3 - 3*x + 8); G = K.class_group()
     326            sage: ~G(2, a)
     327            Fractional ideal class (2, a^2 + 2*a - 1)
     328        """
     329        return self.inverse()
    236330
    237331    def is_principal(self):
    238         """
     332        r"""
    239333        Returns True iff this ideal class is the trivial (principal) class
    240334
    241335        EXAMPLES::
     
    252346            sage: (c^3).is_principal()
    253347            True
    254348        """
    255         return self.__ideal.is_principal()
     349        return self.is_one()
    256350
    257351    def reduce(self):
    258         """
     352        r"""
    259353        Return representative for this ideal class that has been
    260354        reduced using PARI's idealred.
    261355       
     
    273367        return self.parent()(self.__ideal.reduce_equiv())
    274368
    275369    def order(self):
    276         """
     370        r"""
    277371        Return the order of this ideal class in the class group.
    278372
    279373        EXAMPLE::
     
    295389            [38, 2]
    296390
    297391        """
    298         try:
    299             return self.__multiplicative_order
    300         except AttributeError:
    301             from sage.groups.generic import order_from_multiple
    302             self.__multiplicative_order = order_from_multiple(self,self.parent().order(),operation='*')
    303             return self.__multiplicative_order
     392        # an old method with a new docstring
     393        return AbelianGroupElement.order(self)
    304394
    305     multiplicative_order = order
    306    
     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()
     406
    307407    def ideal(self):
    308         """
     408        r"""
    309409        Return a representative ideal in this ideal class.
    310410
    311411        EXAMPLE::
     
    322422        return self.__ideal
    323423
    324424    def gens(self):
    325         """
     425        r"""
    326426        Return generators for a representative ideal in this
    327427        ideal class.
    328428
  • sage/rings/number_field/number_field.py

    diff -r 8dec8b43ccca -r 9d33ffed40c7 sage/rings/number_field/number_field.py
    a b  
    26012601        # Next gens is a list of ideals.
    26022602        gens = [self.ideal([self(convert_from_zk_basis(self, y)) for y in x]) for x in gens]
    26032603       
    2604         G = ClassGroup(cycle_structure, names, self, gens)       
     2604        G = ClassGroup(cycle_structure, names, self, gens, proof=proof)       
    26052605        self.__class_group[proof,names] = G
    26062606        return G
    26072607
  • sage/rings/number_field/number_field_ideal.py

    diff -r 8dec8b43ccca -r 9d33ffed40c7 sage/rings/number_field/number_field_ideal.py
    a b  
    840840                self.__reduced_generators = tuple([g])
    841841            return self.__is_principal
    842842
     843    def _ideal_class_log(self, proof=None):
     844        r"""
     845        Return the output of Pari's 'bnfisprincipal' for this ideal,
     846        i.e. a vector expressing the class of this ideal in terms of a
     847        set of generators for the class group.
     848         
     849        EXAMPLE::
     850         
     851            sage: K.<a, b> = NumberField([x^3 - x + 1, x^2 + 26])
     852            sage: K.primes_above(7)[0]._ideal_class_log() # random
     853            [1, 2]
     854        """
     855        proof = get_flag(proof, "number_field")
     856        try:
     857            return self.__ideal_class_log[proof]
     858        except AttributeError:
     859            self.__ideal_class_log = {}
     860            return self._ideal_class_log(proof)
     861        except KeyError:
     862            bnf = self.number_field().pari_bnf(proof)
     863            v = bnf.bnfisprincipal(self.pari_hnf())
     864            self.__ideal_class_log[proof] = list(v[0])
     865            return self.__ideal_class_log[proof]
     866
    843867    def is_zero(self):
    844868        """
    845869        Return True iff self is the zero ideal