diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index d0b69be4b50..e52895ffeb8 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -3690,13 +3690,14 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): mpfi_union(x.value, self.value, other_intv.value) return x - def min(self, _other): + def min(self, *_others): """ - Return an interval containing the minimum of ``self`` and ``other``. + Return an interval containing the minimum of ``self`` and the + arguments. EXAMPLES:: - sage: a=RIF(-1, 1).min(0).endpoints() + sage: a = RIF(-1, 1).min(0).endpoints() sage: a[0] == -1.0 and a[1].abs() == 0.0 # in MPFI, the sign of 0.0 is not specified True sage: RIF(-1, 1).min(pi).endpoints() @@ -3705,6 +3706,30 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): (-100.000000000000, 1.00000000000000) sage: RIF(-1, 1).min(RIF(-100, 0)).endpoints() (-100.000000000000, 0.000000000000000) + sage: RIF(-1, 1).min(RIF(-100, 2), RIF(-200, -3)).endpoints() + (-200.000000000000, -3.00000000000000) + + Note that if the minimum is one of the given elements, + that element will be returned. :: + + sage: a = RIF(-1, 1) + sage: b = RIF(2, 3) + sage: c = RIF(3, 4) + sage: c.min(a, b) is a + True + sage: b.min(a, c) is a + True + sage: a.min(b, c) is a + True + + It might also be convenient to call the method as a function:: + + sage: from sage.rings.real_mpfi import RealIntervalFieldElement + sage: RealIntervalFieldElement.min(a, b, c) is a + True + sage: elements = [a, b, c] + sage: RealIntervalFieldElement.min(*elements) is a + True The generic min does not always do the right thing:: @@ -3712,24 +3737,56 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): 0 sage: min(RIF(-1, 1), RIF(-100, 100)).endpoints() (-1.00000000000000, 1.00000000000000) + + .. SEEALSO:: + + :meth:`~sage.rings.real_mpfi.RealIntervalFieldElement.max` + + TESTS:: + + sage: a.min('x') + Traceback (most recent call last): + ... + TypeError: Unable to convert number to real interval. """ + cdef RealIntervalFieldElement constructed + cdef RealIntervalFieldElement result cdef RealIntervalFieldElement other - if isinstance(_other, RealIntervalFieldElement): - other = _other - else: - other = self._parent(_other) - if mpfr_cmp(&self.value.right, &other.value.left) <= 0: - return self - elif mpfr_cmp(&other.value.right, &self.value.left) <= 0: - return other - cdef RealIntervalFieldElement x = self._new() - mpfr_min(&x.value.left, &self.value.left, &other.value.left, GMP_RNDD) - mpfr_min(&x.value.right, &self.value.right, &other.value.right, GMP_RNDU) - return x + cdef bint initialized - def max(self, _other): - """ - Return an interval containing the maximum of ``self`` and ``other``. + initialized = False + result = self + + for _other in _others: + if isinstance(_other, RealIntervalFieldElement): + other = _other + else: + other = self._parent(_other) + + if mpfr_cmp(&result.value.right, &other.value.left) <= 0: + pass + elif mpfr_cmp(&other.value.right, &result.value.left) <= 0: + result = other + else: + if not initialized: + constructed = self._new() + initialized = True + mpfr_min(&constructed.value.left, + &result.value.left, + &other.value.left, + GMP_RNDD) + mpfr_min(&constructed.value.right, + &result.value.right, + &other.value.right, + GMP_RNDU) + result = constructed + + return result + + def max(self, *_others): + """ + Return an interval containing the maximum of ``self`` and the + arguments. EXAMPLES:: @@ -3739,6 +3796,30 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): (2.00000000000000, 3.00000000000000) sage: RIF(-1, 1).max(RIF(-100, 100)).endpoints() (-1.00000000000000, 100.000000000000) + sage: RIF(-1, 1).max(RIF(-100, 100), RIF(5, 10)).endpoints() + (5.00000000000000, 100.000000000000) + + Note that if the maximum is one of the given elements, + that element will be returned. :: + + sage: a = RIF(-1, 1) + sage: b = RIF(2, 3) + sage: c = RIF(3, 4) + sage: c.max(a, b) is c + True + sage: b.max(a, c) is c + True + sage: a.max(b, c) is c + True + + It might also be convenient to call the method as a function:: + + sage: from sage.rings.real_mpfi import RealIntervalFieldElement + sage: RealIntervalFieldElement.max(a, b, c) is c + True + sage: elements = [a, b, c] + sage: RealIntervalFieldElement.max(*elements) is c + True The generic max does not always do the right thing:: @@ -3746,20 +3827,52 @@ cdef class RealIntervalFieldElement(sage.structure.element.RingElement): 0 sage: max(RIF(-1, 1), RIF(-100, 100)).endpoints() (-1.00000000000000, 1.00000000000000) + + .. SEEALSO:: + + :meth:`~sage.rings.real_mpfi.RealIntervalFieldElement.min` + + TESTS:: + + sage: a.max('x') + Traceback (most recent call last): + ... + TypeError: Unable to convert number to real interval. """ + cdef RealIntervalFieldElement constructed + cdef RealIntervalFieldElement result cdef RealIntervalFieldElement other - if isinstance(_other, RealIntervalFieldElement): - other = _other - else: - other = self._parent(_other) - if mpfr_cmp(&self.value.right, &other.value.left) <= 0: - return other - elif mpfr_cmp(&other.value.right, &self.value.left) <= 0: - return self - cdef RealIntervalFieldElement x = self._new() - mpfr_max(&x.value.left, &self.value.left, &other.value.left, GMP_RNDD) - mpfr_max(&x.value.right, &self.value.right, &other.value.right, GMP_RNDU) - return x + cdef bint initialized + + initialized = False + result = self + + for _other in _others: + if isinstance(_other, RealIntervalFieldElement): + other = _other + else: + other = self._parent(_other) + + if mpfr_cmp(&result.value.right, &other.value.left) <= 0: + result = other + elif mpfr_cmp(&other.value.right, &result.value.left) <= 0: + pass + else: + if not initialized: + constructed = self._new() + initialized = True + + mpfr_max(&constructed.value.left, + &result.value.left, + &other.value.left, + GMP_RNDD) + mpfr_max(&constructed.value.right, + &result.value.right, + &other.value.right, + GMP_RNDU) + result = constructed + + return result ############################ # Special Functions @@ -5030,107 +5143,3 @@ def __create__RealIntervalFieldElement_version1(parent, lower, upper): 2.226? """ return RealIntervalFieldElement(parent, (lower, upper)) - -def max_RIF(elements): - r""" - Compute the maximum of - :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` elements. - - INPUT: - - - ``elements`` -- iterable of - :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` elements. - - OUTPUT: - - A :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` element. - - EXAMPLES:: - - sage: a = RIF(1, 4) - sage: b = RIF(2, 3) - sage: from sage.rings.real_mpfi import max_RIF - sage: max_RIF([a, b]).endpoints() - (2.00000000000000, 4.00000000000000) - sage: max_RIF([b, a]).endpoints() - (2.00000000000000, 4.00000000000000) - - For two elements, this corresponds to - :meth:`sage.rings.real_mpfi.RealIntervalFieldElement.max`:: - - sage: a.max(b).endpoints() - (2.00000000000000, 4.00000000000000) - sage: b.max(a).endpoints() - (2.00000000000000, 4.00000000000000) - - Note that the standard Python ``max`` function does not handle - :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` elements - correctly:: - - sage: max(a, b).endpoints() - (1.00000000000000, 4.00000000000000) - sage: max(b, a).endpoints() - (2.00000000000000, 3.00000000000000) - - .. SEEALSO:: - - :meth:`sage.rings.real_mpfi.RealIntervalFieldElement.max`, - :func:`min_RIF` - """ - # we iterate twice, so store as a list. - data = list(elements) - max_upper = max(e.upper() for e in data) - max_lower = max(e.lower() for e in data) - return data[0].parent()(max_lower, max_upper) - -def min_RIF(elements): - r""" - Compute the minimum of - :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` elements. - - INPUT: - - - ``elements`` -- iterable of - :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` elements. - - OUTPUT: - - A :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` element. - - EXAMPLES:: - - sage: a = RIF(1, 4) - sage: b = RIF(2, 3) - sage: from sage.rings.real_mpfi import min_RIF - sage: min_RIF([a, b]).endpoints() - (1.00000000000000, 3.00000000000000) - sage: min_RIF([b, a]).endpoints() - (1.00000000000000, 3.00000000000000) - - For two elements, this corresponds to - :meth:`sage.rings.real_mpfi.RealIntervalFieldElement.min`:: - - sage: a.min(b).endpoints() - (1.00000000000000, 3.00000000000000) - sage: b.min(a).endpoints() - (1.00000000000000, 3.00000000000000) - - Note that the standard Python ``min`` function does not handle - :class:`~sage.rings.real_mpfi.RealIntervalFieldElement` elements - correctly:: - - sage: min(a, b).endpoints() - (1.00000000000000, 4.00000000000000) - sage: min(b, a).endpoints() - (2.00000000000000, 3.00000000000000) - - .. SEEALSO:: - - :meth:`sage.rings.real_mpfi.RealIntervalFieldElement.min`, - :func:`max_RIF` - """ - # we iterate twice, so store as a list. - data = list(elements) - min_upper = min(e.upper() for e in data) - min_lower = min(e.lower() for e in data) - return data[0].parent()(min_lower, min_upper)