术语重写#
术语重写(Term rewriting)是一类非常普遍的功能,用于将一种类型的表达式转换为不同类型的表达式。例如,扩展、组合和转换表达式应用于术语重写,这里还可以包括简化例程。目前SymPy有几个函数和基本的内置方法来执行各种类型的重写。
扩大#
最简单的重写规则是将表达式扩展为 _sparse_ 形式。展开有几种类型,包括展开复值表达式、乘积和幂的算术展开,也可以用更一般的函数展开函数。下面列出了所有当前可用的扩展规则。
- 涉及乘积和幂的算术表达式的扩展:
>>> from sympy import * >>> x, y, z = symbols('x,y,z') >>> ((x + y)*(x - y)).expand(basic=True) x**2 - y**2 >>> ((x + y + z)**2).expand(basic=True) x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2
默认情况下,算术展开在中完成 expand()
关键字so basic
可以省略。但是您可以设置 basic=False
为了避免这种类型的扩展,如果您使用下面描述的规则。这样可以完全控制表达式的操作。
另一种扩展规则是扩展复杂值表达式,并将其转换为普通形式。为了这个 complex
使用关键字。请注意,它将始终执行算术展开以获得所需的正规形式:
>>> (x + I*y).expand(complex=True)
re(x) + I*re(y) + I*im(x) - im(y)
>>> sin(x + I*y).expand(complex=True)
sin(re(x) - im(y))*cosh(re(y) + im(x)) + I*cos(re(x) - im(y))*sinh(re(y) + im(x))
还请注意,使用 as_real_imag()
方法。但是,它将返回一个元组,它首先包含实部,另一个元组包含虚部。这也可以通过使用 collect
功能:
>>> (x + I*y).as_real_imag()
(re(x) - im(y), re(y) + im(x))
>>> collect((x + I*y).expand(complex=True), I, evaluate=False)
{1: re(x) - im(y), I: re(y) + im(x)}
也有可能根据不同种类的表达式来扩展表达式。这是一种非常普遍的扩张类型,通常你会用到 rewrite()
要执行特定类型的重写:
>>> GoldenRatio.expand(func=True)
1/2 + sqrt(5)/2
公共子表达式检测与收集#
在计算大型表达式之前,识别公共子表达式、收集它们并立即对它们求值是很有用的。这在 cse
功能。示例:
>>> from sympy import cse, sqrt, sin, pprint
>>> from sympy.abc import x
>>> pprint(cse(sqrt(sin(x))), use_unicode=True)
⎛ ⎡ ________⎤⎞
⎝[], ⎣╲╱ sin(x) ⎦⎠
>>> pprint(cse(sqrt(sin(x)+5)*sqrt(sin(x)+4)), use_unicode=True)
⎛ ⎡ ________ ________⎤⎞
⎝[(x₀, sin(x))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠
>>> pprint(cse(sqrt(sin(x+1) + 5 + cos(y))*sqrt(sin(x+1) + 4 + cos(y))),
... use_unicode=True)
⎛ ⎡ ________ ________⎤⎞
⎝[(x₀, sin(x + 1) + cos(y))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠
>>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y))), use_unicode=True)
⎛ ⎡ ____ ⎤⎞
⎝[(x₀, (x - y)⋅(-y + z))], ⎣╲╱ x₀ + x₀⎦⎠
Optimizations to be performed before and after common subexpressions
elimination can be passed in the optimizations
optional argument. A set of
predefined basic optimizations can be applied by passing
optimizations='basic'
:
>>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y)), optimizations='basic'),
... use_unicode=True)
⎛ ⎡ ____ ⎤⎞
⎝[(x₀, -(x - y)⋅(y - z))], ⎣╲╱ x₀ + x₀⎦⎠
但是,对于大型表达式,这些优化可能非常慢。此外,如果速度是一个问题,你可以通过选择 order='none'
. 术语的顺序将取决于哈希算法的实现,但速度将大大提高。
更多信息:
- sympy.simplify.cse_main.cse(exprs, symbols=None, optimizations=None, postprocess=None, order='canonical', ignore=(), list=True)[源代码]
对表达式执行公共子表达式消除。
- 参数:
exprs : list of SymPy expressions, or a single SymPy expression
要减少的表达式。
符号 :产生唯一符号的无限迭代器
用于标记提取的公共子表达式的符号。这个
numbered_symbols
发电机很有用。默认值是“x0”、“x1”等形式的符号流。这必须是一个无限迭代器。优化 :列表(可调用,可调用)对
(预处理器,后处理器)对外部优化函数。可选地,可以为一组预定义的基本优化传递“basic”。这种“基本”优化默认用于旧实现,但是在较大的表达式上它们可能会非常缓慢。现在,默认情况下不会进行预优化或后优化。
后处理 :一个接受cse和两个返回值的函数
从cse返回所需的输出形式,例如,如果要反转替换,则函数可以是以下lambda:lambda r,e:return reversed(r),e
秩序 :string,'none'或'canonical'
Mul和Add参数的处理顺序。如果设置为“canonical”,则参数将按规范排序。如果设置为'none',排序将更快,但依赖于表达式哈希,因此依赖于机器和变量。对于需要考虑速度的大型表达式,请使用设置顺序=“无”。
忽视 :i符号表
包含来自的任何符号的替换
ignore
将被忽略。list : bool, (default True)
Returns expression in list or else with same type as input (when False).
- 返回:
替换 :列表(符号,表达式)对
所有被替换的公共子表达式。此列表前面的子表达式可能会显示在此列表后面的子表达式中。
reduced_exprs : list of SymPy expressions
包含以上所有替换项的简化表达式。
实例
>>> from sympy import cse, SparseMatrix >>> from sympy.abc import x, y, z, w >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3) ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3])
具有递归替换的表达式列表:
>>> m = SparseMatrix([x + y, x + y + z]) >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m]) ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([ [x0], [x1]])])
注:保留了输入矩阵的类型和可变性。
>>> isinstance(_[1][-1], SparseMatrix) True
用户可能不允许包含某些符号的替换:
>>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,)) ([(x0, x + 1)], [x0*y**2, 3*x0*y**2])
The default return value for the reduced expression(s) is a list, even if there is only one expression. The \(list\) flag preserves the type of the input in the output:
>>> cse(x) ([], [x]) >>> cse(x, list=False) ([], x)