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

File trac_8335-finite_field_coerce-5.7.b3.patch, 23.4 KB (added by jpflori, 9 years ago)

Patch for coercion; rebased on top of 5.7.beta3.

  • sage/categories/pushout.py

    # HG changeset patch
    # User David Roe <roed@math.harvard.edu>
    # Date 1266946333 18000
    # Node ID 5aeb85284566ba65f1fb28f2ad6c6d01501658a6
    # Parent  2230748576bce5e9d0189aa69dd040b9ee7f48aa
    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  
    24872487    """
    24882488    rank = 3
    24892489   
    2490     def __init__(self, polys, names, embeddings, cyclotomic=None):
     2490    def __init__(self, polys, names, embeddings, cyclotomic=None, prefix=None):
    24912491        """
    24922492        INPUT:
    24932493
    2494         - ``polys``: a list of polynomials
     2494        - ``polys``: a list of polynomials (or of integers, for
     2495          finite fields and unramified local extensions)
    24952496        - ``names``: a list of strings of the same length as the
    24962497          list ``polys``
    24972498        - ``embeddings``: a list of approximate complex values,
     
    25012502        - ``cyclotomic``: optional integer. If it is provided,
    25022503          application of the functor to the rational field yields
    25032504          a cyclotomic field, rather than just a number field.
     2505        - ``prefix``: optional string.  If it is provided, it will
     2506          allow application of this functor to some finite fields to
     2507          function without providing a variable name
    25042508
    25052509        REMARK:
    25062510
     
    25652569        self.names = list(names)
    25662570        self.embeddings = list(embeddings)
    25672571        self.cyclotomic = int(cyclotomic) if cyclotomic is not None else None
     2572        self.prefix = prefix
    25682573
    25692574    def _apply_functor(self, R):
    25702575        """
     
    25822587            Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000
    25832588        """
    25842589        from sage.all import QQ, ZZ, CyclotomicField
     2590        from sage.rings.finite_rings.finite_field_base import is_FiniteField
    25852591        if self.cyclotomic:
    25862592            if R==QQ:
    25872593                return CyclotomicField(self.cyclotomic)
    25882594            if R==ZZ:
    25892595                return CyclotomicField(self.cyclotomic).maximal_order()
    25902596        if len(self.polys) == 1:
    2591             return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0])
     2597            if is_FiniteField(R):
     2598                return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0], prefix=self.prefix)
     2599            else:
     2600                return R.extension(self.polys[0], self.names[0], embedding=self.embeddings[0])
    25922601        return R.extension(self.polys, self.names, embedding=self.embeddings)
    25932602
    25942603    def __cmp__(self, other):
     
    26272636          associated with the pushout of the codomains
    26282637          of the two embeddings is returned, provided that
    26292638          it is a number field.
     2639        - If these two extensions are defined by Conway polynomials over finite fields
     2640          (indicated by the fact that their ``poly`` fields are just integers),
     2641          merges them into a single extension of degree the product of the two degrees.
    26302642        - Otherwise, None is returned.
    26312643         
    26322644        REMARK:
     
    26382650
    26392651        TESTS::
    26402652
     2653            sage: k = GF(3^3)
     2654            sage: l = GF(3^2)
     2655            sage: k.gen() + l.gen() # indirect doctest
     2656            z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 1
    26412657            sage: P.<x> = QQ[]
    26422658            sage: L.<b> = NumberField(x^8-x^4+1, embedding=CDF.0)
    26432659            sage: M1.<c1> = NumberField(x^2+x+1, embedding=b^4-1)
     
    26672683            CoercionException: ('Ambiguous Base Extension', Number Field in a with defining polynomial x^3 - 2, Number Field in b with defining polynomial x^6 - 2)
    26682684
    26692685        """
    2670         if not isinstance(other,AlgebraicExtensionFunctor):
     2686        if isinstance(other, AlgebraicClosureFunctor):
     2687            return other
     2688        elif not isinstance(other,AlgebraicExtensionFunctor):
    26712689            return None
    26722690        if self == other:
    26732691            return self
     
    26872705#                return self
    26882706#            if  other.embeddings==[None]:
    26892707#                return other
    2690         # ... or we may use the given embeddings:
     2708        # ... or we may use the given embeddings
     2709        from sage.rings.integer import Integer
     2710        # finite fields use an integer to encode the pseudo-Conway extension that allows pushouts
     2711        if isinstance(self.polys[0], Integer) and isinstance(other.polys[0], Integer) and self.prefix is not None and self.prefix == other.prefix:
     2712            if self.embeddings != [None] or other.embeddings != [None]:
     2713                raise NotImplementedError
     2714            return AlgebraicExtensionFunctor([self.polys[0]*other.polys[0]],[None],[None],prefix=self.prefix)
    26912715        if self.embeddings!=[None] and other.embeddings!=[None]:
    26922716            from sage.all import QQ
    26932717            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  
    10781078            sage: g = K.random_element()
    10791079            sage: g.minpoly()(g)
    10801080            0
     1081
     1082        We check that the NTL modulus is restored properly::
     1083
     1084            sage: k.<a> = GF(2^1000)
     1085            sage: b = a^(k.order()//(2^20-1))
     1086            sage: l.<c> = GF(2^20)
     1087            sage: b.minpoly()
     1088            x^20 + x^17 + x^16 + x^14 + x^13 + x^11 + x^8 + x^7 + x^3 + x + 1
    10811089        """
    10821090        (<Cache_ntl_gf2e>self._parent._cache).F.restore()
    10831091        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  
    312312            ...
    313313            TypeError: images do not define a valid homomorphism           
    314314        """
    315 
    316315        if (self.characteristic() != codomain.characteristic()):
    317316            raise ValueError, "no map from %s to %s"%(self, codomain)
    318317        if (len(im_gens) != 1):
     
    738737        """
    739738        return hash("GF") + hash(self.order())
    740739
     740    def construction(self):
     741        """
     742        Returns the construction of this finite field, as a ConstructionFunctor and the base field.
     743
     744        EXAMPLES::
     745       
     746            sage: v = GF(3^3).construction(); v
     747            (AlgebraicExtensionFunctor, Finite Field of size 3)
     748            sage: v[0].polys[0]
     749            3
     750            sage: v = GF(2^1000,'a').construction(); v[0].polys[0]
     751            a^1000 + a^5 + a^4 + a^3 + 1
     752        """
     753        from sage.categories.pushout import AlgebraicExtensionFunctor
     754        if self.degree() == 1:
     755            # this is not of type FiniteField_prime_modn
     756            from sage.rings.integer import Integer
     757            return AlgebraicExtensionFunctor([Integer(1)], [None],[None]), self.base_ring()
     758        elif hasattr(self, '_PCPT') and self._PCPT is not None:
     759            return AlgebraicExtensionFunctor([self.degree()], [self.variable_name()],[None],prefix=self._prefix), self.base_ring()
     760        else:
     761            return AlgebraicExtensionFunctor([self.polynomial()], [self.variable_name()],[None]), self.base_ring()
     762
     763    def extension(self, modulus, name=None, names=None, embedding=None, prefix='z'):
     764        """
     765        Returns an extension of this finite field.
     766
     767        INPUT::
     768
     769        - modulus -- either a polynomial with coefficients in this field or an integer. 
     770                     If an integer, returns the pseudo-Conway extension of this field of that degree.
     771        - name -- the name of the generator in the new extension
     772        - embedding -- currently not used; for compatibility with other AlgebraicExtensionFunctor calls.
     773        - prefix -- Passed on to the finite field constructor.  See the documentation of
     774                    ``GF`` in ``sage.rings.finite_rings.constructor``
     775
     776        OUTPUT::
     777       
     778        An extension of the given modulus, or pseudo-Conway of the given degree if the modulus is just an integer.
     779       
     780        EXAMPLES::
     781
     782            sage: k = GF(3^4)
     783            sage: k.extension(3)
     784            Finite Field in z12 of size 3^12
     785            sage: R.<x> = GF(2)[]
     786            sage: GF(2).extension(x^1000 + x^5 + x^4 + x^3 + 1,'a')
     787            Finite Field in a of size 2^1000
     788            sage: R.<x> = GF(3)[]
     789
     790        Extensions of non-prime finite fields by polynomials are not yet supported: we fall back to generic code.
     791
     792            sage: k.extension(x^5 + x^2 + x - 1)
     793            Univariate Quotient Polynomial Ring in x over Finite Field in z4 of size 3^4 with modulus x^5 + x^2 + x + 2
     794        """
     795        from constructor import GF
     796        from sage.rings.integer import Integer
     797        from sage.rings.polynomial.all import is_Polynomial
     798        if name is None and names is not None:
     799            name = names
     800        if self.degree() == 1:
     801            if isinstance(modulus, Integer):
     802                return GF(self.characteristic()**modulus, modulus='conway', name=name, prefix=prefix)
     803            if isinstance(modulus, (list, tuple)):
     804                return GF(self.characteristic()**(len(modulus) - 1), name=name, modulus=modulus, prefix=prefix)
     805            elif is_Polynomial(modulus):
     806                if modulus.change_ring(self).is_irreducible():
     807                    return GF(self.characteristic()**(modulus.degree()), name=name, modulus=modulus, prefix=prefix)
     808                else:
     809                    return Field.extension(self, modulus, name=name, embedding=embedding)
     810        elif isinstance(modulus, Integer):
     811            if hasattr(self, '_PCPT') and self._PCPT is not None:
     812                return GF(self.order()**modulus, name=name, prefix=prefix)
     813        return Field.extension(self, modulus, name=name, embedding=embedding)
     814
     815    def subfields(self, degree=0, name=None):
     816        """
     817        Return all proper subfields of self of the given degree,
     818        or of all possible degrees if degree is 0. 
     819
     820        The subfields are returned as
     821        absolute fields together with an embedding into self.
     822
     823        INPUT::
     824
     825        - degree -- (default 0) An integer.
     826        - name -- A string, a dictionary or None.
     827                  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.
     828                  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.
     829                  As a shortcut, you can provide a string and the degree of each subfield will be appended for the variable name of that subfield.
     830                  If None, uses the prefix of this field.
     831   
     832        OUTPUT::
     833
     834        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.
     835
     836        EXAMPLES::
     837
     838            sage: k.<a> = GF(2^21)
     839            sage: k.subfields()
     840            [(Finite Field of size 2,
     841              Conversion map:
     842                  From: Finite Field of size 2
     843                  To:   Finite Field in a of size 2^21),
     844             (Finite Field in z3 of size 2^3,
     845              Ring morphism:
     846                  From: Finite Field in z3 of size 2^3
     847                  To:   Finite Field in a of size 2^21
     848                  Defn: z3 |--> a^20 + a^19 + a^17 + a^15 + a^11 + a^9 + a^8 + a^6 + a^2),
     849             (Finite Field in z7 of size 2^7,
     850              Ring morphism:
     851                  From: Finite Field in z7 of size 2^7
     852                  To:   Finite Field in a of size 2^21
     853                  Defn: z7 |--> a^20 + a^19 + a^17 + a^15 + a^14 + a^6 + a^4 + a^3 + a)]
     854        """
     855        from sage.rings.integer import Integer
     856        from constructor import GF
     857        p = self.characteristic()
     858        if degree != 0:
     859            degree = Integer(degree)
     860            if degree.divides(self.degree()):
     861                if hasattr(self, '_PCPT') and self._PCPT is not None:
     862                    K = GF(p**degree, name=name, prefix=self._prefix)
     863                    return [K, self.coerce_map_from(K)]
     864                elif degree == 1:
     865                    K = GF(p)
     866                    return [K, self.coerce_map_from(K)]
     867                else:
     868                    deg_gen = self.multiplicative_generator()**((self.order() - 1)//(p**degree-1))
     869                    from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     870                    K = GF(p**degree, modulus=deg_gen.minimal_polynomial(), name=name, prefix=self._prefix)
     871                    return [K, FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(K, self), deg_gen)]
     872            else:
     873                return []
     874        if hasattr(self, '_PCPT') and self._PCPT is not None:
     875            if name is None:
     876                name = self._prefix
     877        else:
     878            if isinstance(name, str):
     879                prefix = name
     880                name = {}
     881            else:
     882                if self._prefix is None:
     883                    prefix = self.variable_name()
     884                else:
     885                    prefix = self._prefix
     886                if name is None:
     887                    name = {}
     888                elif not isinstance(name, dict):
     889                    raise ValueError, "name must be None, a string or a dictionary indexed by divisors of the degree"
     890            for m in self.degree().divisors():
     891                name[m] = prefix + str(m)
     892        ans = []
     893        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     894        for m in self.degree().divisors():
     895            if m == self.degree(): continue
     896            if hasattr(self, '_PCPT') and self._PCPT is not None:
     897                K = GF(p**m, prefix=name)
     898                ans.append((K, self.coerce_map_from(K)))
     899            elif m == 1:
     900                ans.append((GF(p), self.coerce_map_from(K)))
     901            else:
     902                deg_gen = self.multiplicative_generator()**((self.order() - 1)//(p**m-1))
     903                K = GF(p**m, modulus=deg_gen.minimal_polynomial(), name=name[m])
     904                print K
     905                ans.append((K, FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(K, self), deg_gen)))
     906        return ans
     907
    741908    def algebraic_closure(self):
    742909        """
    743910        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  
    603603            ...
    604604            TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^3
    605605            sage: FiniteField_ext_pari(16,'a')._coerce_(FiniteField_ext_pari(4,'a').0)
    606             Traceback (most recent call last):
    607             ...
    608             TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^4
     606            a^2 + a
    609607            sage: k = FiniteField_ext_pari(8,'a')
    610608            sage: k._coerce_(FiniteField(7,'a')(2))
    611609            Traceback (most recent call last):
     
    613611            TypeError: no canonical coercion from Finite Field of size 7 to Finite Field in a of size 2^3
    614612        """
    615613        from sage.rings.integer_ring import ZZ
     614        from sage.rings.finite_rings.finite_field_base import is_FiniteField
    616615        from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic
    617616        if R is int or R is long or R is ZZ:
    618617            return True
    619         if isinstance(R, FiniteField_ext_pari):
     618        if is_FiniteField(R):
    620619            if R is self:
    621620                return True
     621            from sage.rings.residue_field import ResidueField_generic
     622            if isinstance(R, ResidueField_generic):
     623                return False
    622624            if R.characteristic() == self.characteristic():
     625                if isinstance(R, IntegerModRing_generic):
     626                    return True
    623627                if R.degree() == 1:
    624628                    return True
    625                 elif self.degree() % R.degree() == 0:
    626                     # TODO: This is where we *would* do coercion from one nontrivial finite field to another...
    627                     return False               
    628         from sage.rings.residue_field import ResidueField_generic
    629         if isinstance(R, IntegerModRing_generic) and R.characteristic() == self.characteristic() and not isinstance(R, ResidueField_generic):
    630             return True
     629                if self.degree() % R.degree() == 0:
     630                    if hasattr(self, '_PCPT') and hasattr(R, '_PCPT') and R._PCPT is not None:
     631                        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     632                        return FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(R, self), self.gen()**((self.order()-1)//(R.order()-1)))
    631633
    632634    def __len__(self):
    633635        """
  • 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  
    326326            sage: F9 = FiniteField_givaro(9)
    327327            sage: F81 = FiniteField_givaro(81)
    328328            sage: F81(F9.gen())
    329             Traceback (most recent call last):
    330             ...
    331             TypeError: unable to coerce from a finite field other than the prime subfield
     329            2*a^3 + 2*a^2 + 1
    332330        """
    333331        return self._cache.element_from_data(e)
    334332
     
    362360                    return True
    363361                if R.degree() == 1:
    364362                    return True
    365                 elif self.degree() % R.degree() == 0:
    366                     # This is where we *would* do coercion from one nontrivial finite field to another...
    367                     # We use this error message for backward compatibility until #8335 is finished
    368                     raise TypeError, "unable to coerce from a finite field other than the prime subfield"
     363                if self.degree() % R.degree() == 0:
     364                    if hasattr(self, '_PCPT') and hasattr(R, '_PCPT') and R._PCPT is not None:
     365                        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     366                        return FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(R, self), self.gen()**((self.order()-1)//(R.order()-1)))
    369367
    370368    def gen(self, n=0):
    371369        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  
    247247                return True
    248248            if isinstance(R, ResidueField_generic):
    249249                return False
    250             if isinstance(R, IntegerModRing_generic) and R.characteristic() % 2 == 0:
    251                 return True
    252250            if R.characteristic() == 2:
     251                if isinstance(R, IntegerModRing_generic):
     252                    return True
    253253                if R.degree() == 1:
    254254                    return True
    255255                elif self.degree() % R.degree() == 0:
    256                     # This is where we *would* do coercion from one nontrivial finite field to another...
    257                     raise NotImplementedError
     256                    if self._PCPT is not None and hasattr(R, '_PCPT') and R._PCPT is not None:
     257                        from homset import FiniteFieldHomset, FiniteFieldHomomorphism_im_gens
     258                        return FiniteFieldHomomorphism_im_gens(FiniteFieldHomset(R, self), self.gen()**((self.order()-1)//(R.order()-1)))
    258259
    259260    def gen(self, ignored=None):
    260261        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  
    174174        if to_ZZ is not None:
    175175            return integer_mod.Integer_to_IntegerMod(self) * to_ZZ
    176176
     177    def construction(self):
     178        """
     179        Returns the construction of this finite field (for use by sage.categories.pushout)
     180
     181        EXAMPLES::
     182
     183            sage: GF(3).construction()
     184            (QuotientFunctor, Integer Ring)
     185        """
     186        return integer_mod_ring.IntegerModRing_generic.construction(self)
     187
    177188    def characteristic(self):
    178189        r"""
    179190        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  
    77    """
    88    Set of homomorphisms with domain a given finite field.
    99    """
     10#     def __init__(self, R, S, category=None):
     11#         if category is None:
     12#             from sage.categories.finite_fields import FiniteFields
     13#             category = FiniteFields()
     14#         RingHomset_generic.__init__(self, R, S, category)
     15
    1016    def __call__(self, im_gens, check=True):
    1117        """
    1218        EXAMPLES::
  • 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)