我有一个非常长的数学公式(仅为了让您了解:它有293095个字符),实际上将成为Python函数的主体。该函数有15个输入参数,如下:
def math_func(t,X,P,n1,n2,R,r):
x,y,z = X
a,b,c = P
u1,v1,w1 = n1
u2,v2,w2 = n2
return <long math formula>
该公式使用简单的数学运算符
+ - * ** /
和一个函数调用arctan
。以下是公式的摘录:r*((-16*(r**6*t*u1**6 - 6*r**6*u1**5*u2 - 15*r**6*t*u1**4*u2**2 +
20*r**6*u1**3*u2**3 + 15*r**6*t*u1**2*u2**4 - 6*r**6*u1*u2**5 -
r**6*t*u2**6 + 3*r**6*t*u1**4*v1**2 - 12*r**6*u1**3*u2*v1**2 -
18*r**6*t*u1**2*u2**2*v1**2 + 12*r**6*u1*u2**3*v1**2 +
3*r**6*t*u2**4*v1**2 + 3*r**6*t*u1**2*v1**4 - 6*r**6*u1*u2*v1**4 -
3*r**6*t*u2**2*v1**4 + r**6*t*v1**6 - 6*r**6*u1**4*v1*v2 -
24*r**6*t*u1**3*u2*v1*v2 + 36*r**6*u1**2*u2**2*v1*v2 +
24*r**6*t*u1*u2**3*v1*v2 - 6*r**6*u2**4*v1*v2 -
12*r**6*u1**2*v1**3*v2 - 24*r**6*t*u1*u2*v1**3*v2 +
12*r**6*u2**2*v1**3*v2 - 6*r**6*v1**5*v2 - 3*r**6*t*u1**4*v2**2 + ...
现在的重点是,实际中将批量评估此函数时会针对固定值
P、n1、n2、R
和 r
进行计算,从而将“自由”变量集减少为仅有四个,理论上具有较少参数的公式应该更快。
因此问题是:我如何在Python中实现此优化?
我知道可以将所有内容放入字符串中,并执行某种类型的 replace
、compile
和 eval
操作,就像以下示例:
formula = formula.replace('r','1').replace('R','2')....
code = compile(formula,'formula-name','eval')
math_func = lambda t,x,y,z: eval(code)
如果一些操作(如幂)可以用它们的值替换,那将是很好的,例如
18*r**6*t*u1**2*u2**2*v1**2
应该在r=u1=u2=v1=1
的情况下变为18*t
。我认为compile
应该这样做,但无论如何我都不确定。 compile
实际上执行此优化吗?
我的解决方案加速了计算,但如果我能够压缩它更多,那将是非常好的。注意:最好在标准Python内完成(稍后我可以尝试Cython)。一般来说,我对以“Pythonic”的方式实现我的目标感兴趣,也许需要一些额外的库:有什么合理好的方法可以做到这一点吗?我的解决方案是一个好的方法吗? 编辑:(为了提供更多背景)
巨大的表达式是圆弧线积分的输出。圆弧在空间中由半径
r
,两个正交规范向量(如二维版本中的x和y轴)n1 =(u1,v1,w1)
,n2 =(u2,v2,w2)
和中心P =(a,b,c)
给出。其余部分是我执行积分的点X =(x,y,z)
和函数R
的参数。
Sympy
和Maple
需要很长时间来计算这个表达式,实际输出来自Mathematica
。如果您对公式感到好奇,请看这里(伪伪代码):
G(u) = P + r*(1-u**2)/(1+u**2)*n1 + r*2*u/(1+u**2)*n2
integral of (1-|X-G(t)|^2/R^2)^3 over t
sympy
(实际上我是sympy
的日常用户),但在这个表达式上它有点慢。虽然它给出了一个很好的输出结果,但很高兴知道你认为这是一个不错的选择 ;) - Alvaro Fuentes2**3*x
优化为8*x
吗?特别是如果我将2**a*x
中的a
替换为3
并编译(我假设,也许是错误的),它应该会进行优化。 - Alvaro Fuentes