【发布时间】:2021-04-06 12:55:52
【问题描述】:
我是 SymPy 的新手,希望有人能指出优化我的代码的方法。
我需要对一个包含非常高小数位 (150–300) 的表达式进行数值计算,并且每个参数集需要 30 秒或更长时间——考虑到要计算的参数空间,这非常长。
我在积分处理中使用了lambdify 和mpmath 后端和meijerg=True,它显着降低了运行时间。还有其他可以使用的方法吗?理想情况下,将评估时间推到 1 秒以下会很棒。我的代码是:
import mpmath
from mpmath import mpf, mp
mp.dps = 150 # ideally would like to have this set to 300
import numpy as np
from sympy import besselj, symbols, hankel2, legendre, sin, cos, tan, summation, I
from sympy import lambdify, expand, Integral
import time
x, alpha, k, m,n, r1, R, theta = symbols('x alpha k m n r1 R theta')
r1 = (R*cos(alpha))/cos(theta) #
Imn_part1 = (n*hankel2(n-1,k*r1)-(n+1)*hankel2(n+1,k*r1))*legendre(n, cos(theta))*cos(theta)
Imn_part2 = n*(n+1)*hankel2(n, k*r1)*(legendre(n-1, cos(theta)-legendre(n+1, cos(theta))))/k*r1
Imn_parts = expand(Imn_part1+Imn_part2)
Imn_expr = expand(Imn_parts*legendre(m,cos(theta))*(r1**2/R**2)*tan(theta))
Imn = Integral(Imn_expr, (theta, 0, alpha)).doit(meijerg=True)
# the lambdified expression
Imn_lambdify = lambdify([m,n,k,R,alpha], Imn,'mpmath')
向函数提供数字输入时 – 需要很长时间(30 秒 - 40 秒)。
substitute_dict = {'alpha':mpf(np.radians(10)), 'k':5,'R':mpf(0.1), 'm':20,'n':10}
print('starting calculation...')
start = time.time()
output = Imn_lambdify(substitute_dict['m'],
substitute_dict['n'],
substitute_dict['k'],
substitute_dict['R'],
substitute_dict['alpha'])
print(time.time()-start)
使用的操作系统/软件包版本:
- Linux Mint 19.2
- Python 3.8.5
- SymPy 1.7.1
- MPMath 1.2.1
【问题讨论】:
-
为什么需要这么多数字?这种准确性几乎不需要。我唯一能想象的是,如果您在表达式中遇到极端的cancellation。
-
嗨@Wrzlprmft 感谢您的ping!我正在尝试移植一些 Mathematica 代码,原作者推荐了如此高的精度。极端取消是否会导致更长的计算时间 - 关于如何解决这个问题的任何想法?
-
我并不是说会发生取消,只是这将是我能想象得到如此高精度的唯一原因。如果处理不当,取消可能会导致大量错误。这些有时可能会导致更长的计算时间,但这将是您遇到的最少问题。
-
两个见解: 1)
Imn仍然包含抽象积分,这意味着doit将对它们进行数值评估。这几乎肯定比你的 150 位数要高。 2)当您删除 MPMath 时(除了作为lambdify的参数,因为它似乎能够根据需要处理复杂的值),一切都在一秒钟内运行并产生相同的结果(对于许多数字)。 —据此,我猜没有理由使用高精度。为了进一步加快速度,最好的方法可能是使用矢量被积函数。 -
@Wrzlprmft doit() 以符号方式而非数字方式评估积分。这样做不会损失准确性(尽管 SymPy 实际上不能以封闭形式计算这个特定的积分,因此调用 doit() 实际上并不是很有用)。
标签: python optimization sympy symbolic-math mpmath