Lambdify¶
此模块提供了方便的函数,用于将 SymPy 表达式转换为可以用于快速计算数值的 lambda 函数。
- sympy.utilities.lambdify.implemented_function(symfunc, implementation)[源代码][源代码]¶
将数值
implementation
添加到函数symfunc
中。symfunc
可以是一个UndefinedFunction
实例,或者是一个名称字符串。在后一种情况下,我们用该名称创建一个UndefinedFunction
实例。请注意,这是一个快速的权宜之计,而不是创建特殊符号函数的一般方法。如果你想创建一个符号函数供SymPy的所有机制使用,你应该子类化
Function
类。- 参数:
- symfunc :
str
或UndefinedFunction
实例str 或 UndefinedFunction 实例 如果
str
,则使用此名称创建新的UndefinedFunction
。如果symfunc
是一个未定义的函数,则创建一个具有相同名称并附加了实现函数的新函数。- 实现可调用
通过
evalf()
或lambdify
调用的数值实现
- symfunc :
- 返回:
- afuncsympy.FunctionClass 实例
带有附加实现的函数
示例
>>> from sympy.abc import x >>> from sympy.utilities.lambdify import implemented_function >>> from sympy import lambdify >>> f = implemented_function('f', lambda x: x+1) >>> lam_f = lambdify(x, f(x)) >>> lam_f(4) 5
- sympy.utilities.lambdify.lambdastr(args, expr, printer=None, dummify=None)[源代码][源代码]¶
返回一个可以被评估为 lambda 函数的字符串。
示例
>>> from sympy.abc import x, y, z >>> from sympy.utilities.lambdify import lambdastr >>> lambdastr(x, x**2) 'lambda x: (x**2)' >>> lambdastr((x,y,z), [z,y,x]) 'lambda x,y,z: ([z, y, x])'
虽然元组可能不会作为参数出现在 Python 3 的 lambda 中,但 lambdastr 将创建一个 lambda 函数,该函数将解包原始参数,以便可以处理嵌套参数:
>>> lambdastr((x, (y, z)), x + y) 'lambda _0,_1: (lambda x,y,z: (x + y))(_0,_1[0],_1[1])'
- sympy.utilities.lambdify.lambdify(
- args,
- expr,
- modules=None,
- printer=None,
- use_imps=True,
- dummify=False,
- cse=False,
- docstring_limit=1000,
将 SymPy 表达式转换为一个允许快速数值评估的函数。
警告
此函数使用
exec
,因此不应在未经净化的输入上使用。自 1.7 版本弃用: 传递一个集合给 args 参数已被弃用,因为集合是无序的。请使用有序的可迭代对象,如列表或元组。
- 参数:
- 参数列表[符号]
一个变量或变量列表,其嵌套结构表示将传递给函数的参数的嵌套结构。
变量可以是符号、未定义的函数或矩阵符号。
>>> from sympy import Eq >>> from sympy.abc import x, y, z
变量列表应与传递给函数的参数结构相匹配。只需将参数按传递时的顺序放入列表中。
要调用像
f(x)
这样的函数,那么[x]
应该是lambdify
的第一个参数;在这种情况下,也可以使用单个x
:>>> f = lambdify(x, x + 1) >>> f(1) 2 >>> f = lambdify([x], x + 1) >>> f(1) 2
要调用一个像
f(x, y)
这样的函数,那么[x, y]
将是lambdify
的第一个参数:>>> f = lambdify([x, y], x + y) >>> f(1, 1) 2
要调用一个带有单个3元素元组的函数,如
f((x, y, z))
,那么[(x, y, z)]
将是lambdify
的第一个参数:>>> f = lambdify([(x, y, z)], Eq(z**2, x**2 + y**2)) >>> f((3, 4, 5)) True
如果传递两个参数,第一个是标量而第二个是包含两个参数的元组,那么列表中的项目应匹配该结构:
>>> f = lambdify([x, (y, z)], x + y + z) >>> f(1, (2, 3)) 6
- 表达式表达式
要计算的表达式、表达式列表或矩阵。
列表可以嵌套。如果表达式是一个列表,输出也将是一个列表。
>>> f = lambdify(x, [x, [x + 1, x + 2]]) >>> f(1) [1, [2, 3]]
如果是矩阵,将返回一个数组(针对NumPy模块)。
>>> from sympy import Matrix >>> f = lambdify(x, Matrix([x, x + 1])) >>> f(1) [[1] [2]]
注意这里的参数顺序(变量然后表达式)是用来模拟Python的``lambda``关键字。``lambdify(x, expr)``的工作方式(大致上)类似于``lambda x: expr``(参见下面的 示例)。
- 模块str, 可选
指定要使用的数值库。
如果未指定,modules 默认为:
["scipy", "numpy"]
如果安装了 SciPy["numpy"]
如果只安装了 NumPy["math", "mpmath", "sympy"]
如果两者都未安装。
也就是说,如果可能的话,SymPy 函数会被替换为
scipy
或numpy
函数(如果可用),否则会使用 Python 标准库中的math
或mpmath
函数。modules 可以是以下类型之一:
字符串
"math"
,"mpmath"
,"numpy"
,"numexpr"
,"scipy"
,"sympy"
, 或"tensorflow"
或"jax"
。这使用相应模块的打印机和命名空间映射。一个模块(例如,
math
)。这使用模块的全局命名空间。如果该模块是上述已知模块之一,它还将使用相应的打印机和命名空间映射(即,modules=numpy
等同于modules="numpy"
)。一个将 SymPy 函数名称映射到任意函数(例如,
{'sin': custom_sin}
)的字典。一个包含上述参数混合的列表,优先级较高的条目出现在前面(例如,要使用 NumPy 模块但用自定义版本覆盖
sin
函数,可以使用[{'sin': custom_sin}, 'numpy']
)。
- dummifybool, 可选
提供的表达式中是否将不是有效 Python 标识符的变量替换为虚拟符号。
这允许像
Function('f')(t)
这样的未定义函数作为参数提供。默认情况下,变量仅在它们不是有效的 Python 标识符时才会被虚拟化。设置
dummify=True
以用虚拟符号替换所有参数(如果args
不是字符串) - 例如,以确保参数不会重新定义任何内置名称。- csebool, 或可调用对象, 可选
当识别并预先计算公共子表达式时,可以更有效地计算大型表达式,这些子表达式在多次使用之前被预先计算。然而,查找这些子表达式会使 ‘lambdify’ 函数的创建变慢。
当
True
时,使用sympy.simplify.cse
,否则(默认)用户可以传递一个匹配cse
签名的函数。- docstring_limit整数或无
在lambdify化大型表达式时,
lambdify
内部花费的时间中,有很大一部分用于生成表达式的字符串表示,以便用于返回函数的自动生成文档字符串中。对于包含数百个或更多节点的表达式,生成的文档字符串通常会变得非常长且密集,难以阅读。为了减少lambdify的运行时间,可以禁用文档字符串中完整表达式的渲染。当
None
时,完整的表达式会在文档字符串中呈现。当0
或负int
时,省略号会在文档字符串中代替表达式呈现。当严格为正的int
时,如果表达式中的节点数超过docstring_limit
,省略号会在文档字符串中呈现,否则表达式的字符串表示会正常呈现。默认值为1000
。
注释
对于涉及大型数组计算的函数,numexpr 可以比 numpy 提供显著的加速。请注意,numexpr 可用的函数比 numpy 更有限,但可以通过
implemented_function
和用户定义的 Function 子类来扩展。如果指定,numexpr 可能是模块中的唯一选项。numexpr 函数的官方列表可以在以下网址找到:https://numexpr.readthedocs.io/en/latest/user_guide.html#supported-functions在上面的例子中,生成的函数可以接受标量值或 numpy 数组作为参数。然而,在某些情况下,生成的函数依赖于输入是一个 numpy 数组:
>>> import numpy >>> from sympy import Piecewise >>> from sympy.testing.pytest import ignore_warnings >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "numpy")
>>> with ignore_warnings(RuntimeWarning): ... f(numpy.array([-1, 0, 1, 2])) [-1. 0. 1. 0.5]
>>> f(0) Traceback (most recent call last): ... ZeroDivisionError: division by zero
在这种情况下,输入应包装在一个numpy数组中:
>>> with ignore_warnings(RuntimeWarning): ... float(f(numpy.array([0]))) 0.0
或者,如果不需要 numpy 功能,可以使用另一个模块:
>>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "math") >>> f(0) 0
示例
>>> from sympy.utilities.lambdify import implemented_function >>> from sympy import sqrt, sin, Matrix >>> from sympy import Function >>> from sympy.abc import w, x, y, z
>>> f = lambdify(x, x**2) >>> f(2) 4 >>> f = lambdify((x, y, z), [z, y, x]) >>> f(1,2,3) [3, 2, 1] >>> f = lambdify(x, sqrt(x)) >>> f(4) 2.0 >>> f = lambdify((x, y), sin(x*y)**2) >>> f(0, 5) 0.0 >>> row = lambdify((x, y), Matrix((x, x + y)).T, modules='sympy') >>> row(1, 2) Matrix([[1, 3]])
lambdify
可以用来将 SymPy 表达式转换为 mpmath 函数。在某些情况下,这可能比使用 ``evalf``(它在后台使用 mpmath)更可取。>>> f = lambdify(x, sin(x), 'mpmath') >>> f(1) 0.8414709848078965
元组参数被处理,并且 lambdified 函数应以创建函数时使用的相同类型的参数调用:
>>> f = lambdify((x, (y, z)), x + y) >>> f(1, (2, 4)) 3
flatten
函数可以用于始终处理扁平化的参数:>>> from sympy.utilities.iterables import flatten >>> args = w, (x, (y, z)) >>> vals = 1, (2, (3, 4)) >>> f = lambdify(flatten(args), w + x + y + z) >>> f(*flatten(vals)) 10
expr
中的函数也可以携带自己的数值实现,这些实现通过附加到_imp_
属性的可调用对象来实现。这可以通过使用implemented_function
工厂与未定义的函数一起使用:>>> f = implemented_function(Function('f'), lambda x: x+1) >>> func = lambdify(x, f(x)) >>> func(4) 5
lambdify
总是优先使用_imp_
实现,而不是其他命名空间中的实现,除非use_imps
输入参数为 False。使用 Tensorflow:
>>> import tensorflow as tf >>> from sympy import Max, sin, lambdify >>> from sympy.abc import x
>>> f = Max(x, sin(x)) >>> func = lambdify(x, f, 'tensorflow')
在 TensorFlow v2 之后,默认启用即时执行。如果你想在本教程中获得与 TensorFlow v1 和 v2 兼容的结果,请运行此行。
>>> tf.compat.v1.enable_eager_execution()
如果你启用了eager执行,你可以立即得到结果,就像你可以使用numpy一样。
如果你传递 TensorFlow 对象,你可能会得到一个
EagerTensor
对象而不是值。>>> result = func(tf.constant(1.0)) >>> print(result) tf.Tensor(1.0, shape=(), dtype=float32) >>> print(result.__class__) <class 'tensorflow.python.framework.ops.EagerTensor'>
你可以使用
.numpy()
来获取张量的 numpy 值。>>> result.numpy() 1.0
>>> var = tf.Variable(2.0) >>> result = func(var) # also works for tf.Variable and tf.Placeholder >>> result.numpy() 2.0
并且它适用于任何形状的数组。
>>> tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]]) >>> result = func(tensor) >>> result.numpy() [[1. 2.] [3. 4.]]