Python 使用sympy纠正符号方程的命令序列
注意:我对sympy是全新的,我正试图弄清楚它是如何工作的 我现在拥有的: 我确实得到了正确的解决方案,但需要35-50秒 目标: 通过定义一次符号方程,然后用不同的变量重复使用,加快计算速度 设置: 我需要为循环的每次迭代计算多项式G(t)(t=6根)。(总共220次迭代) G(t)还有6个其他变量,这些变量是经过计算的,并且在每次迭代中都是已知的。 这些变量在每次迭代中都是不同的Python 使用sympy纠正符号方程的命令序列,python,numpy,sympy,Python,Numpy,Sympy,注意:我对sympy是全新的,我正试图弄清楚它是如何工作的 我现在拥有的: 我确实得到了正确的解决方案,但需要35-50秒 目标: 通过定义一次符号方程,然后用不同的变量重复使用,加快计算速度 设置: 我需要为循环的每次迭代计算多项式G(t)(t=6根)。(总共220次迭代) G(t)还有6个其他变量,这些变量是经过计算的,并且在每次迭代中都是已知的。 这些变量在每次迭代中都是不同的 def function_G(f1, f2, a, b, c, d): t = sp.symbols('
def function_G(f1, f2, a, b, c, d):
t = sp.symbols('t')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
eq = sp.expand(left - right)
roots = sp.solveset(Gt, t)
return roots
第一次尝试(慢):
我只是将每一个函数放入一个python函数中,在这里我象征性地定义了Gt并为t求解。
它运行了大约35-40秒。每次迭代都会调用函数
def function_G(f1, f2, a, b, c, d):
t = sp.symbols('t')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
eq = sp.expand(left - right)
roots = sp.solveset(Gt, t)
return roots
- 然后一个人给了我一个暗示:
- 我要求澄清,该人士补充道:
def constructGt():
t, a, b, c, d, f1, f2 = sp.symbols('t a b c d f1 f2')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
gt = sp.Eq(left - right, 0)
expanded = sp.expand(gt)
expanded = sp.collect(expanded, t)
g_vars = {
"a": a,
"b": b,
"c": c,
"d": d,
"f1": f1,
"f2": f2
}
return expanded, g_vars
然后在每次迭代中,我传递函数及其参数以获得根:
#Variables values:
#a = 0.00011713490404073987
#b = 0.00020253296124588926
#c = 4.235688216068313e-07
#d = 0.012262546040805029
#f1= -0.012553203944721956
#f2 = 0.018529776776949003
def function_G(f1_, f2_, a_, b_, c_, d_, Gt, v):
Gt = Gt.subs([(v['a'], a_), (v['b'], b_),
(v['c'], c_), (v['d'], d_),
(v['f1'], f1_), (v['f2'], f2_)])
roots = sp.solveset(Gt, t)
return roots
但它在56秒左右变得更慢了
问题:
我不明白我做错了什么?我也不明白这个人是如何在结果中使用.coeff()和np.roots的。即使你的
f1和f2在变量中是线性的,你也在使用一个四次多项式,而且它的根很长。如果这是单变量的,那么最好只使用表达式,在已知解的某个常数值处求解,然后使用该值和与旧常数相对接近的新常数,并使用nsolve获得下一个根。如果您对多个解决方案感兴趣,您可能需要使用nsolve
“跟踪”每个根目录,但我认为您会对整体性能感到更满意。使用实根是另一种选择,特别是当表达式只是某个变量中的多项式时
考虑到您使用的是四次曲线,您应该记住这一点:一般解非常长且复杂(非常特殊的情况除外),因此使用一般解并替换已知的值是没有效率的。但是,数值求解非常容易,而且速度要快得多:
首先创建将替换为值的符号表达式;使用无假设的“普通”符号:
t, a, b, c, d, f1, f2 = symbols('t a b c d f1 f2')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
eq = left - right
接下来,定义替换字典以替换表达式,注意dict(x=1)
创建{'x':1},当它与subs一起使用时,将为“x”创建一个普通符号:
计算表达式的实际根:
from time import time
t=time();[i.n(3) for i in real_roots(eq.subs(reps))];'%s sec' % round(time()-t)
[-11.5, -1.73, 8.86, 1.06e+8]
'3 sec'
找到表达式的所有6个根,但只取真实部分:
>>> roots(eq.subs(reps))
{-11.4594523988215: 1, -1.73129179415963: 1, 8.85927293271708: 1, 106354884.4365
42: 1, -1.29328524826433 - 10.3034942999005*I: 1, -1.29328524826433 + 10.3034942
999005*I: 1}
>>> [re(i).n(3) for i in _]
[-11.5, -1.73, 8.86, 1.06e+8, -1.29, -1.29]
更改一个或多个值,然后重试
reps.update(dict(a=2))
[i.n(3) for i in real_roots(eq.subs(reps))]
[-0.0784, -0.000101, 0.0782, 3.10e+16]
更新循环中的值:
>>> a = 1
>>> for i in range(3):
... a += 1
... reps.update(dict(a=a))
... a, real_roots(eq.subs(reps))[0].n(3)
...
(2, -0.0784)
(3, -0.0640)
(4, -0.0554)
注意:当使用根时,实根将以排序顺序排在第一位,然后虚根将以共轭对的形式出现(但不是以任何给定的顺序)。即使您的f1
和f2
在变量中是线性的,您使用的是一个四次多项式,其根非常长。如果这是单变量的,那么最好只使用表达式,在已知解的某个常数值处求解,然后使用该值和与旧常数相对接近的新常数,并使用nsolve获得下一个根。如果您对多个解决方案感兴趣,您可能需要使用nsolve
“跟踪”每个根目录,但我认为您会对整体性能感到更满意。使用实根是另一种选择,特别是当表达式只是某个变量中的多项式时
考虑到您使用的是四次曲线,您应该记住这一点:一般解非常长且复杂(非常特殊的情况除外),因此使用一般解并替换已知的值是没有效率的。但是,数值求解非常容易,而且速度要快得多:
首先创建将替换为值的符号表达式;使用无假设的“普通”符号:
t, a, b, c, d, f1, f2 = symbols('t a b c d f1 f2')
left = t * ((a * t + b)**2 + f2**2 * (c*t+d)**2)**2
right = (a*d-b*c) * (1+ f1**2 * t**2)**2 * (a*t+b) * (c*t+d)
eq = left - right
接下来,定义替换字典以替换表达式,注意dict(x=1)
创建{'x':1},当它与subs一起使用时,将为“x”创建一个普通符号:
计算表达式的实际根:
from time import time
t=time();[i.n(3) for i in real_roots(eq.subs(reps))];'%s sec' % round(time()-t)
[-11.5, -1.73, 8.86, 1.06e+8]
'3 sec'
找到表达式的所有6个根,但只取真实部分:
>>> roots(eq.subs(reps))
{-11.4594523988215: 1, -1.73129179415963: 1, 8.85927293271708: 1, 106354884.4365
42: 1, -1.29328524826433 - 10.3034942999005*I: 1, -1.29328524826433 + 10.3034942
999005*I: 1}
>>> [re(i).n(3) for i in _]
[-11.5, -1.73, 8.86, 1.06e+8, -1.29, -1.29]
更改一个或多个值,然后重试
reps.update(dict(a=2))
[i.n(3) for i in real_roots(eq.subs(reps))]
[-0.0784, -0.000101, 0.0782, 3.10e+16]
更新循环中的值:
>>> a = 1
>>> for i in range(3):
... a += 1
... reps.update(dict(a=a))
... a, real_roots(eq.subs(reps))[0].n(3)
...
(2, -0.0784)
(3, -0.0640)
(4, -0.0554)
注意:当使用根时
,实根将以排序的顺序排在第一位,然后虚根将以共轭对的形式出现(但不是以任何给定的顺序)。我实际上是在以后过滤根,只保留每个根的实部,如:rts=np.array([sp.re(root))表示根中的根)。另外,你说你需要更多地了解这些价值观。你是指参数a、b、c、d、f1、f2吗?@Illia你能为f1、f2、a、b、c、d添加一些典型值吗。它们是同情的表达方式吗