From 315ddc2abef7b9ffb47909d14b29f874058caabd Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 25 Nov 2020 17:51:18 +0100 Subject: [PATCH] #15114 remove coercions from RR, RDF, float to RIF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mainly because it makes it hard to use interval arithmetic reliably. See the discussion on the trac ticket for details. Note that RR → RIF is currently an exception among interval fields: there are no coercions CC → CIF, RR → RBF, RR → CBF, or CC → CBF. There are, however, coercions CC → SR and SR → CIF, but the bug here is the existence of the latter, not that their composition is not defined. fixR --- src/sage/categories/pushout.py | 12 ++---- src/sage/rings/real_mpfi.pyx | 71 ++++++++++++++-------------------- 2 files changed, 34 insertions(+), 49 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 2d4eb607f6b..e270892257f 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2542,14 +2542,10 @@ def merge(self, other): We check that :trac:`12353` has been resolved:: - sage: RealIntervalField(53)(-1) > RR(1) - False - sage: RealIntervalField(54)(-1) > RR(1) - False - sage: RealIntervalField(54)(1) > RR(-1) - True - sage: RealIntervalField(53)(1) > RR(-1) - True + sage: RIF(1) > RR(1) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for >: 'Real Interval Field with 53 bits of precision' and 'Real Field with 53 bits of precision' We check that various pushouts work:: diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 24c652f9958..47dfd58e1ae 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -115,7 +115,7 @@ satisfying, but we have chosen the latter. sage: a = R(1.25) sage: a.str(style='brackets') '[1.2 .. 1.3]' - sage: a == 1.25 + sage: a == 5/4 True sage: a == 2 False @@ -228,21 +228,17 @@ specified if given a non-interval and an interval:: sage: val.overlaps(ref) # known bug False -TESTS: - -Comparisons with numpy types are right (see :trac:`17758` and :trac:`18076`):: +TESTS:: sage: import numpy - sage: RIF(0,1) < numpy.float('2') - True - sage: RIF(0,1) <= numpy.float('1') - True - sage: RIF(0,1) <= numpy.float('0.5') - False sage: RIF(2) == numpy.int8('2') True sage: numpy.int8('2') == RIF(2) True + sage: RIF(0,1) < numpy.float('2') + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for <: ... """ # **************************************************************************** @@ -759,14 +755,11 @@ cdef class RealIntervalField_class(Field): - this mpfi field itself - - any mpfr real field with precision that is as large as this - one - - any other mpfi real field with precision that is as large as this one - - anything that canonically coerces to the mpfr real field - with same precision as ``self``. + - some exact or lazy parents representing subsets of the real + numbers, such as ``ZZ``, ``QQ``, ``AA``, and ``RLF``. Values which can be exactly represented as a floating-point number are coerced to a precise interval, with upper and lower bounds @@ -781,12 +774,13 @@ cdef class RealIntervalField_class(Field): To: Real Interval Field with 53 bits of precision sage: phi(3^100) 5.153775207320114?e47 - sage: phi = RIF.coerce_map_from(float); phi - Coercion map: - From: Set of Python objects of class 'float' + + :: + + sage: phi = RIF.coerce_map_from(AA); phi + Conversion via _real_mpfi_ method map: + From: Algebraic Real Field To: Real Interval Field with 53 bits of precision - sage: phi(math.pi) - 3.1415926535897932? Coercion can decrease precision, but not increase it:: @@ -794,35 +788,29 @@ cdef class RealIntervalField_class(Field): Coercion map: From: Real Interval Field with 100 bits of precision To: Real Interval Field with 53 bits of precision - sage: phi = RIF.coerce_map_from(RealField(100)); phi - Coercion map: - From: Real Field with 100 bits of precision - To: Real Interval Field with 53 bits of precision sage: print(RIF.coerce_map_from(RealIntervalField(20))) None - sage: print(RIF.coerce_map_from(RealField(20))) - None - :: + There are no coercions from plain floating-point numbers to intervals + (otherwise the rounding errors resulting from floating-point operations + could easily lead to incorrect interval results):: - sage: phi = RIF.coerce_map_from(AA); phi - Conversion via _real_mpfi_ method map: - From: Algebraic Real Field - To: Real Interval Field with 53 bits of precision + sage: RIF.has_coerce_map_from(RR) + False + sage: RIF.has_coerce_map_from(RDF) + False + sage: RIF.has_coerce_map_from(float) + False """ prec = self.__prec # Direct and efficient conversions if S is ZZ or S is QQ: return True - if S is float or S is int or S is long: + if S is int or S is long: return True if isinstance(S, RealIntervalField_class): return (S).__prec >= prec - if isinstance(S, RealField_class): - return (S).__prec >= prec - if S is RDF: - return 53 >= prec from .number_field.number_field import NumberField_quadratic if isinstance(S, NumberField_quadratic): return S.discriminant() > 0 @@ -2550,7 +2538,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: I = RIF(e, pi) sage: a, b = I.bisection() - sage: a.intersection(b) == I.center() + sage: a.intersection(b) == RIF(I.center()) True sage: a.union(b).endpoints() == I.endpoints() True @@ -4385,7 +4373,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: r = RIF(16.0); r.log10() 1.204119982655925? - sage: r.log() / log(10.0) + sage: r.log() / RIF(10).log() 1.204119982655925? :: @@ -4976,7 +4964,8 @@ cdef class RealIntervalFieldElement(RingElement): -3.54490770181104? sage: gamma(-1/2).n(100) in RIF(-1/2).gamma() True - sage: 0 in (RealField(2000)(-19/3).gamma() - RealIntervalField(1000)(-19/3).gamma()) + sage: RIF1000 = RealIntervalField(1000) + sage: 0 in (RIF1000(RealField(2000)(-19/3).gamma()) - RIF1000(-19/3).gamma()) True sage: gamma(RIF(100)) 9.33262154439442?e155 @@ -5005,7 +4994,7 @@ cdef class RealIntervalFieldElement(RingElement): [-infinity .. +infinity] """ x = self._new() - if self > 1.462: + if self.lower() > 1.462: # increasing mpfr_gamma(&x.value.left, &self.value.left, MPFR_RNDD) mpfr_gamma(&x.value.right, &self.value.right, MPFR_RNDU) @@ -5017,7 +5006,7 @@ cdef class RealIntervalFieldElement(RingElement): elif self.contains_zero(): # [-infinity, infinity] return ~self - elif self < 1.461: + elif self.upper() < 1.461: # 0 < self as well, so decreasing mpfr_gamma(&x.value.left, &self.value.right, MPFR_RNDD) mpfr_gamma(&x.value.right, &self.value.left, MPFR_RNDU)