Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .github/workflows/ci-meson.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,20 +140,6 @@ jobs:
# Use --no-deps and pip check below to verify that all necessary dependencies are installed via conda
pip install --no-build-isolation --no-deps --config-settings=builddir=builddir ${{ matrix.editable && '--editable' || '' }} . -v

- name: Check update-meson
# this step must be after build, because meson.build creates a number of __init__.py files
# that is needed to make tools/update-meson.py run correctly
shell: bash -l {0}
if: matrix.tests == 'all' && matrix.python == '3.12'
run: |
python tools/update-meson.py
if ! ./tools/test-git-no-uncommitted-changes; then
git add --intent-to-add . # also show newly created files in git diff
git status
git diff
false
fi

- name: Verify dependencies
shell: bash -l {0}
run: pip check
Expand Down
2 changes: 1 addition & 1 deletion build/pkgs/sagelib/dependencies
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) meson_python $(PYTHON) pythran
FORCE $(SCRIPTS) boost_cropped $(BLAS) brial cliquer cypari cysignals cython ecl eclib ecm flint libgd gap givaro glpk gmpy2 gsl iml importlib_metadata importlib_resources jupyter_core lcalc lrcalc_python libbraiding libhomfly libpng linbox m4ri m4rie memory_allocator mpc mpfi mpfr $(MP_LIBRARY) mpmath ntl numpy pari pip pkgconfig planarity ppl pplpy primesieve primecount primecountpy $(PYTHON) requests rw singular symmetrica typing_extensions $(PCFILES) | $(PYTHON_TOOLCHAIN) meson_python $(PYTHON) pythran

----------
All lines of this file are ignored except the first.
Expand Down
5 changes: 3 additions & 2 deletions src/sage/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,9 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st
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", "")
Expand Down
39 changes: 39 additions & 0 deletions src/sage/features/mpmath13.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
r"""
Feature for test for mpmath-1.3.x. Used to simultaneously
support v1.3 and v1.4 in the doctests.
"""
from . import Feature


class MpMath13(Feature):
r"""
A :class:`~sage.features.Feature`.

EXAMPLES::

sage: from sage.features.mpmath13 import MpMath13
sage: MpMath13()
Feature('mpmath13')
sage: MpMath13() is MpMath13()
True
"""
def __init__(self):
Feature.__init__(self, 'mpmath13')

def _is_present(self):
r"""
Test the mpmath version.

EXAMPLES::

sage: from sage.features.mpmath13 import MpMath13
sage: MpMath()._is_present() # needs mpmath13
FeatureTestResult('mpmath13', True)

"""
from mpmath import __version__ as mpmath_version
return mpmath_version.startswith("1.3")


def all_features():
return [MpMath13()]
1 change: 1 addition & 0 deletions src/sage/libs/mpmath/ext_impl.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# sage.doctest: needs sage.libs.mpmath13
"""
This module provides the core implementation of multiprecision
floating-point arithmetic. Operations are done in-place.
Expand Down
1 change: 1 addition & 0 deletions src/sage/libs/mpmath/ext_libmp.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# sage.doctest: needs sage.libs.mpmath13
"""
Faster versions of some key functions in mpmath.libmp
"""
Expand Down
1 change: 1 addition & 0 deletions src/sage/libs/mpmath/ext_main.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# sage.doctest: needs sage.libs.mpmath13
"""
mpmath floating-point numbers

Expand Down
94 changes: 66 additions & 28 deletions src/sage/libs/mpmath/meson.build
Original file line number Diff line number Diff line change
@@ -1,31 +1,69 @@
py.install_sources(
'__init__.py',
'all.py',
'ext_impl.pxd',
'ext_impl.pyx',
'ext_libmp.pyx',
'ext_main.pxd',
'ext_main.pyx',
'utils.pxd',
'utils.pyx',
subdir: 'sage/libs/mpmath',
)

extension_data = {
'ext_impl' : files('ext_impl.pyx'),
'ext_libmp' : files('ext_libmp.pyx'),
'ext_main' : files('ext_main.pyx'),
'utils' : files('utils.pyx'),
}

foreach name, pyx : extension_data
py.extension_module(
name,
sources: pyx,
# Determine the mpmath version at build time so that we can support
# both 1.3 and 1.4 simultaneously (for a while).
mpmath14 = run_command(
py, [
'-c',
'import mpmath; print(mpmath.__version__);'
],
check: true,
).stdout().strip().startswith('1.4')


if mpmath14
py.install_sources(
'__init__.py',
'all.py',
'utils.pxd',
'utils.pyx',
subdir: 'sage/libs/mpmath',
install: true,
include_directories: [inc_cpython, inc_ext, inc_rings],
dependencies: [py_dep, cysignals, gmp, mpfr],
)
endforeach

extension_data = {
'utils' : files('utils.pyx'),
}

foreach name, pyx : extension_data
py.extension_module(
name,
sources: pyx,
subdir: 'sage/libs/mpmath',
install: true,
include_directories: [inc_cpython, inc_ext, inc_rings],
dependencies: [py_dep, cysignals, gmp, gmpy2, mpfr],
)
endforeach

else
# mpmath-1.3.x
py.install_sources(
'__init__.py',
'all.py',
'ext_impl.pxd',
'ext_impl.pyx',
'ext_libmp.pyx',
'ext_main.pxd',
'ext_main.pyx',
'utils.pxd',
'utils13.pyx',
subdir: 'sage/libs/mpmath',
)

extension_data = {
'ext_impl' : files('ext_impl.pyx'),
'ext_libmp' : files('ext_libmp.pyx'),
'ext_main' : files('ext_main.pyx'),
'utils' : files('utils13.pyx'),
}

foreach name, pyx : extension_data
py.extension_module(
name,
sources: pyx,
subdir: 'sage/libs/mpmath',
install: true,
include_directories: [inc_cpython, inc_ext, inc_rings],
dependencies: [py_dep, cysignals, gmp, mpfr],
)
endforeach

endif
154 changes: 8 additions & 146 deletions src/sage/libs/mpmath/utils.pyx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -16,157 +16,19 @@ 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 = <Integer>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 = <Integer>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.

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)
gmpy2.import_gmpy2()

cdef mpfr_from_mpfval(mpfr_t res, tuple x):
"""
Set value of an MPFR number (in place) to that of a given mpmath mpf
data tuple.
"""
cdef int sign
cdef Integer man
cdef gmpy2.mpz man
cdef long exp
sign, man, exp, _ = 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)
Expand Down Expand Up @@ -210,7 +72,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):
Expand Down Expand Up @@ -305,7 +167,7 @@ def sage_to_mpmath(x, prec):
sage: print(a.sage_to_mpmath(1+pi, 53))
4.14159265358979
sage: a.sage_to_mpmath(infinity, 53)
mpf('+inf')
mpf('inf')
sage: a.sage_to_mpmath(-infinity, 53)
mpf('-inf')
sage: a.sage_to_mpmath(NaN, 53)
Expand Down Expand Up @@ -413,7 +275,7 @@ def call(func, *args, **kwargs):

Check that :issue:`11885` is fixed::

sage: a.call(a.ei, 1.0r, parent=float)
sage: a.call(a.ei, 1.0r, parent=float) # abs tol 1e-15
1.8951178163559366

Check that :issue:`14984` is fixed::
Expand Down
Loading
Loading