数值计算#
象SymPy这样的符号计算机代数系统有助于构造和操作数学表达式。不幸的是,当需要在数值数据上计算这些表达式时,符号系统的性能往往很差。
Fortunately SymPy offers a number of easy-to-use hooks into other numeric
systems, allowing you to create mathematical expressions in SymPy and then
ship them off to the numeric system of your choice. This page documents many
of the options available including the math
library, the popular array
computing package numpy
, code generation in Fortran
or C
, and the
use of the array compiler Aesara
.
潜艇/救生艇#
潜艇是最慢但最简单的选择。它以相同的速度运行。这个 .subs(...).evalf()
方法可以用数值替换符号值,然后在SymPy中计算结果。
>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> expr.evalf(subs={x: 3.14})
0.000507214304613640
这种方法很慢。只有在性能不是问题时才应使用此方法生成。你可以期待 .subs
需要几十微秒。它可以在原型制作时很有用,或者如果您只想看到一个值一次。
兰姆迪菲#
这个 lambdify
函数将SymPy表达式转换为Python函数,利用各种数值库。其用途如下:
>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> f = lambdify(x, expr)
>>> f(3.14)
0.000507214304614
这里lambdify生成了一个函数 f(x) = sin(x)/x
. 默认情况下,lambdify依赖于 math
标准库。这个数值计算需要几百纳秒,大约比 .subs
方法。这就是SymPy和原始Python之间的速度差异。
Lambdify可以利用各种数字后端。默认情况下,它使用 math
类库。但是它也支持 mpmath
最值得注意的是, numpy
. 使用 numpy
库使生成的函数可以访问由编译的C代码支持的强大的矢量化ufunc。
>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> f = lambdify(x, expr, "numpy")
>>> import numpy
>>> data = numpy.linspace(1, 10, 10000)
>>> f(data)
[ 0.84147098 0.84119981 0.84092844 ... -0.05426074 -0.05433146
-0.05440211]
如果你有基于数组的数据,这可以提供相当大的加速,每一个元素10纳秒。不幸的是,numpy需要一些启动时间,并引入了几微秒的开销。
CuPy is a NumPy-compatible array library that mainly runs on CUDA, but has increasing support for other GPU manufacturers. It can in many cases be used as a drop-in replacement for numpy.
>>> f = lambdify(x, expr, "cupy")
>>> import cupy as cp
>>> data = cp.linspace(1, 10, 10000)
>>> y = f(data) # perform the computation
>>> cp.asnumpy(y) # explicitly copy from GPU to CPU / numpy array
[ 0.84147098 0.84119981 0.84092844 ... -0.05426074 -0.05433146
-0.05440211]
JAX is a similar alternative to CuPy that provides GPU and TPU acceleration via just-in-time compilation to XLA. It too, can in some cases, be used as a drop-in replacement for numpy.
>>> f = lambdify(x, expr, "jax")
>>> import jax.numpy as jnp
>>> data = jnp.linspace(1, 10, 10000)
>>> y = f(data) # perform the computation
>>> numpy.asarray(y) # explicitly copy to CPU / numpy array
array([ 0.84147096, 0.8411998 , 0.84092844, ..., -0.05426079,
-0.05433151, -0.05440211], dtype=float32)
乌芬奇#
这个 autowrap
帮助中包含高效计算的模块。
binary_function 方法自动执行自动包装SymPy表达式并将其附加到
Function
对象与implemented_function()
.ufuncify 生成一个二进制函数,该函数支持在numpy数组上使用比
subs/evalf
和lambdify
.
以上所有API参考如下: sympy.utilities.autowrap()
.
Aesara#
SymPy has a strong connection with Aesara, a mathematical array compiler. SymPy expressions can be easily translated to Aesara graphs and then compiled using the Aesara compiler chain.
>>> from sympy import *
>>> from sympy.abc import x
>>> expr = sin(x)/x
>>> from sympy.printing.aesaracode import aesara_function
>>> f = aesara_function([x], [expr])
If array broadcasting or types are desired then Aesara requires this extra information
>>> f = aesara_function([x], [expr], dims={x: 1}, dtypes={x: 'float64'})
Aesara has a more sophisticated code generation system than SymPy's C/Fortran code printers. Among other things it handles common sub-expressions and compilation onto the GPU. Aesara also supports SymPy Matrix and Matrix Expression objects.
那我该用哪一个呢?#
The options here were listed in order from slowest and least dependencies to
fastest and most dependencies. For example, if you have Aesara installed then
that will often be the best choice. If you don't have Aesara but do have
f2py
then you should use ufuncify
. If you have been comfortable using
lambdify with the numpy module, but have a GPU, CuPy and JAX can provide substantial
speedups with little effort.
工具 |
速度 |
品质 |
依赖关系 |
---|---|---|---|
潜艇/救生艇 |
50美元 |
简单的 |
没有 |
兰姆迪菲 |
1美国 |
标量型函数 |
数学 |
小羔羊 |
10纳秒 |
向量函数 |
numpy |
乌芬奇 |
10纳秒 |
复向量表达式 |
f2py,赛顿 |
lambdify-cupy |
10纳秒 |
Vector functions on GPUs |
cupy |
lambdify-jax |
10纳秒 |
Vector functions on CPUs, GPUs and TPUs |
jax |
Aesara |
10纳秒 |
多输出,CSE,GPU |
Aesara |