Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用sympy纠正符号方程的命令序列_Python_Numpy_Sympy - Fatal编程技术网

Python 使用sympy纠正符号方程的命令序列

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('

注意:我对sympy是全新的,我正试图弄清楚它是如何工作的

我现在拥有的: 我确实得到了正确的解决方案,但需要35-50秒

目标: 通过定义一次符号方程,然后用不同的变量重复使用,加快计算速度

设置: 我需要为循环的每次迭代计算多项式G(t)(t=6根)。(总共220次迭代) G(t)还有6个其他变量,这些变量是经过计算的,并且在每次迭代中都是已知的。 这些变量在每次迭代中都是不同的

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
  • 然后一个人给了我一个暗示:
作为预处理步骤,只需(象征性地)求解多项式的系数一次。之后,在处理每次迭代时,只需计算多项式系数,然后求根

  • 我要求澄清,该人士补充道:
因此,我定义了函数g(t),然后使用sympy.expand计算出所有括号/指数,然后使用sympy.collect通过t的幂收集项。最后,我在collect的输出上使用.coeff来获得要输入numpy.root的系数

第二次尝试: 为了遵循建议,我首先以符号方式定义了一个G(t),并将其传递给运行循环的函数及其符号参数。因此,函数constructGt()只被调用一次

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添加一些典型值吗。它们是同情的表达方式吗