Ticket #11869: 11869.patch

File 11869.patch, 11.9 KB (added by Jeroen Demeyer, 11 years ago)
  • sage/rings/number_field/number_field.py

    # HG changeset patch
    # User Jeroen Demeyer <jdemeyer@cage.ugent.be>
    # Date 1317394042 -7200
    # Node ID 18743a844307e392946ce456467a73e7a5f8c1d8
    # Parent  a8dc03d2ebb202498c6d4c8c98dd0b1b44959645
    Fix conversion of elements of one number field to another
    
    diff --git a/sage/rings/number_field/number_field.py b/sage/rings/number_field/number_field.py
    a b  
    50685068        """
    50695069        Coerce a number field element x into this number field.
    50705070
     5071        Unless `x` is in ``QQ``, this requires ``x.parent()`` and
     5072        ``self`` to have compatible embeddings: either they both embed
     5073        in a common field, or there is an embedding of ``x.parent()``
     5074        into ``self`` or the other way around.  If no compatible
     5075        embeddings are found and `x` is not in ``QQ``, then raise
     5076        ``TypeError``.  This guarantees that these conversions respect
     5077        the field operations and conversions between several fields
     5078        commute.
     5079
    50715080        REMARK:
    50725081
    50735082        The name of this method was chosen for historical reasons.
     
    50775086
    50785087        ``x`` -- an element of some number field
    50795088
    5080         ASSUMPTION:
    5081 
    5082         ``x`` should be an element of a number field whose underlying
    5083         polynomial ring allows conversion into the polynomial ring of
    5084         ``self``.
    5085 
    5086         Note that it is only tested that there is a method
    5087         ``x.polynomial()`` yielding an output that can be converted
    5088         into ``self.polynomial_ring()``.
    5089 
    50905089        OUTPUT:
    50915090
    50925091        An element of ``self`` corresponding to ``x``.
     
    50975096            sage: L.<b> = NumberField(x^2 + 1)
    50985097            sage: K._coerce_from_other_number_field(L(2/3))
    50995098            2/3
     5099            sage: L._coerce_from_other_number_field(K(0))
     5100            0
     5101            sage: K._coerce_from_other_number_field(b)
     5102            Traceback (most recent call last):
     5103            ...
     5104            ValueError: Cannot convert b to Number Field in a with defining polynomial x^3 + 2 (regardless of embeddings)
     5105
     5106        Two number fields both containing `i`::
     5107
     5108            sage: K.<a> = NumberField(x^4 + 6*x^2 + 1, embedding = CC(-2.4*I))
     5109            sage: L.<b> = NumberField(x^4 + 8*x^2 + 4, embedding = CC(2.7*I))
     5110            sage: Ki = 1/2*a^3 + 5/2*a; Ki.minpoly()
     5111            x^2 + 1
     5112            sage: L(Ki)
     5113            -1/4*b^3 - 3/2*b
     5114            sage: K(L(Ki)) == Ki
     5115            True
     5116            sage: Q.<i> = QuadraticField(-1)
     5117            sage: Q(Ki)
     5118            i
     5119            sage: Q(L(Ki))
     5120            i
     5121            sage: L( (Ki+2)^1000 )
     5122            737533628...075020804*b^3 + 442520177...450124824*b + 793311113...453515313
     5123
     5124        This fails if we don't specify the embeddings::
     5125
     5126            sage: K.<a> = NumberField(x^4 + 6*x^2 + 1)
     5127            sage: L.<b> = NumberField(x^4 + 8*x^2 + 4)
     5128            sage: L(1/2*a^3 + 5/2*a)
     5129            Traceback (most recent call last):
     5130            ...
     5131            TypeError: No compatible natural embeddings found for Number Field in b with defining polynomial x^4 + 8*x^2 + 4 and Number Field in a with defining polynomial x^4 + 6*x^2 + 1
     5132
     5133        Embeddings can also be `p`-adic::
     5134
     5135            sage: F = Qp(73)
     5136            sage: K.<a> = NumberField(x^4 + 6*x^2 + 1, embedding = F(1290990671961076190983179596556712119))
     5137            sage: L.<b> = NumberField(x^4 + 8*x^2 + 4, embedding = F(1773398470280167815153042237103591466))
     5138            sage: L(2*a^3 + 10*a + 3)
     5139            b^3 + 6*b + 3
     5140
     5141        If we take the same non-Galois number field with two different
     5142        embeddings, conversion fails::
     5143
     5144            sage: K.<a> = NumberField(x^3 - 4*x + 1, embedding = 0.254)
     5145            sage: L.<b> = NumberField(x^3 - 4*x + 1, embedding = 1.86)
     5146            sage: L(a)
     5147            Traceback (most recent call last):
     5148            ...
     5149            ValueError: Cannot convert a to Number Field in b with defining polynomial x^3 - 4*x + 1 (using the specified embeddings)
     5150
     5151        Subfields automatically come with an embedding::
     5152
     5153            sage: K.<a> = NumberField(x^2 - 5)
     5154            sage: L.<b>, phi = K.subfield(-a)
     5155            sage: phi(b)
     5156            -a
     5157            sage: K(b)
     5158            -a
     5159            sage: L(a)
     5160            -b
     5161
     5162        Below we create two subfields of `K` which both contain `i`.
     5163        Since `L2` and `L3` both embed in `K`, conversion works::
     5164
     5165            sage: K.<z> = NumberField(x^8 - x^4 + 1)
     5166            sage: i = (x^2+1).roots(ring=K)[0][0]
     5167            sage: r2 = (x^2-2).roots(ring=K)[0][0]
     5168            sage: r3 = (x^2-3).roots(ring=K)[0][0]
     5169            sage: L2.<a2>, phi2 = K.subfield(r2+i)
     5170            sage: L3.<a3>, phi3 = K.subfield(r3+i)
     5171            sage: i_in_L2 = L2(i); i_in_L2
     5172            1/6*a2^3 + 1/6*a2
     5173            sage: i_in_L3 = L3(i); i_in_L3
     5174            1/8*a3^3
     5175            sage: L2(i_in_L3) == i_in_L2
     5176            True
     5177            sage: L3(i_in_L2) == i_in_L3
     5178            True
    51005179
    51015180        TESTS:
    51025181
     
    51095188            sage: F(R) == L   #indirect doctest
    51105189            True
    51115190
    5112         """
    5113         f = self.polynomial_ring()(x.polynomial())
    5114         return self._element_class(self, f)
     5191        AUTHORS:
     5192
     5193        - Jeroen Demeyer (2011-09-30): Trac ticket #11869
     5194
     5195        """
     5196        # Special case for x in QQ.  This is common, so should be fast.
     5197        xpol = x.polynomial()
     5198        if xpol.degree() <= 0:
     5199            return self._element_class(self, xpol[0])
     5200        # Convert from L to K
     5201        K = self
     5202        L = x.parent()
     5203        # List of candidates for K(x)
     5204        f = x.minpoly()
     5205        ys = f.roots(ring=K, multiplicities=False)
     5206        if not ys:
     5207            raise ValueError, "Cannot convert %s to %s (regardless of embeddings)"%(x,K)
     5208
     5209        # Find embeddings for K and L.  If no embedding is given, simply
     5210        # take the identity map as "embedding".  This handles the case
     5211        # where one field is created as subfield of the other.
     5212        Kgen = K.gen_embedding()
     5213        if Kgen is None:
     5214            Kgen = K.gen()
     5215        KF = Kgen.parent()
     5216        Lgen = L.gen_embedding()
     5217        if Lgen is None:
     5218            Lgen = L.gen()
     5219        LF = Lgen.parent()
     5220
     5221        # Do not use CDF or RDF because of constraints on the
     5222        # exponent of floating-point numbers
     5223        from sage.rings.all import RealField, ComplexField
     5224        CC = ComplexField(53)
     5225        RR = RealField(53)
     5226
     5227        # Find a common field F into which KF and LF both embed.
     5228        if CC.has_coerce_map_from(KF) and CC.has_coerce_map_from(LF):
     5229            # We postpone converting Kgen and Lgen to F until we know the
     5230            # floating-point precision required.
     5231            F = CC
     5232        elif KF is LF:
     5233            F = KF
     5234        elif KF.has_coerce_map_from(LF):
     5235            F = KF
     5236            Lgen = F(Lgen)
     5237        elif LF.has_coerce_map_from(KF):
     5238            F = LF
     5239            Kgen = F(Kgen)
     5240        else:
     5241            raise TypeError, "No compatible natural embeddings found for %s and %s"%(KF,LF)
     5242
     5243        # Define a function are_roots_equal to determine whether two
     5244        # roots of f are equal.  A simple a == b does not suffice for
     5245        # inexact fields because of floating-point errors.
     5246        if F.is_exact():
     5247            are_roots_equal = lambda a,b: a == b
     5248        else:
     5249            ### Compute a lower bound on the distance between the roots of f.
     5250            ### This essentially gives the precision to work with.
     5251
     5252            # A function
     5253            # log2abs: F --> RR
     5254            #          x |-> log2(abs(x))
     5255            # This should work for all fields F with an absolute value.
     5256            # The p-adic absolute value goes into QQ, so we need the RR().
     5257            log2abs = lambda x: RR(F(x).abs()).log2()
     5258
     5259            # Compute half Fujiwara's bound on the roots of f
     5260            n = f.degree()
     5261            log_half_root_bound = log2abs(f[0]/2)/n
     5262            for i in range(1,n):
     5263                bd = log2abs(f[i])/(n-i)
     5264                if bd > log_half_root_bound:
     5265                    log_half_root_bound = bd
     5266            # Twice the bound on the roots of f, in other words an upper
     5267            # bound for the distance between two roots.
     5268            log_double_root_bound = log_half_root_bound + 2.0  # 2.0 = log2(4)
     5269            # Now we compute the minimum distance between two roots of f
     5270            # using the fact that the discriminant of f is the product of
     5271            # all root distances.
     5272            # We use pari to compute the discriminant to work around #11872.
     5273            log_root_diff = log2abs(pari(f).poldisc())*0.5 - (n*(n-1)*0.5 - 1.0)*log_double_root_bound
     5274            # Let eps be 1/128 times the minimal root distance.
     5275            # This implies: If two roots of f are at distance <= eps, then
     5276            # they are equal.  The factor 128 is arbitrary, it is an extra
     5277            # safety margin.
     5278            eps = (log_root_diff - 7.0).exp2()
     5279            are_roots_equal = lambda a,b: (a-b).abs() <= eps
     5280            if F is CC:
     5281                # Adjust the precision of F, sufficient to represent all
     5282                # the temporaries in the computation with a precision
     5283                # of eps, plus some extra bits.
     5284                H = [log_double_root_bound - 1.0]
     5285                for e in [x] + ys:
     5286                    H += [log2abs(c) for c in e.polynomial().coefficients()]
     5287                prec = (max(H) + RR(n+1).log2() - log_root_diff).ceil() + 12 + n
     5288                F = ComplexField(prec=prec)
     5289                Kgen = F(Kgen)
     5290                Lgen = F(Lgen)
     5291
     5292        # Embed x and the y's in F
     5293        emb_x = x.polynomial()(Lgen)
     5294        for y in ys:
     5295            emb_y = y.polynomial()(Kgen)
     5296            if are_roots_equal(emb_x, emb_y):
     5297                return y
     5298        raise ValueError, "Cannot convert %s to %s (using the specified embeddings)"%(x,K)
    51155299   
    51165300    def _coerce_non_number_field_element_in(self, x):
    51175301        """
     
    53035487                            except ValueError: # no embedding found
    53045488                                # there might be one in the alg. completion
    53055489                                return number_field_morphisms.EmbeddedNumberFieldMorphism(R, self, ambient_field.algebraic_closure() if hasattr(ambient_field,'algebraic_closure') else ambient_field)
    5306                     except (ValueError, TypeError, sage.structure.coerce_exceptions.CoercionException),msg:
     5490                    except (ValueError, TypeError, NotImplementedError, sage.structure.coerce_exceptions.CoercionException),msg:
    53075491                        # no success with the pushout
    53085492                        try:
    53095493                            return number_field_morphisms.EmbeddedNumberFieldMorphism(R, self)
  • sage/rings/residue_field.pyx

    diff --git a/sage/rings/residue_field.pyx b/sage/rings/residue_field.pyx
    a b  
    494494            a
    495495            sage: k(GF(17)(4))
    496496            4
    497 
    498         In the remaining tests, we elaborate a bit more on the difference of
    499         coercion and conversion::
    500 
    501             sage: K.<r4> = NumberField(x^4-2)
    502             sage: L.<r4> = NumberField(x^4-2, embedding=CDF.0)
    503             sage: FK = K.fractional_ideal(K.0)
    504             sage: FL = L.fractional_ideal(L.0)
    505 
    506         There is no coercion from the embedded to the unembedded
    507         number field. Hence, the two fractional ideals are different.
    508         By consequence, the resulting residue fields are different::
    509 
    510             sage: RL = ResidueField(FL)
    511             sage: RK = ResidueField(FK)
    512             sage: RK == RL
    513             False
    514 
    515         Since ``RL`` is defined with the embedded number field ``L``, there
    516         is no coercion from the maximal order of ``K`` to ``RL``. However,
    517         conversion is possible::
    518 
    519             sage: OK = K.maximal_order()
    520             sage: RL.has_coerce_map_from(OK)
    521             False
    522             sage: RL(OK.1)
    523             0
    524 
    525497        """
    526498        K = OK = self.p.ring()
    527499        if OK.is_field():