为什么安装 sagemath 会提高 python 中 mpmath 的性能?

Why does installing sagemath improve the performance of mpmath in python?

我注意到 mpmath 的性能,听起来很奇怪,取决于是否安装了 sagemath,而不管 sage 模块是否在当前会话中加载。特别是,我在使用多个精度浮点数的操作中遇到了这种情况。

示例:

from mpmath import mp
import time
mp.prec = 650

t = time.time()
for i in range(1000000):
    x_mpmath + y_mpmath
w = time.time()
print('plus:\t', (w-t), 'μs')
t = time.time()
for i in range(1000000):
    x_mpmath * y_mpmath
w = time.time()
print('times:\t', (w-t), 'μs')

# If sagemath is installed:
# plus:  0.12919950485229492 μs
# times: 0.17601895332336426 μs
#
# If sagemath is *not* installed:
# plus:  0.6239776611328125 μs
# times: 0.6283771991729736 μs

虽然在这两种情况下,模块 mpmath 完全相同

import mpmath
print(mpmath.__file__)
# /usr/lib/python3.9/site-packages/mpmath/__init__.py

我认为 mpmath 的后端将依赖于某些 sagemath 依赖项,如果缺少它,它会退回到优化程度较低的后端,但我无法弄清楚它到底是什么。我的目标是能够只安装所需的包来加速 mpmath,而不是安装所有的 sagemath。

因为这很可能取决于事物的打包方式,您可能需要了解我的系统的详细信息:我正在使用 Arch Linux 并且所有包都已更新到最新版本(sagemath 9.3 , mpmath 1.2.1, python 3.9.5).

我找到了解释。在第 82 行的 /usr/lib/python3.9/site-packages/mpmath/libmp/backend.py 中有

if 'MPMATH_NOSAGE' not in os.environ:
    try:
        import sage.all
        import sage.libs.mpmath.utils as _sage_utils
        sage = sage.all
        sage_utils = _sage_utils
        BACKEND = 'sage'
        MPZ = sage.Integer
    except:
        pass

如果安装了 sagemath,这将加载所有 sage,并将其设置为后端。这意味着接下来将加载以下库:

        import sage.libs.mpmath.ext_libmp as ext_lib

来自 /usr/lib/python3.9/site-packages/mpmath/libmp/libmpf.py 第 1407 行。通过查看该模块的 __file__,可以看到它是一个 .so 对象,因此编译速度更快。

这也意味着通过将 MPMATH_NOSAGE 导出到任何非空值将强制后端成为默认值(python 或 gmpy)并且我确实可以确认我在在这种情况下,问题 运行 变慢了,即使安装了 sagemath。