Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Embeddings into ambient fields
This module provides classes to handle embeddings of number fields into ambient fields (generally `\RR` or `\CC`). """
#***************************************************************************** # Copyright (C) 2008 Robert Bradshaw <robertwb@math.washington.edu> # # Distributed under the terms of the GNU General Public License (GPL) # # This code is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import
import sage.rings.complex_double
from sage.structure.element cimport Element from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map from sage.categories.pushout import pushout
from sage.rings.real_mpfr import RealField, mpfr_prec_min from sage.rings.complex_field import ComplexField from sage.rings.real_lazy import RLF, CLF, LazyField, LazyAlgebraic
cdef class NumberFieldEmbedding(Morphism):
cdef _gen_image
def __init__(self, K, R, gen_embedding): """ If R is a lazy field, the closest root to gen_embedding will be chosen.
EXAMPLES::
sage: x = polygen(QQ) sage: from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding sage: K.<a> = NumberField(x^3-2) sage: f = NumberFieldEmbedding(K, RLF, 1) sage: f(a)^3 2.00000000000000? sage: RealField(200)(f(a)^3) 2.0000000000000000000000000000000000000000000000000000000000
sage: sigma_a = K.polynomial().change_ring(CC).roots()[1][0]; sigma_a -0.62996052494743... - 1.09112363597172*I sage: g = NumberFieldEmbedding(K, CC, sigma_a) sage: g(a+1) 0.37003947505256... - 1.09112363597172*I """ else:
cdef dict _extra_slots(self): """ A helper for pickling and copying.
INPUT:
``_slots`` -- a dictionary
OUTPUT:
The given dictionary, with the generator image added.
EXAMPLES::
sage: x = polygen(QQ) sage: from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding sage: K.<a> = NumberField(x^3-2) sage: f = NumberFieldEmbedding(K, RLF, 1) sage: g = copy(f) # indirect doctest sage: g Generic morphism: From: Number Field in a with defining polynomial x^3 - 2 To: Real Lazy Field Defn: a -> 1.259921049894873? sage: g(a)^3 2.00000000000000? """
cdef _update_slots(self, dict _slots): """ A helper for unpickling and copying.
INPUT:
``_slots`` -- a dictionary providing values for the c(p)def slots of self.
EXAMPLES::
sage: x = polygen(QQ) sage: from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding sage: K.<a> = NumberField(x^3-2) sage: f = NumberFieldEmbedding(K, RLF, 1) sage: g = copy(f) # indirect doctest sage: g Generic morphism: From: Number Field in a with defining polynomial x^3 - 2 To: Real Lazy Field Defn: a -> 1.259921049894873? sage: g(a)^3 2.00000000000000? """
cpdef Element _call_(self, x): """ EXAMPLES::
sage: x = polygen(QQ) sage: from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding sage: K.<a> = NumberField(x^2-2) sage: f = NumberFieldEmbedding(K, RLF, 1.4) sage: f(a) # indirect doctest 1.414213562373095? """
def _repr_defn(self): """ EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding sage: K.<a> = NumberField(x^2-2) sage: f = NumberFieldEmbedding(K, RLF, 1.4) sage: f # indirect doctest Generic morphism: From: Number Field in a with defining polynomial x^2 - 2 To: Real Lazy Field Defn: a -> 1.414213562373095? """
def gen_image(self): """ Returns the image of the generator under this embedding.
EXAMPLES::
sage: f = QuadraticField(7, 'a', embedding=2).coerce_embedding() sage: f.gen_image() 2.645751311064591? """
cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): r""" This allows one to go from one number field in another consistently, assuming they both have specified embeddings into an ambient field.
If no ambient field is supplied, then the following ambient fields are tried:
* the pushout of the fields where the number fields are embedded;
* the algebraic closure of the previous pushout;
* `\CC`.
EXAMPLES::
sage: K.<i> = NumberField(x^2+1,embedding=QQbar(I)) sage: L.<i> = NumberField(x^2+1,embedding=-QQbar(I)) sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism sage: EmbeddedNumberFieldMorphism(K,L,CDF) Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 To: Number Field in i with defining polynomial x^2 + 1 Defn: i -> -i sage: EmbeddedNumberFieldMorphism(K,L,QQbar) Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 To: Number Field in i with defining polynomial x^2 + 1 Defn: i -> -i
""" cdef readonly ambient_field
def __init__(self, K, L, ambient_field=None): """ EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism sage: K.<a> = NumberField(x^2-17, embedding=4.1) sage: L.<b> = NumberField(x^4-17, embedding=2.0) sage: f = EmbeddedNumberFieldMorphism(K, L) sage: f(a) b^2
sage: K.<zeta12> = CyclotomicField(12) sage: L.<zeta36> = CyclotomicField(36) sage: f = EmbeddedNumberFieldMorphism(K, L) sage: f(zeta12) zeta36^3 sage: f(zeta12^5-zeta12+1) zeta36^9 - 2*zeta36^3 + 1 sage: f Generic morphism: From: Cyclotomic Field of order 12 and degree 4 To: Cyclotomic Field of order 36 and degree 12 Defn: zeta12 -> zeta36^3
The embeddings must be compatible::
sage: F1 = NumberField(x^3 + 2, 'a', embedding=2) sage: F2 = NumberField(x^3 + 2, 'a', embedding=CC.0) sage: F1.gen() + F2.gen() Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: 'Number Field in a with defining polynomial x^3 + 2' and 'Number Field in a with defining polynomial x^3 + 2'
The following was fixed to raise a ``TypeError`` in :trac:`15331`::
sage: L.<i> = NumberField(x^2 + 1) sage: K = NumberField(L(i/2+3).minpoly(), names=('i0',), embedding=L(i/2+3)) sage: EmbeddedNumberFieldMorphism(K, L) Traceback (most recent call last): ... TypeError: No embedding available for Number Field in i with defining polynomial x^2 + 1
""" raise TypeError("No embedding available for %s"%K) pass else:
else:
def section(self): """ EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism sage: K.<a> = NumberField(x^2-700, embedding=25) sage: L.<b> = NumberField(x^6-700, embedding=3) sage: f = EmbeddedNumberFieldMorphism(K, L) sage: f(2*a-1) 2*b^3 - 1 sage: g = f.section() sage: g(2*b^3-1) 2*a - 1 """
cdef class EmbeddedNumberFieldConversion(Map): r""" This allows one to cast one number field in another consistently, assuming they both have specified embeddings into an ambient field (by default it looks for an embedding into `\CC`).
This is done by factoring the minimal polynomial of the input in the number field of the codomain. This may fail if the element is not actually in the given field. """ cdef _gen_image cdef readonly ambient_field
def __init__(self, K, L, ambient_field=None): """ EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldConversion sage: K.<a> = NumberField(x^2-17, embedding=4.1) sage: L.<b> = NumberField(x^4-17, embedding=2.0) sage: f = EmbeddedNumberFieldConversion(K, L) sage: f(a) b^2 sage: f(K(b^2/2-11)) 1/2*b^2 - 11 """
cpdef Element _call_(self, x): """ EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldConversion sage: K.<zeta12> = CyclotomicField(12) sage: L.<zeta15> = CyclotomicField(15) sage: f = EmbeddedNumberFieldConversion(K, L) sage: f(zeta12^4) # indirect doctest zeta15^5 sage: f(zeta12) Traceback (most recent call last): ... ValueError: No consistent embedding of Cyclotomic Field of order 12 and degree 4 into Cyclotomic Field of order 15 and degree 8. """
cpdef matching_root(poly, target, ambient_field=None, margin=1, max_prec=None): """ Given a polynomial and a target, this function chooses the root that target best approximates as compared in ambient_field.
If the parent of target is exact, the equality is required, otherwise find closest root (with respect to the \code{abs} function) in the ambient field to the target, and return the root of poly (if any) that approximates it best.
EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import matching_root sage: R.<x> = CC[] sage: matching_root(x^2-2, 1.5) 1.41421356237310 sage: matching_root(x^2-2, -100.0) -1.41421356237310 sage: matching_root(x^2-2, .00000001) 1.41421356237310 sage: matching_root(x^3-1, CDF.0) -0.50000000000000... + 0.86602540378443...*I sage: matching_root(x^3-x, 2, ambient_field=RR) 1.00000000000000 """ roots = poly else:
else: # since things are inexact, try and pick the closest one # -- unless the ambient field is inexact and has no prec(), # which holds, e.g., for the symbolic ring return None ambient_roots = [ambient_field(r) for r in poly] else:
cpdef closest(target, values, margin=1): """ This is a utility function that returns the item in values closest to target (with respect to the \code{abs} function). If margin is greater than 1, and x and y are the first and second closest elements to target, then only return x if x is margin times closer to target than y, i.e. margin * abs(target-x) < abs(target-y).
TESTS::
sage: from sage.rings.number_field.number_field_morphisms import closest sage: closest(1.2, [0,1,2,3,4]) 1 sage: closest(1.7, [0,1,2,3,4]) 2 sage: closest(1.7, [0,1,2,3,4], margin=5) sage: closest(1.9, [0,1,2,3,4], margin=5) 2 sage: closest(.2, [-1, 1, CDF.0, -CDF.0]) 1 """ cdef int i raise ValueError else: else:
def root_from_approx(f, a): """ Return an exact root of the polynomial `f` closest to `a`.
INPUT:
- ``f`` -- polynomial with rational coefficients
- ``a`` -- element of a ring
OUTPUT:
A root of ``f`` in the parent of ``a`` or, if ``a`` is not already an exact root of ``f``, in the corresponding lazy field. The root is taken to be closest to ``a`` among all roots of ``f``.
EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import root_from_approx sage: R.<x> = QQ[]
sage: root_from_approx(x^2 - 1, -1) -1 sage: root_from_approx(x^2 - 2, 1) 1.414213562373095? sage: root_from_approx(x^3 - x - 1, RR(1)) 1.324717957244746? sage: root_from_approx(x^3 - x - 1, CC.gen()) -0.6623589786223730? + 0.5622795120623013?*I
sage: root_from_approx(x^2 + 1, 0) Traceback (most recent call last): ... ValueError: x^2 + 1 has no real roots sage: root_from_approx(x^2 + 1, CC(0)) -1*I
sage: root_from_approx(x^2 - 2, sqrt(2)) sqrt(2) sage: root_from_approx(x^2 - 2, sqrt(3)) Traceback (most recent call last): ... ValueError: sqrt(3) is not a root of x^2 - 2
""" # p-adic lazy, when implemented, would go here else:
def create_embedding_from_approx(K, gen_image): """ Return an embedding of ``K`` determined by ``gen_image``.
The codomain of the embedding is the parent of ``gen_image`` or, if ``gen_image`` is not already an exact root of the defining polynomial of ``K``, the corresponding lazy field. The embedding maps the generator of ``K`` to a root of the defining polynomial of ``K`` closest to ``gen_image``.
EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import create_embedding_from_approx sage: K.<a> = NumberField(x^3-x+1/10) sage: create_embedding_from_approx(K, 1) Generic morphism: From: Number Field in a with defining polynomial x^3 - x + 1/10 To: Real Lazy Field Defn: a -> 0.9456492739235915? sage: create_embedding_from_approx(K, 0) Generic morphism: From: Number Field in a with defining polynomial x^3 - x + 1/10 To: Real Lazy Field Defn: a -> 0.10103125788101081? sage: create_embedding_from_approx(K, -1) Generic morphism: From: Number Field in a with defining polynomial x^3 - x + 1/10 To: Real Lazy Field Defn: a -> -1.046680531804603?
We can define embeddings from one number field to another::
sage: L.<b> = NumberField(x^6-x^2+1/10) sage: create_embedding_from_approx(K, b^2) Generic morphism: From: Number Field in a with defining polynomial x^3 - x + 1/10 To: Number Field in b with defining polynomial x^6 - x^2 + 1/10 Defn: a -> b^2
If the embedding is exact, it must be valid::
sage: create_embedding_from_approx(K, b) Traceback (most recent call last): ... ValueError: b is not a root of x^3 - x + 1/10 """ return None return gen_image else: raise TypeError("Embedding (type %s) must be a morphism or element." % type(gen_image))
cdef class CyclotomicFieldEmbedding(NumberFieldEmbedding): """ Specialized class for converting cyclotomic field elements into a cyclotomic field of higher order. All the real work is done by _lift_cyclotomic_element. """
cdef ratio
def __init__(self, K, L): """ Check and cache the parameters.
EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import CyclotomicFieldEmbedding sage: CyclotomicFieldEmbedding(CyclotomicField(7), CyclotomicField(21)) Generic morphism: From: Cyclotomic Field of order 7 and degree 6 To: Cyclotomic Field of order 21 and degree 12 Defn: zeta7 -> zeta21^3
Note that this only handles the easy case of cyclotomic fields where the order of the smaller dividing the order of the larger, regardless of whether or not there is an actual coercion::
sage: CyclotomicFieldEmbedding(CyclotomicField(3), QuadraticField(-3, 'a')) Traceback (most recent call last): ... TypeError: CyclotomicFieldEmbedding only valid for cyclotomic fields. sage: CyclotomicFieldEmbedding(CyclotomicField(14), CyclotomicField(21)) Traceback (most recent call last): ... TypeError: The zeta_order of the new field must be a multiple of the zeta_order of the original.
Check that :trac:`13765` is fixed::
sage: z3=(CC(-1)^(1/3))^2 sage: Ka.<a>=CyclotomicField(3,embedding=z3) sage: Kb.<b>=CyclotomicField(3,embedding=z3^2) sage: CyclotomicFieldEmbedding(Ka, Kb) Generic morphism: From: Cyclotomic Field of order 3 and degree 2 To: Cyclotomic Field of order 3 and degree 2 Defn: a -> -b - 1 sage: Ka(b) -a - 1 sage: a + b -1 sage: b + a -1 """
cdef dict _extra_slots(self): """ A helper for pickling and copying.
INPUT:
``_slots`` -- a dictionary
OUTPUT:
The given dictionary, with _gen_image and ratio added.
EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import CyclotomicFieldEmbedding sage: cf6 = CyclotomicField(6) sage: cf12 = CyclotomicField(12) sage: f = CyclotomicFieldEmbedding(cf6, cf12) sage: g = copy(f) # indirect doctest sage: g Generic morphism: From: Cyclotomic Field of order 6 and degree 2 To: Cyclotomic Field of order 12 and degree 4 Defn: zeta6 -> zeta12^2 sage: g(cf6.0) zeta12^2 """
cdef _update_slots(self, dict _slots): """ A helper for unpickling and copying.
INPUT:
``_slots`` -- a dictionary providing values for the c(p)def slots of self.
EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import CyclotomicFieldEmbedding sage: cf6 = CyclotomicField(6) sage: cf12 = CyclotomicField(12) sage: f = CyclotomicFieldEmbedding(cf6, cf12) sage: g = copy(f) # indirect doctest sage: g Generic morphism: From: Cyclotomic Field of order 6 and degree 2 To: Cyclotomic Field of order 12 and degree 4 Defn: zeta6 -> zeta12^2 sage: g(cf6.0) zeta12^2 """
cpdef Element _call_(self, x): """ EXAMPLES::
sage: from sage.rings.number_field.number_field_morphisms import CyclotomicFieldEmbedding sage: K = CyclotomicField(7) sage: L = CyclotomicField(21) sage: f = CyclotomicFieldEmbedding(K, L) sage: f(K.gen()) # indirect doctest zeta21^3 sage: f(K.gen()^2 + 3) # indirect doctest zeta21^6 + 3 """ |