如何使用 SymPy 加速符号集成?
How to speed up symbolic integration using SymPy?
我正在尝试对以下表达式进行符号积分(最终表达式将以 x 表示):
from sympy import *
x, y = symbols('x, y')
expr = 0.25*sqrt(15/(2*pi)) * exp(2j*y) * (sin(x))**2 * sin(x) * sqrt(cos(x))
int_expr = simplify(integrate(expr, x,(y,0,2*pi)))
print(int_expr)
需要注意的一点是,当我集成 0.25*sqrt(15/(2*pi)) * exp(2j*y) * (sin(x))**2 * sin(x)
程序运行速度稍快一些。加入 sqrt(cos(x))
会使它变得非常慢,并且需要很长时间才能实现代码。
经过大量简化后,我得到了这个数学表达式,它使程序 'start working'
有什么办法可以加快这段代码的速度吗?非常感谢任何建议。
首先,我建议不要使用浮点数,尤其是在指数中(即 2j
)。您应该使用 sympy 的精确有理数,并且 I
用于 sqrt(-1)
.
这给了我们这个:
In [11]: expr = sqrt(15/(2*pi))/4 * exp(2*I*y) * (sin(x))**2 * sin(x) * sqrt(cos(x))
In [12]: int_expr = Integral(expr, (x, 0, 2*pi))
In [13]: int_expr
Out[13]:
2⋅π
⌠
⎮ 2⋅ⅈ⋅y 3 ________
⎮ √30⋅ℯ ⋅sin (x)⋅╲╱ cos(x)
⎮ ───────────────────────────── dx
⎮ 8⋅√π
⌡
0
现在我注意到实际上可以从这个积分中剔除无关因素。我们可以使用 factor_terms
来做到这一点:
In [14]: factor_terms(int_expr)
Out[14]:
2⋅π
⌠
2⋅ⅈ⋅y ⎮ 3 ________
√30⋅ℯ ⋅ ⎮ sin (x)⋅╲╱ cos(x) dx
⌡
0
────────────────────────────────────
8⋅√π
看到剩下的积分值得知道的是,当你有一个没有自由符号的积分时(被积函数中唯一的符号是虚拟积分符号)然后你通常可以通过评估更快地获得近似结果数值积分:
In [15]: Integral(sin(x)**3 * sqrt(cos(x)), (x, 0, 2*pi))
Out[15]:
2⋅π
⌠
⎮ 3 ________
⎮ sin (x)⋅╲╱ cos(x) dx
⌡
0
In [16]: _.n()
Out[16]: -0.e-103 + 0.e-103⋅ⅈ
这说明积分基本为零
在某些情况下,用于符号积分的算法可能非常慢。这是许多积分算法的普遍问题,它们通常对输入的确切形式非常敏感。 sqrt(cos(x))
的附加因子改变了事情,您不应该感到惊讶:它会使手工积分变得更加困难,而且积分没有“乘积规则”。在这个例子中,它在“heurisch”算法中很慢,所以你可以设置 heurisch=False
来禁用它,但是其他算法的 none 可以计算积分,所以你不会得到结果。
通常替换会使积分更容易,您可以要求 sympy 明确地进行替换。在这种情况下,我们可以使用替换 z = cos(x)
但我们需要将积分分成两部分,从 0
到 pi
和从 pi
到 2*pi
以便每个部分的替换都是单调的:
In [30]: Integral(expr, (x, 0, pi))
Out[30]:
π
⌠
⎮ 2⋅ⅈ⋅y 3 ________
⎮ √30⋅ℯ ⋅sin (x)⋅╲╱ cos(x)
⎮ ───────────────────────────── dx
⎮ 8⋅√π
⌡
0
In [31]: Integral(expr, (x, 0, pi)).transform(cos(x), z)
Out[31]:
1
⌠
⎮ ⎛ 2⎞ 2⋅ⅈ⋅y
⎮ √30⋅√z⋅⎝1 - z ⎠⋅ℯ
⎮ ────────────────────── dz
⎮ 8⋅√π
⌡
-1
In [32]: Integral(expr, (x, 0, pi)).transform(cos(x), z).doit()
Out[32]:
2⋅ⅈ⋅y 2⋅ⅈ⋅y
√30⋅ℯ √30⋅ⅈ⋅ℯ
────────── + ────────────
21⋅√π 21⋅√π
In [33]: _ + Integral(expr, (x, pi, 2*pi)).transform(cos(x), z).doit()
Out[33]: 0
我正在尝试对以下表达式进行符号积分(最终表达式将以 x 表示):
from sympy import *
x, y = symbols('x, y')
expr = 0.25*sqrt(15/(2*pi)) * exp(2j*y) * (sin(x))**2 * sin(x) * sqrt(cos(x))
int_expr = simplify(integrate(expr, x,(y,0,2*pi)))
print(int_expr)
需要注意的一点是,当我集成 0.25*sqrt(15/(2*pi)) * exp(2j*y) * (sin(x))**2 * sin(x)
程序运行速度稍快一些。加入 sqrt(cos(x))
会使它变得非常慢,并且需要很长时间才能实现代码。
经过大量简化后,我得到了这个数学表达式,它使程序 'start working'
有什么办法可以加快这段代码的速度吗?非常感谢任何建议。
首先,我建议不要使用浮点数,尤其是在指数中(即 2j
)。您应该使用 sympy 的精确有理数,并且 I
用于 sqrt(-1)
.
这给了我们这个:
In [11]: expr = sqrt(15/(2*pi))/4 * exp(2*I*y) * (sin(x))**2 * sin(x) * sqrt(cos(x))
In [12]: int_expr = Integral(expr, (x, 0, 2*pi))
In [13]: int_expr
Out[13]:
2⋅π
⌠
⎮ 2⋅ⅈ⋅y 3 ________
⎮ √30⋅ℯ ⋅sin (x)⋅╲╱ cos(x)
⎮ ───────────────────────────── dx
⎮ 8⋅√π
⌡
0
现在我注意到实际上可以从这个积分中剔除无关因素。我们可以使用 factor_terms
来做到这一点:
In [14]: factor_terms(int_expr)
Out[14]:
2⋅π
⌠
2⋅ⅈ⋅y ⎮ 3 ________
√30⋅ℯ ⋅ ⎮ sin (x)⋅╲╱ cos(x) dx
⌡
0
────────────────────────────────────
8⋅√π
看到剩下的积分值得知道的是,当你有一个没有自由符号的积分时(被积函数中唯一的符号是虚拟积分符号)然后你通常可以通过评估更快地获得近似结果数值积分:
In [15]: Integral(sin(x)**3 * sqrt(cos(x)), (x, 0, 2*pi))
Out[15]:
2⋅π
⌠
⎮ 3 ________
⎮ sin (x)⋅╲╱ cos(x) dx
⌡
0
In [16]: _.n()
Out[16]: -0.e-103 + 0.e-103⋅ⅈ
这说明积分基本为零
在某些情况下,用于符号积分的算法可能非常慢。这是许多积分算法的普遍问题,它们通常对输入的确切形式非常敏感。 sqrt(cos(x))
的附加因子改变了事情,您不应该感到惊讶:它会使手工积分变得更加困难,而且积分没有“乘积规则”。在这个例子中,它在“heurisch”算法中很慢,所以你可以设置 heurisch=False
来禁用它,但是其他算法的 none 可以计算积分,所以你不会得到结果。
通常替换会使积分更容易,您可以要求 sympy 明确地进行替换。在这种情况下,我们可以使用替换 z = cos(x)
但我们需要将积分分成两部分,从 0
到 pi
和从 pi
到 2*pi
以便每个部分的替换都是单调的:
In [30]: Integral(expr, (x, 0, pi))
Out[30]:
π
⌠
⎮ 2⋅ⅈ⋅y 3 ________
⎮ √30⋅ℯ ⋅sin (x)⋅╲╱ cos(x)
⎮ ───────────────────────────── dx
⎮ 8⋅√π
⌡
0
In [31]: Integral(expr, (x, 0, pi)).transform(cos(x), z)
Out[31]:
1
⌠
⎮ ⎛ 2⎞ 2⋅ⅈ⋅y
⎮ √30⋅√z⋅⎝1 - z ⎠⋅ℯ
⎮ ────────────────────── dz
⎮ 8⋅√π
⌡
-1
In [32]: Integral(expr, (x, 0, pi)).transform(cos(x), z).doit()
Out[32]:
2⋅ⅈ⋅y 2⋅ⅈ⋅y
√30⋅ℯ √30⋅ⅈ⋅ℯ
────────── + ────────────
21⋅√π 21⋅√π
In [33]: _ + Integral(expr, (x, pi, 2*pi)).transform(cos(x), z).doit()
Out[33]: 0