Embeddings into ambient fields#

This module provides classes to handle embeddings of number fields into ambient fields (generally \(\RR\) or \(\CC\)).

class sage.rings.number_field.number_field_morphisms.CyclotomicFieldConversion[source]#

Bases: Map

This allows one to cast one cyclotomic field in another consistently.

EXAMPLES:

sage: from sage.rings.number_field.number_field_morphisms import CyclotomicFieldConversion
sage: K1.<z1> = CyclotomicField(12)
sage: K2.<z2> = CyclotomicField(18)
sage: f = CyclotomicFieldConversion(K1, K2)
sage: f(z1^2)
z2^3
sage: f(z1)
Traceback (most recent call last):
...
ValueError: Element z1 has no image in the codomain
>>> from sage.all import *
>>> from sage.rings.number_field.number_field_morphisms import CyclotomicFieldConversion
>>> K1 = CyclotomicField(Integer(12), names=('z1',)); (z1,) = K1._first_ngens(1)
>>> K2 = CyclotomicField(Integer(18), names=('z2',)); (z2,) = K2._first_ngens(1)
>>> f = CyclotomicFieldConversion(K1, K2)
>>> f(z1**Integer(2))
z2^3
>>> f(z1)
Traceback (most recent call last):
...
ValueError: Element z1 has no image in the codomain

Tests from Issue #29511:

sage: K.<z> = CyclotomicField(12)
sage: K1.<z1> = CyclotomicField(3)
sage: K(2) in K1 # indirect doctest
True
sage: K1(K(2)) # indirect doctest
2
>>> from sage.all import *
>>> K = CyclotomicField(Integer(12), names=('z',)); (z,) = K._first_ngens(1)
>>> K1 = CyclotomicField(Integer(3), names=('z1',)); (z1,) = K1._first_ngens(1)
>>> K(Integer(2)) in K1 # indirect doctest
True
>>> K1(K(Integer(2))) # indirect doctest
2
class sage.rings.number_field.number_field_morphisms.CyclotomicFieldEmbedding[source]#

Bases: 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().

section()[source]#

Return the section of self.

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: h = f.section()
sage: h(f(K.gen())) # indirect doctest
zeta7
>>> from sage.all import *
>>> from sage.rings.number_field.number_field_morphisms import CyclotomicFieldEmbedding
>>> K = CyclotomicField(Integer(7))
>>> L = CyclotomicField(Integer(21))
>>> f = CyclotomicFieldEmbedding(K, L)
>>> h = f.section()
>>> h(f(K.gen())) # indirect doctest
zeta7
class sage.rings.number_field.number_field_morphisms.EmbeddedNumberFieldConversion[source]#

Bases: Map

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.

ambient_field[source]#
class sage.rings.number_field.number_field_morphisms.EmbeddedNumberFieldMorphism[source]#

Bases: NumberFieldEmbedding

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: x = polygen(ZZ, 'x')
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 with i = I
  To:   Number Field in i with defining polynomial x^2 + 1 with i = -I
  Defn: i -> -i
sage: EmbeddedNumberFieldMorphism(K, L, QQbar)
Generic morphism:
  From: Number Field in i with defining polynomial x^2 + 1 with i = I
  To:   Number Field in i with defining polynomial x^2 + 1 with i = -I
  Defn: i -> -i
>>> from sage.all import *
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) + Integer(1), embedding=QQbar(I), names=('i',)); (i,) = K._first_ngens(1)
>>> L = NumberField(x**Integer(2) + Integer(1), embedding=-QQbar(I), names=('i',)); (i,) = L._first_ngens(1)
>>> from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism
>>> EmbeddedNumberFieldMorphism(K, L, CDF)
Generic morphism:
  From: Number Field in i with defining polynomial x^2 + 1 with i = I
  To:   Number Field in i with defining polynomial x^2 + 1 with i = -I
  Defn: i -> -i
>>> EmbeddedNumberFieldMorphism(K, L, QQbar)
Generic morphism:
  From: Number Field in i with defining polynomial x^2 + 1 with i = I
  To:   Number Field in i with defining polynomial x^2 + 1 with i = -I
  Defn: i -> -i
ambient_field[source]#
section()[source]#

EXAMPLES:

sage: from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism
sage: x = polygen(ZZ, 'x')
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
>>> from sage.all import *
>>> from sage.rings.number_field.number_field_morphisms import EmbeddedNumberFieldMorphism
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(2) - Integer(700), embedding=Integer(25), names=('a',)); (a,) = K._first_ngens(1)
>>> L = NumberField(x**Integer(6) - Integer(700), embedding=Integer(3), names=('b',)); (b,) = L._first_ngens(1)
>>> f = EmbeddedNumberFieldMorphism(K, L)
>>> f(Integer(2)*a - Integer(1))
2*b^3 - 1
>>> g = f.section()
>>> g(Integer(2)*b**Integer(3) - Integer(1))
2*a - 1
class sage.rings.number_field.number_field_morphisms.NumberFieldEmbedding[source]#

Bases: Morphism

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
>>> from sage.all import *
>>> x = polygen(QQ)
>>> from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding
>>> K = NumberField(x**Integer(3)-Integer(2), names=('a',)); (a,) = K._first_ngens(1)
>>> f = NumberFieldEmbedding(K, RLF, Integer(1))
>>> f(a)**Integer(3)
2.00000000000000?
>>> RealField(Integer(200))(f(a)**Integer(3))
2.0000000000000000000000000000000000000000000000000000000000

>>> sigma_a = K.polynomial().change_ring(CC).roots()[Integer(1)][Integer(0)]; sigma_a
-0.62996052494743... - 1.09112363597172*I
>>> g = NumberFieldEmbedding(K, CC, sigma_a)
>>> g(a+Integer(1))
0.37003947505256... - 1.09112363597172*I
gen_image()[source]#

Return the image of the generator under this embedding.

EXAMPLES:

sage: f = QuadraticField(7, 'a', embedding=2).coerce_embedding()
sage: f.gen_image()
2.645751311064591?
>>> from sage.all import *
>>> f = QuadraticField(Integer(7), 'a', embedding=Integer(2)).coerce_embedding()
>>> f.gen_image()
2.645751311064591?
sage.rings.number_field.number_field_morphisms.closest(target, values, margin=1)[source]#

This is a utility function that returns the item in values closest to target (with respect to the 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).

sage.rings.number_field.number_field_morphisms.create_embedding_from_approx(K, gen_image)[source]#

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: x = polygen(ZZ, 'x')
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?
>>> from sage.all import *
>>> from sage.rings.number_field.number_field_morphisms import create_embedding_from_approx
>>> x = polygen(ZZ, 'x')
>>> K = NumberField(x**Integer(3) - x + Integer(1)/Integer(10), names=('a',)); (a,) = K._first_ngens(1)
>>> create_embedding_from_approx(K, Integer(1))
Generic morphism:
  From: Number Field in a with defining polynomial x^3 - x + 1/10
  To:   Real Lazy Field
  Defn: a -> 0.9456492739235915?
>>> create_embedding_from_approx(K, Integer(0))
Generic morphism:
  From: Number Field in a with defining polynomial x^3 - x + 1/10
  To:   Real Lazy Field
  Defn: a -> 0.10103125788101081?
>>> create_embedding_from_approx(K, -Integer(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
>>> from sage.all import *
>>> L = NumberField(x**Integer(6)-x**Integer(2)+Integer(1)/Integer(10), names=('b',)); (b,) = L._first_ngens(1)
>>> create_embedding_from_approx(K, b**Integer(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
>>> from sage.all import *
>>> create_embedding_from_approx(K, b)
Traceback (most recent call last):
...
ValueError: b is not a root of x^3 - x + 1/10
sage.rings.number_field.number_field_morphisms.matching_root(poly, target, ambient_field=None, margin=1, max_prec=None)[source]#

Given a polynomial and a target, choose 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 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
>>> from sage.all import *
>>> from sage.rings.number_field.number_field_morphisms import matching_root
>>> R = CC['x']; (x,) = R._first_ngens(1)
>>> matching_root(x**Integer(2)-Integer(2), RealNumber('1.5'))
1.41421356237310
>>> matching_root(x**Integer(2)-Integer(2), -RealNumber('100.0'))
-1.41421356237310
>>> matching_root(x**Integer(2)-Integer(2), RealNumber('.00000001'))
1.41421356237310
>>> matching_root(x**Integer(3)-Integer(1), CDF.gen(0))
-0.50000000000000... + 0.86602540378443...*I
>>> matching_root(x**Integer(3)-x, Integer(2), ambient_field=RR)
1.00000000000000
sage.rings.number_field.number_field_morphisms.root_from_approx(f, a)[source]#

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))                                        # needs sage.symbolic
sqrt(2)
sage: root_from_approx(x^2 - 2, sqrt(3))                                        # needs sage.symbolic
Traceback (most recent call last):
...
ValueError: sqrt(3) is not a root of x^2 - 2
>>> from sage.all import *
>>> from sage.rings.number_field.number_field_morphisms import root_from_approx
>>> R = QQ['x']; (x,) = R._first_ngens(1)

>>> root_from_approx(x**Integer(2) - Integer(1), -Integer(1))
-1
>>> root_from_approx(x**Integer(2) - Integer(2), Integer(1))
1.414213562373095?
>>> root_from_approx(x**Integer(3) - x - Integer(1), RR(Integer(1)))
1.324717957244746?
>>> root_from_approx(x**Integer(3) - x - Integer(1), CC.gen())
-0.6623589786223730? + 0.5622795120623013?*I

>>> root_from_approx(x**Integer(2) + Integer(1), Integer(0))
Traceback (most recent call last):
...
ValueError: x^2 + 1 has no real roots
>>> root_from_approx(x**Integer(2) + Integer(1), CC(Integer(0)))
-1*I

>>> root_from_approx(x**Integer(2) - Integer(2), sqrt(Integer(2)))                                        # needs sage.symbolic
sqrt(2)
>>> root_from_approx(x**Integer(2) - Integer(2), sqrt(Integer(3)))                                        # needs sage.symbolic
Traceback (most recent call last):
...
ValueError: sqrt(3) is not a root of x^2 - 2