diff --git a/sci-mathematics/sagemath-standard/files/mpmath.patch b/sci-mathematics/sagemath-standard/files/mpmath.patch new file mode 100644 index 000000000..d45cc5549 --- /dev/null +++ b/sci-mathematics/sagemath-standard/files/mpmath.patch @@ -0,0 +1,333 @@ +diff --git a/sage/env.py b/sage/env.py +index 3548c65f43e..d6b6218d7b6 100644 +--- a/sage/env.py ++++ b/sage/env.py +@@ -245,8 +245,9 @@ SINGULAR_BIN = var("SINGULAR_BIN") or "Singular" + OPENMP_CFLAGS = var("OPENMP_CFLAGS", "") + OPENMP_CXXFLAGS = var("OPENMP_CXXFLAGS", "") + +-# Make sure mpmath uses Sage types +-os.environ['MPMATH_SAGE'] = '1' ++# Make sure that mpmath < 1.4 does not try to use Sage types ++os.environ.pop('MPMATH_SAGE', None) ++os.environ['MPMATH_NOSAGE'] = '1' + + # misc + SAGE_BANNER = var("SAGE_BANNER", "") +diff --git a/sage/libs/mpmath/utils.pyx b/sage/libs/mpmath/utils.pyx +index 0123d4190be..0f451e18f65 100644 +--- a/sage/libs/mpmath/utils.pyx ++++ b/sage/libs/mpmath/utils.pyx +@@ -1,9 +1,9 @@ + """ + Utilities for Sage-mpmath interaction +- +-Also patches some mpmath functions for speed + """ + ++cimport gmpy2 ++ + from sage.ext.stdsage cimport PY_NEW + + from sage.rings.integer cimport Integer +@@ -16,141 +16,8 @@ from sage.libs.gmp.all cimport * + + from sage.rings.real_mpfr cimport RealField + +-cpdef int bitcount(n) noexcept: +- """ +- Bitcount of a Sage Integer or Python int/long. +- +- EXAMPLES:: +- +- sage: from mpmath.libmp import bitcount +- sage: bitcount(0) +- 0 +- sage: bitcount(1) +- 1 +- sage: bitcount(100) +- 7 +- sage: bitcount(-100) +- 7 +- sage: bitcount(2r) +- 2 +- sage: bitcount(2L) +- 2 +- """ +- cdef Integer m +- if isinstance(n, Integer): +- m = n +- else: +- m = Integer(n) +- if mpz_sgn(m.value) == 0: +- return 0 +- return mpz_sizeinbase(m.value, 2) +- +-cpdef isqrt(n): +- """ +- Square root (rounded to floor) of a Sage Integer or Python int/long. +- The result is a Sage Integer. +- +- EXAMPLES:: +- +- sage: from mpmath.libmp import isqrt +- sage: isqrt(0) +- 0 +- sage: isqrt(100) +- 10 +- sage: isqrt(10) +- 3 +- sage: isqrt(10r) +- 3 +- sage: isqrt(10L) +- 3 +- """ +- cdef Integer m, y +- if isinstance(n, Integer): +- m = n +- else: +- m = Integer(n) +- if mpz_sgn(m.value) < 0: +- raise ValueError("square root of negative integer not defined.") +- y = PY_NEW(Integer) +- mpz_sqrt(y.value, m.value) +- return y +- +-cpdef from_man_exp(man, exp, long prec = 0, str rnd = 'd'): +- """ +- Create normalized mpf value tuple from mantissa and exponent. +- +- With prec > 0, rounds the result in the desired direction +- if necessary. ++gmpy2.import_gmpy2() + +- EXAMPLES:: +- +- sage: from mpmath.libmp import from_man_exp +- sage: from_man_exp(-6, -1) +- (1, 3, 0, 2) +- sage: from_man_exp(-6, -1, 1, 'd') +- (1, 1, 1, 1) +- sage: from_man_exp(-6, -1, 1, 'u') +- (1, 1, 2, 1) +- """ +- cdef Integer res +- cdef long bc +- res = Integer(man) +- bc = mpz_sizeinbase(res.value, 2) +- if not prec: +- prec = bc +- if mpz_sgn(res.value) < 0: +- mpz_neg(res.value, res.value) +- return normalize(1, res, exp, bc, prec, rnd) +- else: +- return normalize(0, res, exp, bc, prec, rnd) +- +-cpdef normalize(long sign, Integer man, exp, long bc, long prec, str rnd): +- """ +- Create normalized mpf value tuple from full list of components. +- +- EXAMPLES:: +- +- sage: from mpmath.libmp import normalize +- sage: normalize(0, 4, 5, 3, 53, 'n') +- (0, 1, 7, 1) +- """ +- cdef long shift +- cdef Integer res +- cdef unsigned long trail +- if mpz_sgn(man.value) == 0: +- from mpmath.libmp import fzero +- return fzero +- if bc <= prec and mpz_odd_p(man.value): +- return (sign, man, exp, bc) +- shift = bc - prec +- res = PY_NEW(Integer) +- if shift > 0: +- if rnd == 'n': +- if mpz_tstbit(man.value, shift-1) and (mpz_tstbit(man.value, shift) +- or (mpz_scan1(man.value, 0) < (shift-1))): +- mpz_cdiv_q_2exp(res.value, man.value, shift) +- else: +- mpz_fdiv_q_2exp(res.value, man.value, shift) +- elif rnd == 'd': +- mpz_fdiv_q_2exp(res.value, man.value, shift) +- elif rnd == 'f': +- if sign: mpz_cdiv_q_2exp(res.value, man.value, shift) +- else: mpz_fdiv_q_2exp(res.value, man.value, shift) +- elif rnd == 'c': +- if sign: mpz_fdiv_q_2exp(res.value, man.value, shift) +- else: mpz_cdiv_q_2exp(res.value, man.value, shift) +- elif rnd == 'u': +- mpz_cdiv_q_2exp(res.value, man.value, shift) +- exp += shift +- else: +- mpz_set(res.value, man.value) +- # Strip trailing bits +- trail = mpz_scan1(res.value, 0) +- if 0 < trail < bc: +- mpz_tdiv_q_2exp(res.value, res.value, trail) +- exp += trail +- bc = mpz_sizeinbase(res.value, 2) +- return (sign, res, int(exp), bc) + + cdef mpfr_from_mpfval(mpfr_t res, tuple x): + """ +@@ -158,12 +25,12 @@ cdef mpfr_from_mpfval(mpfr_t res, tuple x): + data tuple. + """ + cdef int sign +- cdef Integer man ++ cdef gmpy2.mpz man + cdef long exp + cdef long bc + sign, man, exp, bc = x + if man: +- mpfr_set_z(res, man.value, MPFR_RNDZ) ++ mpfr_set_z(res, man.z, MPFR_RNDZ) + if sign: + mpfr_neg(res, res, MPFR_RNDZ) + mpfr_mul_2si(res, res, exp, MPFR_RNDZ) +@@ -207,7 +74,7 @@ cdef mpfr_to_mpfval(mpfr_t value): + mpz_tdiv_q_2exp(man.value, man.value, trailing) + exp += trailing + bc = mpz_sizeinbase(man.value, 2) +- return (sign, man, int(exp), bc) ++ return (sign, man.__mpz__(), int(exp), bc) + + + def mpmath_to_sage(x, prec): +@@ -412,7 +279,7 @@ def call(func, *args, **kwargs): + Check that :issue:`11885` is fixed:: + + sage: a.call(a.ei, 1.0r, parent=float) +- 1.8951178163559366 ++ 1.8951178163559368 + + Check that :issue:`14984` is fixed:: + +diff --git a/sage/rings/real_mpfr.pyx b/sage/rings/real_mpfr.pyx +index 7e1ab748b55..4a332e6fb5d 100644 +--- a/sage/rings/real_mpfr.pyx ++++ b/sage/rings/real_mpfr.pyx +@@ -150,8 +150,6 @@ from sage.structure.richcmp cimport rich_to_bool_sgn + cdef bin_op + from sage.structure.element import bin_op + +-from sage.libs.mpmath.utils cimport mpfr_to_mpfval +- + from sage.rings.integer cimport Integer + from sage.rings.rational cimport Rational + from sage.rings.real_double cimport RealDoubleElement +diff --git a/sage/structure/coerce.pyx b/sage/structure/coerce.pyx +index cc15eff82e9..79d5ecb74e0 100644 +--- a/sage/structure/coerce.pyx ++++ b/sage/structure/coerce.pyx +@@ -144,6 +144,13 @@ cpdef py_scalar_parent(py_type): + Real Double Field + sage: py_scalar_parent(gmpy2.mpc) # needs sage.rings.complex_double + Complex Double Field ++ ++ sage: # needs mpmath ++ sage: import mpmath ++ sage: py_scalar_parent(mpmath.mpf) ++ Real Double Field ++ sage: py_scalar_parent(mpmath.mpc) # needs sage.rings.complex_double ++ Complex Double Field + """ + if issubclass(py_type, int): + import sage.rings.integer_ring +@@ -151,39 +158,46 @@ cpdef py_scalar_parent(py_type): + if py_type is FractionType: + import sage.rings.rational_field + return sage.rings.rational_field.QQ +- elif issubclass(py_type, float): ++ if issubclass(py_type, float): + import sage.rings.real_double + return sage.rings.real_double.RDF +- elif issubclass(py_type, complex): ++ if issubclass(py_type, complex): + import sage.rings.complex_double + return sage.rings.complex_double.CDF +- elif is_numpy_type(py_type): ++ if is_numpy_type(py_type): + import numpy + if issubclass(py_type, numpy.integer): + import sage.rings.integer_ring + return sage.rings.integer_ring.ZZ +- elif issubclass(py_type, numpy.floating): ++ if issubclass(py_type, numpy.floating): + import sage.rings.real_double + return sage.rings.real_double.RDF +- elif issubclass(py_type, numpy.complexfloating): ++ if issubclass(py_type, numpy.complexfloating): + import sage.rings.complex_double + return sage.rings.complex_double.CDF +- else: +- return None +- elif issubclass(py_type, gmpy2.mpz): ++ return None ++ if issubclass(py_type, gmpy2.mpz): + import sage.rings.integer_ring + return sage.rings.integer_ring.ZZ +- elif issubclass(py_type, gmpy2.mpq): ++ if issubclass(py_type, gmpy2.mpq): + import sage.rings.rational_field + return sage.rings.rational_field.QQ +- elif issubclass(py_type, gmpy2.mpfr): ++ if issubclass(py_type, gmpy2.mpfr): + import sage.rings.real_double + return sage.rings.real_double.RDF +- elif issubclass(py_type, gmpy2.mpc): ++ if issubclass(py_type, gmpy2.mpc): + import sage.rings.complex_double + return sage.rings.complex_double.CDF +- else: ++ if is_mpmath_type(py_type): ++ import mpmath ++ if issubclass(py_type, mpmath.mpf): ++ from sage.rings.real_double import RDF ++ return RDF ++ if issubclass(py_type, mpmath.mpc): ++ from sage.rings.complex_double import CDF ++ return CDF + return None ++ return None + + cpdef py_scalar_to_element(x): + """ +@@ -469,10 +483,10 @@ cpdef bint is_numpy_type(t) noexcept: + return True + return False + ++ + cpdef bint is_mpmath_type(t) noexcept: + r""" +- Check whether the type ``t`` is a type whose name starts with either +- ``mpmath.`` or ``sage.libs.mpmath.``. ++ Check whether the type ``t`` is a type whose name starts with ``mpmath.`` + + EXAMPLES:: + +@@ -489,7 +503,7 @@ cpdef bint is_mpmath_type(t) noexcept: + True + """ + return isinstance(t, type) and \ +- strncmp((t).tp_name, "sage.libs.mpmath.", 17) == 0 ++ t.__module__.startswith("mpmath.") + + + cdef class CoercionModel: +diff --git a/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py b/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +index bf0bb747282..9e7597eba9d 100644 +--- a/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py ++++ b/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +@@ -151,7 +151,7 @@ Sage example in ./integration.tex, line 846:: + sage: mpmath.quad(f, [0, 1]) + Traceback (most recent call last): + ... +- TypeError: no canonical coercion from to ... ++ TypeError: no canonical coercion from to ... + + Sage example in ./integration.tex, line 866:: + diff --git a/sci-mathematics/sagemath-standard/sagemath-standard-9999.ebuild b/sci-mathematics/sagemath-standard/sagemath-standard-9999.ebuild index 1c0f09648..18de29f0e 100644 --- a/sci-mathematics/sagemath-standard/sagemath-standard-9999.ebuild +++ b/sci-mathematics/sagemath-standard/sagemath-standard-9999.ebuild @@ -7,10 +7,6 @@ PYTHON_COMPAT=( python3_{10..12} ) PYTHON_REQ_USE="readline,sqlite" DISTUTILS_USE_PEP517=setuptools DISTUTILS_EXT=1 -# 38113 mpmath 1.4 support -# GIT_PRS=( -# 38113 -# ) inherit desktop distutils-r1 multiprocessing sage-git-patch toolchain-funcs @@ -145,6 +141,7 @@ REQUIRED_USE="doc? ( jmol ) PATCHES=( "${FILESDIR}"/gap-4.13.1_b.patch + "${FILESDIR}"/mpmath.patch "${FILESDIR}"/${PN}-10.4-env.patch "${FILESDIR}"/sage_exec-9.3.patch "${FILESDIR}"/${PN}-10.4b-neutering.patch @@ -158,6 +155,14 @@ pkg_setup() { python_prepare_all() { distutils-r1_python_prepare_all + # delete mpmath files. This saves a lot of patch space + rm -r \ + sage/libs/mpmath/ext_impl.pxd \ + sage/libs/mpmath/ext_impl.pyx \ + sage/libs/mpmath/ext_libmp.pyx \ + sage/libs/mpmath/ext_main.pxd \ + sage/libs/mpmath/ext_main.pyx + # use installed copy, not the vendored one. rm -rf sage_setup