Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit de9c3d5

Browse files
author
Release Manager
committed
Trac #31628: fix/improve conversions to QQbar and AA
* fix conversion from ℚ[i] to `QQbar` (honor complex embeddings) * add implicit coercions from python ints and from number fields with compatible embeddings URL: https://trac.sagemath.org/31628 Reported by: mmezzarobba Ticket author(s): Marc Mezzarobba, Vincent Delecroix Reviewer(s): Vincent Delecroix, Marc Mezzarobba
2 parents 96c2708 + ed19558 commit de9c3d5

File tree

5 files changed

+107
-63
lines changed

5 files changed

+107
-63
lines changed

src/sage/modular/dirichlet.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,10 +1590,10 @@ def kloosterman_sum(self, a=1, b=0):
15901590
15911591
sage: G = DirichletGroup(12, QQbar)
15921592
sage: e = G.gens()[0]
1593+
sage: e.kloosterman_sum(5, 4)
1594+
0.?e-17 - 4.000000000000000?*I
15931595
sage: e.kloosterman_sum(5,11)
1594-
Traceback (most recent call last):
1595-
...
1596-
NotImplementedError: Kloosterman sums not implemented over this ring
1596+
0
15971597
"""
15981598
G = self.parent()
15991599
zo = G.zeta_order()

src/sage/rings/number_field/number_field_element.pyx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,6 +2789,10 @@ cdef class NumberFieldElement(FieldElement):
27892789
sage: E = C.algebraic_closure()
27902790
sage: E(a)
27912791
-4.949886207424724? - 0.2195628712241434?*I
2792+
2793+
sage: NF.<sqrt2> = QuadraticField(2)
2794+
sage: AA(sqrt2)
2795+
1.414213562373095?
27922796
"""
27932797
if self.is_rational():
27942798
return parent(self._rational_())

src/sage/rings/number_field/number_field_element_quadratic.pyx

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,29 +1706,6 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute):
17061706
mpq_canonicalize(res.value)
17071707
return res
17081708

1709-
def _algebraic_(self, parent):
1710-
r"""
1711-
Convert this element to an algebraic number, if possible.
1712-
1713-
EXAMPLES::
1714-
1715-
sage: NF.<i> = QuadraticField(-1)
1716-
sage: QQbar(1+i)
1717-
I + 1
1718-
sage: NF.<sqrt3> = QuadraticField(2)
1719-
sage: AA(sqrt3)
1720-
1.414213562373095?
1721-
"""
1722-
import sage.rings.qqbar as qqbar
1723-
if (parent is qqbar.QQbar
1724-
and list(self._parent.polynomial()) == [1, 0, 1]):
1725-
# AlgebraicNumber.__init__ does a better job than
1726-
# NumberFieldElement._algebraic_ in this case, but
1727-
# QQbar._element_constructor_ calls the latter first.
1728-
return qqbar.AlgebraicNumber(self)
1729-
else:
1730-
return NumberFieldElement._algebraic_(self, parent)
1731-
17321709
cpdef bint is_one(self):
17331710
r"""
17341711
Check whether this number field element is `1`.
@@ -2417,6 +2394,34 @@ cdef class NumberFieldElement_gaussian(NumberFieldElement_quadratic):
24172394
from sage.symbolic.constants import I
24182395
return self[1]*(I if self.standard_embedding else -I) + self[0]
24192396

2397+
def _algebraic_(self, parent):
2398+
r"""
2399+
Convert this element to an algebraic number, if possible.
2400+
2401+
EXAMPLES::
2402+
2403+
sage: NF.<i> = QuadraticField(-1)
2404+
sage: QQbar(i+2)
2405+
I + 2
2406+
sage: K.<ii> = QuadraticField(-1, embedding=CC(0,-1))
2407+
sage: QQbar(ii+2)
2408+
-I + 2
2409+
sage: AA(i)
2410+
Traceback (most recent call last):
2411+
...
2412+
ValueError: unable to convert i to an element of Algebraic Real Field
2413+
"""
2414+
import sage.rings.qqbar as qqbar
2415+
if parent is qqbar.QQbar:
2416+
# AlgebraicNumber.__init__ does a better job than
2417+
# NumberFieldElement._algebraic_ in this case, but
2418+
# QQbar._element_constructor_ calls the latter first.
2419+
return qqbar.AlgebraicNumber(self)
2420+
elif parent is qqbar.AA and self[1].is_zero():
2421+
return qqbar.AlgebraicReal(self)
2422+
else:
2423+
raise ValueError(f"unable to convert {self!r} to an element of {parent!r}")
2424+
24202425
cpdef real_part(self):
24212426
r"""
24222427
Real part.

src/sage/rings/qqbar.py

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,6 @@
115115
3.146264369941973?
116116
sage: QQbar(I)
117117
I
118-
sage: AA(I)
119-
Traceback (most recent call last):
120-
...
121-
ValueError: Cannot coerce algebraic number with non-zero imaginary part to algebraic real
122118
sage: QQbar(I * golden_ratio)
123119
1.618033988749895?*I
124120
sage: AA(golden_ratio)^2 - AA(golden_ratio)
@@ -150,24 +146,30 @@
150146
sage: QQbar(-1)^(1/3)
151147
0.500000000000000? + 0.866025403784439?*I
152148
153-
We can explicitly coerce from `\QQ[I]`. (Technically, this is not quite
154-
kosher, since `\QQ[I]` does not come with an embedding; we do not know
155-
whether the field generator is supposed to map to `+I` or `-I`. We assume
156-
that for any quadratic field with polynomial `x^2+1`, the generator maps
157-
to `+I`.)::
158-
159-
sage: K.<im> = QQ[I]
160-
sage: pythag = QQbar(3/5 + 4*im/5); pythag
161-
4/5*I + 3/5
162-
sage: pythag.abs() == 1
163-
True
149+
However, implicit coercion from `\QQ[I]` is only allowed when it is equipped
150+
with a complex embedding::
164151
165-
However, implicit coercion from `\QQ[I]` is not allowed::
152+
sage: i.parent()
153+
Number Field in I with defining polynomial x^2 + 1 with I = 1*I
154+
sage: QQbar(1) + i
155+
I + 1
166156
157+
sage: K.<im> = QuadraticField(-1, embedding=None)
167158
sage: QQbar(1) + im
168159
Traceback (most recent call last):
169160
...
170-
TypeError: unsupported operand parent(s) for +: 'Algebraic Field' and 'Number Field in I with defining polynomial x^2 + 1 with I = 1*I'
161+
TypeError: unsupported operand parent(s) for +: 'Algebraic Field' and
162+
'Number Field in im with defining polynomial x^2 + 1'
163+
164+
However, we can explicitly coerce from the abstract number field `\QQ[I]`.
165+
(Technically, this is not quite kosher, since we do not know whether the field
166+
generator is supposed to map to `+I` or `-I`. We assume that for any quadratic
167+
field with polynomial `x^2+1`, the generator maps to `+I`.)::
168+
169+
sage: pythag = QQbar(3/5 + 4*im/5); pythag
170+
4/5*I + 3/5
171+
sage: pythag.abs() == 1
172+
True
171173
172174
We can implicitly coerce from algebraic reals to algebraic numbers::
173175
@@ -553,8 +555,10 @@
553555
import operator
554556

555557
import sage.rings.ring
558+
import sage.rings.number_field.number_field_base
556559
from sage.misc.fast_methods import Singleton
557560
from sage.misc.cachefunc import cached_method
561+
from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical
558562
from sage.structure.sage_object import SageObject
559563
from sage.structure.richcmp import (richcmp, richcmp_method,
560564
rich_to_bool, richcmp_not_equal,
@@ -569,7 +573,7 @@
569573
from sage.rings.integer_ring import ZZ
570574
from sage.rings.rational_field import QQ
571575
from sage.rings.number_field.number_field import NumberField, GaussianField, CyclotomicField
572-
from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic
576+
from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic, NumberFieldElement_gaussian
573577
from sage.arith.all import factor
574578
from . import infinity
575579
from sage.categories.action import Action
@@ -1063,9 +1067,17 @@ def __init__(self):
10631067
10641068
sage: QQbar.category() # indirect doctest
10651069
Category of infinite fields
1070+
1071+
Coercions::
1072+
1073+
sage: AA.has_coerce_map_from(ZZ)
1074+
True
1075+
sage: AA.has_coerce_map_from(int)
1076+
True
10661077
"""
10671078
from sage.categories.fields import Fields
10681079
AlgebraicField_common.__init__(self, self, ('x',), normalize=False, category=Fields().Infinite())
1080+
self._populate_coercion_lists_([ZZ, QQ])
10691081

10701082
def _element_constructor_(self, x):
10711083
r"""
@@ -1157,8 +1169,6 @@ def _coerce_map_from_(self, from_par):
11571169
11581170
TESTS::
11591171
1160-
sage: AA.has_coerce_map_from(ZZ) # indirect doctest
1161-
True
11621172
sage: K.<a> = QuadraticField(7, embedding=AA(7).sqrt()); AA.has_coerce_map_from(K)
11631173
True
11641174
sage: a in AA
@@ -1167,9 +1177,23 @@ def _coerce_map_from_(self, from_par):
11671177
5.645751311064590?
11681178
sage: AA.has_coerce_map_from(SR)
11691179
False
1180+
1181+
sage: K = NumberField(x^3 - 2, 'a', embedding=2.**(1/3))
1182+
sage: AA.has_coerce_map_from(K)
1183+
True
1184+
sage: K.<s> = QuadraticField(3, embedding=-2.)
1185+
sage: s + AA(1)
1186+
-0.732050807568878?
1187+
sage: K.<s> = QuadraticField(3, embedding=2.)
1188+
sage: s + AA(1)
1189+
2.732050807568878?
1190+
sage: K.<s> = QuadraticField(-5)
1191+
sage: AA.has_coerce_map_from(K)
1192+
False
11701193
"""
1171-
return (from_par is ZZ or from_par is QQ
1172-
or from_par is AA)
1194+
if isinstance(from_par, sage.rings.number_field.number_field_base.NumberField):
1195+
emb = from_par.coerce_embedding()
1196+
return emb is not None and parent_is_real_numerical(emb.codomain())
11731197

11741198
def completion(self, p, prec, extras={}):
11751199
r"""
@@ -1497,9 +1521,15 @@ def __init__(self):
14971521
14981522
sage: QQbar._repr_option('element_is_atomic')
14991523
False
1524+
1525+
sage: QQbar.has_coerce_map_from(ZZ)
1526+
True
1527+
sage: QQbar.has_coerce_map_from(int)
1528+
True
15001529
"""
15011530
from sage.categories.fields import Fields
15021531
AlgebraicField_common.__init__(self, AA, ('I',), normalize=False, category=Fields().Infinite())
1532+
self._populate_coercion_lists_([ZZ, QQ])
15031533

15041534
def _element_constructor_(self, x):
15051535
"""
@@ -1565,17 +1595,28 @@ def _coerce_map_from_(self, from_par):
15651595
15661596
TESTS::
15671597
1568-
sage: QQbar.has_coerce_map_from(ZZ) # indirect doctest
1569-
True
15701598
sage: QQbar.has_coerce_map_from(AA)
15711599
True
15721600
sage: QQbar.has_coerce_map_from(CC)
15731601
False
15741602
sage: QQbar.has_coerce_map_from(SR)
15751603
False
1604+
1605+
sage: i + QQbar(2)
1606+
I + 2
1607+
sage: K.<ii> = QuadraticField(-1, embedding=ComplexField(13)(0,-1))
1608+
sage: ii + QQbar(2)
1609+
-I + 2
1610+
1611+
sage: L.<a> = QuadraticField(-1, embedding=Zp(5).teichmuller(2))
1612+
sage: QQbar.has_coerce_map_from(L)
1613+
False
15761614
"""
1577-
return (from_par is ZZ or from_par is QQ
1578-
or from_par is AA or from_par is QQbar)
1615+
if from_par is AA:
1616+
return True
1617+
if isinstance(from_par, sage.rings.number_field.number_field_base.NumberField):
1618+
emb = from_par.coerce_embedding()
1619+
return emb is not None and parent_is_numerical(emb.codomain())
15791620

15801621
def completion(self, p, prec, extras={}):
15811622
r"""
@@ -3453,10 +3494,11 @@ def __init__(self, parent, x):
34533494
self._descr = ANRational(x)
34543495
elif isinstance(x, ANDescr):
34553496
self._descr = x
3456-
elif parent is QQbar and \
3457-
isinstance(x, NumberFieldElement_quadratic) and \
3458-
list(x.parent().polynomial()) == [1, 0, 1]:
3459-
self._descr = ANExtensionElement(QQbar_I_generator, QQbar_I_nf(x.list()))
3497+
elif parent is QQbar and isinstance(x, NumberFieldElement_gaussian):
3498+
if x.parent()._standard_embedding:
3499+
self._descr = ANExtensionElement(QQbar_I_generator, QQbar_I_nf(x.list()))
3500+
else:
3501+
self._descr = ANExtensionElement(QQbar_I_generator, QQbar_I_nf([x[0], -x[1]]))
34603502
else:
34613503
raise TypeError("Illegal initializer for algebraic number")
34623504

src/sage/symbolic/expression.pyx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3150,13 +3150,6 @@ cdef class Expression(CommutativeRingElement):
31503150
sage: bool(f(x) - f(x) == 0)
31513151
True
31523152
3153-
Check that we catch exceptions from Pynac (:trac:`19904`)::
3154-
3155-
sage: bool(SR(QQbar(I)) == I)
3156-
Traceback (most recent call last):
3157-
...
3158-
TypeError: unsupported operand parent(s)...
3159-
31603153
Check that :trac:`24658` is fixed::
31613154
31623155
sage: val = pi - 2286635172367940241408/1029347477390786609545*sqrt(2)

0 commit comments

Comments
 (0)