Ticket #8335: trac_8335-finite_field_coerce-5.7.b4.patch

File trac_8335-finite_field_coerce-5.7.b4.patch, 23.5 KB (added by jpflori, 9 years ago)
  • sage/categories/pushout.py

    # HG changeset patch
    # User David Roe <roed@math.harvard.edu>
    # Date 1266946333 18000
    # Node ID 4cbd00666457bacdfc6afaec73bad96ad83d2e05
    # Parent  cf291487ba675ef650010e9bdef907bc9853a4fa
    8335: Modifies _coerce_map_from_ for finite fields and AlgebraicExtensionFunctor in pushout to allow for coercion within lattices of finite fields defined by Conway and pseudo-Conway polynomials.  Defines a subfields() method on finite fields analogous to the one on number fields.
    
    diff --git a/sage/categories/pushout.py b/sage/categories/pushout.py
    a b  
    24932493    """
    24942494    rank = 3
    24952495   
    2496     def __init__(self, polys, names, embeddings, cyclotomic=None):
     2496    def __init__(self, polys, names, embeddings, cyclotomic=None, prefix=None):
    24972497        """
    24982498        INPUT:
    24992499
    2500         - ``polys``: a list of polynomials
     2500        - ``polys``: a list of polynomials (or of integers, for
     2501          finite fields and unramified local extensions)
    25012502        - ``names``: a list of strings of the same length as the
    25022503          list ``polys``
    25032504        - ``embeddings``: a list of approximate complex values,
     
    25072508        - ``cyclotomic``: optional integer. If it is provided,
    25082509          application of the functor to the rational field yields
    25092510          a cyclotomic field, rather than just a number field.
     2511        - ``prefix``: optional string.  If it is provided, it will
     2512          allow application of this functor to some finite fields to
     2513          function without providing a variable name
    25102514
    25112515        REMARK:
    25122516
     
    25712575        self.names = list(names)
    25722576        self.embeddings = list(embeddings)
    25732577        self.cyclotomic = int(cyclotomic) if cyclotomic is not None else None
     2578        self.prefix = prefix
    25742579
    25752580    def _apply_functor(self, R):
    25762581        """
     
    25882593            Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000
    25892594        """
    25902595        from sage.all import QQ, ZZ, CyclotomicField
     2596        from sage.rings.finite_rings.finite_field_base import is_FiniteField
    25912597        if self.cyclotomic:
    25922598            if R==QQ:
    25932599                return CyclotomicField(self.cyclotomic)
    25942600            if R==ZZ:
    25952601                return CyclotomicField(self.cyclotomic).maximal_order()
    25962602        if len(self.polys) == 1:
    2597             return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0])
     2603            if is_FiniteField(R):
     2604                return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0], prefix=self.prefix)
     2605            else:
     2606                return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0])
    25982607        return R.extension(self.polys, self.names, embedding=self.embeddings)
    25992608
    26002609    def __cmp__(self, other):
     
    26332642          associated with the pushout of the codomains
    26342643          of the two embeddings is returned, provided that
    26352644          it is a number field.
     2645        - If these two extensions are defined by Conway polynomials over finite fields
     2646          (indicated by the fact that their ``poly`` fields are just integers),
     2647          merges them into a single extension of degree the product of the two degrees.
    26362648        - Otherwise, None is returned.
    26372649         
    26382650        REMARK:
     
    26442656
    26452657        TESTS::
    26462658
     2659            sage: k = GF(3^3)
     2660            sage: l = GF(3^2)
     2661            sage: k.gen() + l.gen() # indirect doctest
     2662            z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 1
    26472663            sage: P.<x> = QQ[]
    26482664            sage: L.<b> = NumberField(x^8-x^4+1, embedding=CDF.0)
    26492665            sage: M1.<c1> = NumberField(x^2+x+1, embedding=b^4-1)
     
    26732689            CoercionException: ('Ambiguous Base Extension', Number Field in a with defining polynomial x^3 - 2, Number Field in b with defining polynomial x^6 - 2)
    26742690
    26752691        """
    2676         if not isinstance(other,AlgebraicExtensionFunctor):
     2692        if isinstance(other, AlgebraicClosureFunctor):
     2693            return other
     2694        elif not isinstance(other,AlgebraicExtensionFunctor):
    26772695            return None
    26782696        if self == other:
    26792697            return self
     
    26932711#                return self
    26942712#            if  other.embeddings==[None]:
    26952713#                return other
    2696         # ... or we may use the given embeddings:
     2714        # ... or we may use the given embeddings
     2715        from sage.rings.integer import Integer
     2716        # finite fields use an integer to encode the pseudo-Conway extension that allows pushouts
     2717        if isinstance(self.polys[0], Integer) and isinstance(other.polys[0], Integer) and self.prefix is not None and self.prefix == other.prefix:
     2718            if self.embeddings != [None] or other.embeddings != [None]:
     2719                raise NotImplementedError
     2720            return AlgebraicExtensionFunctor([self.polys[0]*other.polys[0]],[None],[None],prefix=self.prefix)
    26972721        if self.embeddings!=[None] and other.embeddings!=[None]:
    26982722            from sage.all import QQ
    26992723            KS = self(QQ)
  • sage/rings/finite_rings/constructor.py

    diff --git a/sage/rings/finite_rings/constructor.py b/sage/rings/finite_rings/constructor.py
    a b  
    724724        sage: from sage.rings.finite_rings.constructor import find_pseudo_conway_polynomial_tree
    725725        sage: PCPT = find_pseudo_conway_polynomial_tree(2, 12, False)
    726726        sage: PCPT.f
    727         x^12 + x^8 + x^7 + x^6 + x^4 + x^3 + 1
     727        x^12 + x^10 + x^9 + x^8 + x^4 + x^2 + 1
    728728    """
    729729    if not pseudo_conway_poly.has_key(p):
    730730        pseudo_conway_poly[p] = {}
  • sage/rings/finite_rings/element_ntl_gf2e.pyx

    diff --git a/sage/rings/finite_rings/element_ntl_gf2e.pyx b/sage/rings/finite_rings/element_ntl_gf2e.pyx
    a b  
    10941094            sage: g = K.random_element()
    10951095            sage: g.minpoly()(g)
    10961096            0
     1097
     1098        We check that the NTL modulus is restored properly::
     1099
     1100            sage: k.<a> = GF(2^1000)
     1101            sage: b = a^(k.order()//(2^20-1))
     1102            sage: l.<c> = GF(2^20)
     1103            sage: b.minpoly()
     1104            x^20 + x^17 + x^16 + x^14 + x^13 + x^11 + x^8 + x^7 + x^3 + x + 1
    10971105        """
    10981106        (<Cache_ntl_gf2e>self._parent._cache).F.restore()
    10991107        cdef GF2X_c r = GF2X_IrredPolyMod(GF2E_rep(self.x), GF2E_modulus())
  • sage/rings/finite_rings/finite_field_base.pyx

    diff --git a/sage/rings/finite_rings/finite_field_base.pyx b/sage/rings/finite_rings/finite_field_base.pyx
    a b  
    322322            ...
    323323            TypeError: images do not define a valid homomorphism           
    324324        """
    325 
    326325        if (self.characteristic() != codomain.characteristic()):
    327326            raise ValueError, "no map from %s to %s"%(self, codomain)
    328327        if (len(im_gens) != 1):
     
    747746        """
    748747        return hash("GF") + hash(self.order())
    749748
     749    def construction(self):
     750        """
     751        Returns the construction of this finite field, as a ConstructionFunctor and the base field.
     752
     753        EXAMPLES::
     754       
     755            sage: v = GF(3^3).construction(); v
     756            (AlgebraicExtensionFunctor, Finite Field of size 3)
     757            sage: v[0].polys[0]
     758            3
     759            sage: v = GF(2^1000,'a').construction(); v[0].polys[0]
     760            a^1000 + a^5 + a^4 + a^3 + 1
     761        """
     762        from sage.categories.pushout import AlgebraicExtensionFunctor
     763        if self.degree() == 1:
     764            # this is not of type FiniteField_prime_modn
     765            from sage.rings.integer import Integer
     766            return AlgebraicExtensionFunctor([Integer(1)], [None],[None]), self.base_ring()
     767        elif hasattr(self, '_PCPT') and self._PCPT is not None:
     768            return AlgebraicExtensionFunctor([self.degree()], [self.variable_name()],[None],prefix=self._prefix), self.base_ring()
     769        else:
     770            return AlgebraicExtensionFunctor([self.polynomial()], [self.variable_name()],[None]), self.base_ring()
     771
     772    def extension(self, modulus, name=None, names=None, embedding=None, prefix='z'):
     773        """
     774        Returns an extension of this finite field.
     775
     776        INPUT::
     777
     778        - modulus -- either a polynomial with coefficients in this field or an integer. 
     779                     If an integer, returns the pseudo-Conway extension of this field of that degree.
     780        - name -- the name of the generator in the new extension
     781        - embedding -- currently not used; for compatibility with other AlgebraicExtensionFunctor calls.
     782        - prefix -- Passed on to the finite field constructor.  See the documentation of
     783                    ``GF`` in ``sage.rings.finite_rings.constructor``
     784
     785        OUTPUT::
     786       
     787        An extension of the given modulus, or pseudo-Conway of the given degree if the modulus is just an integer.
     788       
     789        EXAMPLES::
     790
     791            sage: k = GF(3^4)
     792            sage: k.extension(3)
     793            Finite Field in z12 of size 3^12
     794            sage: R.<x> = GF(2)[]
     795            sage: GF(2).extension(x^1000 + x^5 + x^4 + x^3 + 1,'a')
     796            Finite Field in a of size 2^1000
     797            sage: R.<x> = GF(3)[]
     798
     799        Extensions of non-prime finite fields by polynomials are not yet supported: we fall back to generic code.
     800
     801            sage: k.extension(x^5 + x^2 + x - 1)
     802            Univariate Quotient Polynomial Ring in x over Finite Field in z4 of size 3^4 with modulus x^5 + x^2 + x + 2
     803        """
     804        from constructor import GF
     805        from sage.rings.integer import Integer
     806        from sage.rings.polynomial.all import is_Polynomial
     807        if name is None and names is not None:
     808            name = names
     809        if self.degree() == 1:
     810            if isinstance(modulus, Integer):
     811                return GF(self.characteristic()**modulus, modulus='conway', name=name, prefix=prefix)
     812            if isinstance(modulus, (list, tuple)):
     813                return GF(self.characteristic()**(len(modulus) - 1), name=name, modulus=modulus, prefix=prefix)
     814            elif is_Polynomial(modulus):
     815                if modulus.change_ring(self).is_irreducible():
     816                    return GF(self.characteristic()**(modulus.degree()), name=name, modulus=modulus, prefix=prefix)
     817                else:
     818                    return Field.extension(self, modulus, name=name, embedding=embedding)
     819        elif isinstance(modulus, Integer):
     820            if hasattr(self, '_PCPT') and self._PCPT is not None:
     821                return GF(self.order()**modulus, name=name, prefix=prefix)
     822        return Field.extension(self, modulus, name=name, embedding=embedding)
     823
     824    def subfields(self, degree=0, name=None):
     825        """
     826        Return all proper subfields of self of the given degree,
     827        or of all possible degrees if degree is 0. 
     828
     829        The subfields are returned as
     830        absolute fields together with an embedding into self.
     831
     832        INPUT::
     833
     834        - degree -- (default 0) An integer.
     835        - name -- A string, a dictionary or None.
     836                  If degree is nonzero, name must be a string (or None, if this is a pseudo-Conway extension), and will be the variable name of the returned field.
     837                  If degree is zero, the dictionary should have keys the divisors of the degree of this field, with the desired variable name for the field of that degree as an entry.
     838                  As a shortcut, you can provide a string and the degree of each subfield will be appended for the variable name of that subfield.
     839                  If None, uses the prefix of this field.
     840   
     841        OUTPUT::
     842
     843        A list of pairs (K, e), where K ranges over the subfields of this field and e gives an embedding of K into this field.
     844
     845        EXAMPLES::
     846
     847            sage: k.<a> = GF(2^21)
     848            sage: k.subfields()
     849            [(Finite Field of size 2,
     850              Conversion map:
     851                  From: Finite Field of size 2
     852                  To:   Finite Field in a of size 2^21),
     853             (Finite Field in z3 of size 2^3,
     854              Ring morphism:
     855                  From: Finite Field in z3 of size 2^3
     856                  To:   Finite Field in a of size 2^21
     857                  Defn: z3 |--> a^20 + a^19 + a^17 + a^15 + a^11 + a^9 + a^8 + a^6 + a^2),
     858             (Finite Field in z7 of size 2^7,
     859              Ring morphism:
     860                  From: Finite Field in z7 of size 2^7
     861                  To:   Finite Field in a of size 2^21
     862                  Defn: z7 |--> a^20 + a^19 + a^17 + a^15 + a^14 + a^6 + a^4 + a^3 + a)]
     863        """
     864        from sage.rings.integer import Integer
     865        from constructor import GF
     866        p = self.characteristic()
     867        if degree != 0:
     868            degree = Integer(degree)
     869            if degree.divides(self.degree()):
     870                if hasattr(self, '_PCPT') and self._PCPT is not None:
     871                    K = GF(p**degree, name=name, prefix=self._prefix)
     872                    return [K, self.coerce_map_from(K)]
     873                elif degree == 1:
     874                    K = GF(p)
     875                    return [K, self.coerce_map_from(K)]
     876                else:
     877                    deg_gen = self.multiplicative_generator()**((self.order() - 1)//(p**degree-1))
     878                    from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     879                    K = GF(p**degree, modulus=deg_gen.minimal_polynomial(), name=name, prefix=self._prefix)
     880                    return [K, FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(K, self), deg_gen)]
     881            else:
     882                return []
     883        if hasattr(self, '_PCPT') and self._PCPT is not None:
     884            if name is None:
     885                name = self._prefix
     886        else:
     887            if isinstance(name, str):
     888                prefix = name
     889                name = {}
     890            else:
     891                if self._prefix is None:
     892                    prefix = self.variable_name()
     893                else:
     894                    prefix = self._prefix
     895                if name is None:
     896                    name = {}
     897                elif not isinstance(name, dict):
     898                    raise ValueError, "name must be None, a string or a dictionary indexed by divisors of the degree"
     899            for m in self.degree().divisors():
     900                name[m] = prefix + str(m)
     901        ans = []
     902        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     903        for m in self.degree().divisors():
     904            if m == self.degree(): continue
     905            if hasattr(self, '_PCPT') and self._PCPT is not None:
     906                K = GF(p**m, prefix=name)
     907                ans.append((K, self.coerce_map_from(K)))
     908            elif m == 1:
     909                ans.append((GF(p), self.coerce_map_from(K)))
     910            else:
     911                deg_gen = self.multiplicative_generator()**((self.order() - 1)//(p**m-1))
     912                K = GF(p**m, modulus=deg_gen.minimal_polynomial(), name=name[m])
     913                print K
     914                ans.append((K, FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(K, self), deg_gen)))
     915        return ans
     916
    750917    def algebraic_closure(self):
    751918        """
    752919        Return the algebraic closure of ``self`` (not implemented).
  • sage/rings/finite_rings/finite_field_ext_pari.py

    diff --git a/sage/rings/finite_rings/finite_field_ext_pari.py b/sage/rings/finite_rings/finite_field_ext_pari.py
    a b  
    590590            ...
    591591            TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^3
    592592            sage: FiniteField_ext_pari(16,'a')._coerce_(FiniteField_ext_pari(4,'a').0)
    593             Traceback (most recent call last):
    594             ...
    595             TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^4
     593            a^2 + a
    596594            sage: k = FiniteField_ext_pari(8,'a')
    597595            sage: k._coerce_(FiniteField(7,'a')(2))
    598596            Traceback (most recent call last):
     
    600598            TypeError: no canonical coercion from Finite Field of size 7 to Finite Field in a of size 2^3
    601599        """
    602600        from sage.rings.integer_ring import ZZ
     601        from sage.rings.finite_rings.finite_field_base import is_FiniteField
    603602        from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic
    604603        if R is int or R is long or R is ZZ:
    605604            return True
    606         if isinstance(R, FiniteField_ext_pari):
     605        if is_FiniteField(R):
    607606            if R is self:
    608607                return True
     608            from sage.rings.residue_field import ResidueField_generic
     609            if isinstance(R, ResidueField_generic):
     610                return False
    609611            if R.characteristic() == self.characteristic():
     612                if isinstance(R, IntegerModRing_generic):
     613                    return True
    610614                if R.degree() == 1:
    611615                    return True
    612                 elif self.degree() % R.degree() == 0:
    613                     # TODO: This is where we *would* do coercion from one nontrivial finite field to another...
    614                     return False               
    615         from sage.rings.residue_field import ResidueField_generic
    616         if isinstance(R, IntegerModRing_generic) and R.characteristic() == self.characteristic() and not isinstance(R, ResidueField_generic):
    617             return True
     616                if self.degree() % R.degree() == 0:
     617                    if hasattr(self, '_PCPT') and hasattr(R, '_PCPT') and R._PCPT is not None:
     618                        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     619                        return FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(R, self), self.gen()**((self.order()-1)//(R.order()-1)))
    618620
    619621    def __len__(self):
    620622        """
  • sage/rings/finite_rings/finite_field_givaro.py

    diff --git a/sage/rings/finite_rings/finite_field_givaro.py b/sage/rings/finite_rings/finite_field_givaro.py
    a b  
    352352            sage: F9 = FiniteField_givaro(9)
    353353            sage: F81 = FiniteField_givaro(81)
    354354            sage: F81(F9.gen())
    355             Traceback (most recent call last):
    356             ...
    357             TypeError: unable to coerce from a finite field other than the prime subfield
     355            2*a^3 + 2*a^2 + 1
    358356        """
    359357        return self._cache.element_from_data(e)
    360358
     
    388386                    return True
    389387                if R.degree() == 1:
    390388                    return True
    391                 elif self.degree() % R.degree() == 0:
    392                     # This is where we *would* do coercion from one nontrivial finite field to another...
    393                     # We use this error message for backward compatibility until #8335 is finished
    394                     raise TypeError, "unable to coerce from a finite field other than the prime subfield"
     389                if self.degree() % R.degree() == 0:
     390                    if hasattr(self, '_PCPT') and hasattr(R, '_PCPT') and R._PCPT is not None:
     391                        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     392                        return FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(R, self), self.gen()**((self.order()-1)//(R.order()-1)))
    395393
    396394    def gen(self, n=0):
    397395        r"""
  • sage/rings/finite_rings/finite_field_ntl_gf2e.py

    diff --git a/sage/rings/finite_rings/finite_field_ntl_gf2e.py b/sage/rings/finite_rings/finite_field_ntl_gf2e.py
    a b  
    266266                return True
    267267            if isinstance(R, ResidueField_generic):
    268268                return False
    269             if isinstance(R, IntegerModRing_generic) and R.characteristic() % 2 == 0:
    270                 return True
    271269            if R.characteristic() == 2:
     270                if isinstance(R, IntegerModRing_generic):
     271                    return True
    272272                if R.degree() == 1:
    273273                    return True
    274274                elif self.degree() % R.degree() == 0:
    275                     # This is where we *would* do coercion from one nontrivial finite field to another...
    276                     raise NotImplementedError
     275                    if self._PCPT is not None and hasattr(R, '_PCPT') and R._PCPT is not None:
     276                        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     277                        return FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(R, self), self.gen()**((self.order()-1)//(R.order()-1)))
    277278
    278279    def gen(self, ignored=None):
    279280        r"""
  • sage/rings/finite_rings/finite_field_prime_modn.py

    diff --git a/sage/rings/finite_rings/finite_field_prime_modn.py b/sage/rings/finite_rings/finite_field_prime_modn.py
    a b  
    189189        if to_ZZ is not None:
    190190            return integer_mod.Integer_to_IntegerMod(self) * to_ZZ
    191191
     192    def construction(self):
     193        """
     194        Returns the construction of this finite field (for use by sage.categories.pushout)
     195
     196        EXAMPLES::
     197
     198            sage: GF(3).construction()
     199            (QuotientFunctor, Integer Ring)
     200        """
     201        return integer_mod_ring.IntegerModRing_generic.construction(self)
     202
    192203    def characteristic(self):
    193204        r"""
    194205        Return the characteristic of \code{self}.
  • sage/rings/finite_rings/homset.py

    diff --git a/sage/rings/finite_rings/homset.py b/sage/rings/finite_rings/homset.py
    a b  
    4444    """
    4545    Set of homomorphisms with domain a given finite field.
    4646    """
     47#     def __init__(self, R, S, category=None):
     48#         if category is None:
     49#             from sage.categories.finite_fields import FiniteFields
     50#             category = FiniteFields()
     51#         RingHomset_generic.__init__(self, R, S, category)
     52
    4753    def __call__(self, im_gens, check=True):
    4854        """
    4955        Construct the homomorphism defined by ``im_gens``.
  • sage/sets/set.py

    diff --git a/sage/sets/set.py b/sage/sets/set.py
    a b  
    379379            sage: Set(GF(2)) + Set(GF(4,'a'))
    380380            {0, 1, a, a + 1}
    381381            sage: Set(GF(8,'b')) + Set(GF(4,'a'))
    382             {0, 1, b, b + 1, b^2, b^2 + 1, b^2 + b, b^2 + b + 1, a, a + 1, 1, 0}
     382            {0, 1, b, b + 1, b^2, b^2 + 1, b^2 + b, b^2 + b + 1, a, a + 1}
    383383        """
    384384        return self.union(X)
    385385
     
    414414
    415415            sage: X = Set(GF(9,'b')).intersection(Set(GF(27,'c')))
    416416            sage: X
    417             {}
     417            {0, 1, 2}
    418418
    419419            sage: X = Set(GF(9,'b')).intersection(Set(GF(27,'b')))
    420420            sage: X
    421             {}
     421            {0, 1, 2}
    422422        """
    423423        if is_Set(X):
    424424            if self is X:
     
    444444
    445445            sage: X = Set(GF(9,'b')).difference(Set(GF(27,'c')))
    446446            sage: X
    447             {0, 1, 2, b, b + 1, b + 2, 2*b, 2*b + 1, 2*b + 2}
     447            {b, b + 1, b + 2, 2*b, 2*b + 1, 2*b + 2}
    448448
    449449            sage: X = Set(GF(9,'b')).difference(Set(GF(27,'b')))
    450450            sage: X
    451             {0, 1, 2, b, b + 1, b + 2, 2*b, 2*b + 1, 2*b + 2}
     451            {b, b + 1, b + 2, 2*b, 2*b + 1, 2*b + 2}
    452452        """
    453453        if is_Set(X):
    454454            if self is X:
  • sage/structure/factory.pyx

    diff --git a/sage/structure/factory.pyx b/sage/structure/factory.pyx
    a b  
    267267        EXAMPLES::
    268268
    269269            sage: key, _ = GF.create_key_and_extra_args(27, 'k'); key
    270             (27, ('k',), 'conway', None, '{}', 3, 3, True)
     270            (27, ('k',), 'conwayz', None, '{}', 3, 3, True)
    271271            sage: K = GF.create_object(0, key); K
    272272            Finite Field in k of size 3^3
    273273            sage: GF.other_keys(key, K)