Ticket #1183: trac-1138-throughstep4.patch

File trac-1138-throughstep4.patch, 14.3 KB (added by was, 15 years ago)

further work, but still some issues....

  • sage/rings/number_field/number_field_ideal.py

    # HG changeset patch
    # User William Stein <wstein@gmail.com>
    # Date 1196601199 28800
    # Node ID e931e76e1eae8ad28fb7dc7c27362e372a4ffb92
    # Parent  6a7a05ed7b705b22c1e1589fe8263cfc03bb28b1
    work in progress on residue class fields.
    
    diff -r 6a7a05ed7b70 -r e931e76e1eae sage/rings/number_field/number_field_ideal.py
    a b def basis_to_module(B, K): 
    10201020    """
    10211021    V, from_V, to_V = K.absolute_vector_space()
    10221022    M = ZZ**(V.dimension())
    1023     C = [to_V(b) for b in B]
     1023    C = [to_V(K(b.list())) for b in B]
    10241024    return M.span_of_basis(C)
    10251025       
    10261026
    def quotient_char_p(I, p): 
    10971097        raise ValueError, "I must be an integral ideal."
    10981098   
    10991099    K    = I.number_field()
    1100     OK   = K.maximal_order(p)  # really only need a p-maximal order.
     1100    OK   = K.maximal_order()  # will in the long run only really need a p-maximal order.
    11011101    M_OK = OK.free_module()
    11021102    M_I  = I.free_module()
    11031103
  • sage/rings/residue_field.pyx

    diff -r 6a7a05ed7b70 -r e931e76e1eae sage/rings/residue_field.pyx
    a b from sage.rings.finite_field_ext_pari im 
    4949from sage.rings.finite_field_ext_pari import FiniteField_ext_pari
    5050from sage.structure.parent_base import ParentWithBase
    5151
     52from sage.modules.free_module_element import FreeModuleElement
     53
    5254from sage.rings.polynomial.polynomial_ring import PolynomialRing
    5355
    5456residue_field_cache = {}
    def ResidueField(p, names = None, check  
    8890        abar^2 + 3*abar + 4
    8991        sage: k.0^3 - 875
    9092        2
     93
     94    An example where the residue class field is large but of degree 1:
     95        sage: K.<a> = NumberField(x^3-875); P = K.ideal(2007).factor()[0][0]; k = K.residue_field(P); k
     96        Residue field of Fractional ideal (-2/25*a^2 - 2/5*a - 3)
     97        sage: k(a)
     98        168
     99        sage: k(a)^3 - 875
     100        0
     101
     102    In this example, 2 is an inessential discriminant divisor, so divides
     103    the index of ZZ[a] in the maximal order for all a.
     104        sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8); P = K.ideal(2).factor()[0][0]; P
     105        Fractional ideal (1/2*a^2 - 1/2*a + 1)
     106        sage: F = K.residue_field(P); F
     107        Residue field of Fractional ideal (1/2*a^2 - 1/2*a + 1)
     108        sage: F(a)
     109        0
     110        sage: B = K.maximal_order().basis(); B
     111        [1, 1/2*a^2 + 1/2*a, a^2]
     112        sage: F(B[1])
     113        1
     114        sage: F(B[2])
     115        0
     116        sage: F
     117        Residue field of Fractional ideal (1/2*a^2 - 1/2*a + 1)
     118        sage: F.degree()
     119        1
    91120    """
    92121    if isinstance(names, tuple):
    93122        if len(names) > 0:
    def ResidueField(p, names = None, check  
    99128        k = residue_field_cache[key]()
    100129        if k is not None:
    101130            return k
    102     if PY_TYPE_CHECK(p, Integer):
    103         if check and not p.is_prime():
     131    if check:
     132        if not is_NumberFieldIdeal(p):
     133            raise TypeError, "p must be a prime ideal in the ring of integers of a number field."
     134        if not p.is_prime():
    104135            raise ValueError, "p must be prime"
    105         if names is None:
    106             names = 'x'
    107         k = ResidueFiniteField_prime_modn(p, names)
    108     elif is_NumberFieldIdeal(p):
    109         if names is None:
    110             names = '%sbar'%(p.number_field().variable_name())
    111         if check and not p.is_prime():
    112             raise ValueError, "p must be prime"
    113         # Should generalize to allowing residue fields of relative extensions to be extensions of finite fields.
    114         characteristic = p.smallest_integer()
    115136
    116         K = p.number_field()
    117         OK = K.maximal_order() # should change to p.order once this works.
    118        
    119         U, to_vs, to_order = p._p_quotient(characteristic)
    120         k = U.base_ring()
    121         R = PolynomialRing(k, names)
    122         n = p.residue_class_degree()
    123         gen_ok = False
    124         from sage.matrix.constructor import matrix
    125         try:
    126             x = K.gen()
    127             M = matrix(k, n+1, n, [to_vs(x**i).list() for i in range(n+1)]).transpose()
    128             M.echelonize()
    129             if M.rank() == n:
    130                 gen_ok = True
    131                 f = R((-M.column(n)).list() + [1])
    132         except TypeError:
    133             pass
    134         if not gen_ok:
    135             bad = True
    136             for u in U: # using this iterator may not be optimal, we may get a long string of non-generators
    137                 if u:
    138                     x = to_order(u)
    139                     M = matrix(k, n+1, n, [to_vs(x**i).list() for i in range(n+1)]).transpose()
    140                     M.echelonize()
    141                     if M.rank() == n:
    142                         f = R((-M.column(n)).list() + [1])
    143                         bad = False
    144                         break
    145             assert not bad, "error -- didn't find a generator."
    146         if n == 1:
    147             k = ResidueFiniteField_prime_modn(p, names, im_gen = -f[0], intp = p.smallest_integer())
     137    if names is None:
     138        names = '%sbar'%(p.number_field().variable_name())
     139    # Should generalize to allowing residue fields of relative extensions to be extensions of finite fields.
     140    characteristic = p.smallest_integer()
     141
     142    K = p.number_field()
     143    OK = K.maximal_order() # should change to p.order once this works.
     144
     145    U, to_vs, to_order = p._p_quotient(characteristic)
     146    k = U.base_ring()
     147    R = PolynomialRing(k, names)
     148    n = p.residue_class_degree()
     149    gen_ok = False
     150    from sage.matrix.constructor import matrix
     151    try:
     152        x = K.gen()
     153        M = matrix(k, n+1, n, [to_vs(x**i).list() for i in range(n+1)])
     154        W = M.transpose().echelon_form()
     155        if M.rank() == n:
     156            PB = M.matrix_from_rows(range(n))
     157            gen_ok = True
     158            f = R((-W.column(n)).list() + [1])
     159    except TypeError:
     160        pass
     161    if not gen_ok:
     162        bad = True
     163        for u in U: # using this iterator may not be optimal, we may get a long string of non-generators
     164            if u:
     165                x = to_order(u)
     166                M = matrix(k, n+1, n, [to_vs(x**i).list() for i in range(n+1)])
     167                W = M.transpose().echelon_form()
     168                if W.rank() == n:
     169                    f = R((-W.column(n)).list() + [1])
     170                    PB = M.matrix_from_rows(range(n))
     171                    bad = False
     172                    break
     173        assert not bad, "error -- didn't find a generator."
     174    if n == 1:
     175        k = ResidueFiniteField_prime_modn(p, names, im_gen = -f[0], intp = p.smallest_integer())
     176    else:
     177        q = characteristic**(f.degree())
     178        if q < Integer(2)**Integer(16):
     179            k = ResidueFiniteField_givaro(p, q, names, f, characteristic)           
    148180        else:
    149             q = characteristic**(f.degree())
    150             if q < Integer(2)**Integer(16):
    151                 k = ResidueFiniteField_givaro(p, q, names, f, characteristic)           
    152             else:
    153                 k = ResidueFiniteField_ext_pari(p, q, names, f, characteristic)
    154             k.structure = (U, to_vs, to_order)
    155     else: # Add support for primes in other rings later.
    156         raise TypeError, "p must be a prime in the integers or a number field"
     181            k = ResidueFiniteField_ext_pari(p, q, names, f, characteristic)
     182    # end creating field.
     183
     184    # The reduction map is just x |--> k(to_vs(x) * (PB**(-1)))
     185    # The lifting map is just x |--> to_order(x * PB)
     186    pi = ReductionMap(K, k, to_vs, PB**(-1))
     187    lift = LiftingMap(K, k, to_order, PB)
     188    k._structure = (pi, lift)
     189               
    157190    residue_field_cache[key] = weakref.ref(k)
    158191    return k
    159192
    class ResidueField_generic(Field): 
    232265                return -1
    233266        return cmp(type(self), type(x))
    234267
     268class ReductionMap:
     269    def __init__(self, K, F, to_vs, PBinv):
     270        self.__K = K
     271        self.__F = F   # finite field
     272        self.__to_vs = to_vs
     273        self.__PBinv = PBinv
     274
     275    def __call__(self, x):
     276        # The reduction map is just x |--> F(to_vs(x) * (PB**(-1)))
     277        x = self.__K(x)
     278        return self.__F(self.__to_vs(x) * self.__PBinv)
     279
     280    def __repr__(self):
     281        return "Partially defined reduction map from %s to %s"%(self.__K, self.__F)
     282
     283class LiftingMap:
     284    def __init__(self, K, F, to_order, PB):
     285        self.__K = K
     286        self.__F = F   # finite field
     287        self.__to_order = to_order
     288        self.__PB = PB
     289
     290    def __call__(self, x):
     291        # The lifting map is just x |--> to_order(x * PB)
     292        x = self.__F(x)
     293        v = x.polynomial().padded_list(self.__F.degree())
     294        return self.__to_order(self.__PB.linear_combination_of_rows(v))
     295
     296    def __repr__(self):
     297        return "Lifting map from %s to %s"%(self.__F, self.__K)
     298
    235299cdef class NFResidueFieldHomomorphism(ResidueFieldHomomorphism):
    236300    """
    237301    The class representing a homomorphism from the order of a number
    cdef class NFResidueFieldHomomorphism(Re 
    275339           
    276340        """
    277341        self.im_gen = im_gen
    278         self.p = p
     342        self.p = p 
    279343        ResidueFieldHomomorphism.__init__(self,Hom(p.number_field().maximal_order(), k, Rings())) # should eventually change to p.order()
    280344
    281345    cdef Element _call_c_impl(self, Element x):
    cdef class NFResidueFieldHomomorphism(Re 
    290354            sage: k.coerce_map_from(OK)(OK(a)^7)
    291355            13*abar^2 + 7*abar + 21
    292356        """
    293         y = x.polynomial().change_ring(self.codomain().base_ring())(self.im_gen)  #polynomial should change to absolute_polynomial?
     357        #y = x.polynomial().change_ring(self.codomain().base_ring())(self.im_gen)  #polynomial should change to absolute_polynomial?
     358        y = self.codomain()(x)
    294359        (<Element>y)._set_parent_c(self.codomain())
    295360        return y       
    296361
    cdef class NFResidueFieldHomomorphism(Re 
    302367        EXAMPLES:
    303368            sage: K.<a> = NumberField(x^3-7)
    304369            sage: P = K.ideal(29).factor()[0][0]
    305             sage: k =K.residue_field(P)
     370            sage: k = K.residue_field(P)
    306371            sage: OK = K.maximal_order()
    307372            sage: f = k.coerce_map_from(OK)
    308373            sage: c = OK(a)
    cdef class NFResidueFieldHomomorphism(Re 
    314379        """
    315380        if self.domain() is ZZ:
    316381            return x.lift()
    317         return self.domain()(x.polynomial().change_ring(self.domain().base_ring())(self.domain().ring_generators()[0]))  #polynomial should change to absolute_polynomial?
     382        else:
     383            return self.codomain()._structure[1](x)
     384           
     385        # return self.domain()(x.polynomial().change_ring(self.domain().base_ring())(self.domain().ring_generators()[0]))  #polynomial should change to absolute_polynomial?
    318386       
    319387
    320388class ResidueFiniteField_prime_modn(ResidueField_generic, FiniteField_prime_modn):
    class ResidueFiniteField_prime_modn(Resi 
    345413    def __init__(self, p, name, im_gen = None, intp = None):
    346414        """
    347415        INPUT:
    348            p -- An integral prime or a prime ideal of a number field.
     416           p -- A prime ideal of a number field.
    349417           name -- the name of the generator of this extension
    350418           im_gen -- the image of the generator of the number field in this finite field.
    351419           intp -- the rational prime that p lies over.
    class ResidueFiniteField_prime_modn(Resi 
    383451            16
    384452        """
    385453        try:
    386             return self.coerce_map_from(self.f.domain())(self.f.domain()(x))
    387         except (AttributeError, TypeError):
    388454            return FiniteField_prime_modn.__call__(self, x)
     455        except TypeError:
     456            if isinstance(x, FreeModuleElement):
     457                return FiniteField_prime_modn.__call__(self, x[0])
     458            else:
     459                return self._structure[0](x)
     460        #try:
     461        #    return self.coerce_map_from(self.f.domain())(self.f.domain()(x))
     462        #except (AttributeError, TypeError):
     463        #    return FiniteField_prime_modn.__call__(self, x)
    389464
    390465class ResidueFiniteField_ext_pari(ResidueField_generic, FiniteField_ext_pari):
    391466    """
    class ResidueFiniteField_ext_pari(Residu 
    394469    EXAMPLES:
    395470        sage: K.<a> = NumberField(x^3-7)
    396471        sage: P = K.ideal(923478923).factor()[0][0]
    397         sage: k =K.residue_field(P)
     472        sage: k = K.residue_field(P)
    398473        sage: k.degree()
    399474        2
    400475        sage: OK = K.maximal_order()
    class ResidueFiniteField_ext_pari(Residu 
    437512            6677
    438513        """
    439514        try:
    440             return self.coerce_map_from(self.f.domain())(self.f.domain()(x))
    441         except (AttributeError, TypeError):
    442515            return FiniteField_ext_pari.__call__(self, x)
     516        except TypeError:
     517            return self._structure[0](x)
     518        #try:
     519        #    return self.coerce_map_from(self.f.domain())(self.f.domain()(x))
     520        #except (AttributeError, TypeError):
     521        #    return FiniteField_ext_pari.__call__(self, x)
    443522
    444523class ResidueFiniteField_givaro(ResidueField_generic, FiniteField_givaro):
    445524    """
    class ResidueFiniteField_givaro(ResidueF 
    473552            sage: R.<x> = QQ[]
    474553            sage: K.<a> = NumberField(x^4+3*x^2-17)
    475554            sage: P = K.ideal(61).factor()[0][0]
    476             sage: k =K.residue_field(P)
     555            sage: k = K.residue_field(P)
    477556        """
    478557        FiniteField_givaro.__init__(self, q, name, g)
    479558        self.f = NFResidueFieldHomomorphism(self, p, GF(q, name = name, modulus = g).gen(0))
    class ResidueFiniteField_givaro(ResidueF 
    493572            2*abar + 4
    494573        """
    495574        try:
    496             return self.coerce_map_from(self.f.domain())(self.f.domain()(x))
    497         except (AttributeError, TypeError):
    498575            return FiniteField_givaro.__call__(self, x)
     576        except TypeError:
     577            try:
     578                return self._structure[0](x)
     579            except:
     580                raise TypeError
    499581
     582        #try:
     583        #    return self.coerce_map_from(self.f.domain())(self.f.domain()(x))
     584        #except (AttributeError, TypeError):
     585        #    return FiniteField_givaro.__call__(self, x)
     586
     587
  • setup.py

    diff -r 6a7a05ed7b70 -r e931e76e1eae setup.py
    a b def cython(ext_modules): 
    10561056
    10571057if not sdist:
    10581058    cython(ext_modules)
     1059    pass
    10591060
    10601061setup(name        = 'sage',
    10611062