加速SymPy方程求解器

时间:2015-04-13 14:42:50

标签: python sympy numerical-methods

我正在尝试使用以下python代码解决一组方程式(当然使用SymPy):

def Solve(kp1, kp2):
    a, b, d, e, f = S('a b d e f'.split())
    equations = [
      Eq(a+b, 2.6),
      Eq(2*a + b + d + 2*f, 7),
      Eq(d + e, 2),
      Eq(a*e,kp2*b*d),
      Eq( ((b * (f**0.5))/a)*((a+b+d+e+f+13.16)**-0.5), kp1)
    ]
    return solve(equations)

代码在大约35秒后成功解决了方程式。 Solve()函数在另一个文件中的迭代块(大约2000次迭代)中使用,因此速度对我来说非常重要。

有没有办法加速求解器?如果没有,你能推荐另一种方法来解决使用python的方程组吗?

2 个答案:

答案 0 :(得分:5)

你只需要解决一次方程式。之后,您将获得以下形式的等式:

  • a = f_1(kp1,kp2)
  • b = f_2(kp1,kp2)
  • ...

所以你可以简单地计算a,...,e依赖于kp1和kp2。例如,求解第一,第三和第四个方程给出:

  • b:-a + 2.6
  • e:2.0 * kp2 *(5.0 * a - 13.0)/(5.0 * a * kp2 - 5.0 * a - 13.0 * kp2),
  • d:10.0 * a /( - 5.0 * a * kp2 + 5.0 * a + 13.0 * kp2)

在我的电脑上解决所有五个方程式太慢了,但是如果它给你一个表达式,你只需要插入(替换)kp1和kp2的值,你就不必再次求解方程式了。如需替换,请查看sympy documentation

所以你的循环应该是这样的:

solutions = sympy.solve(eqs, exclude=[kp1, kp2])
for data_kp1, data_kp2 in data:
    for key, eq in solutions:
        solution = eq.subs([(kp1, data_kp1), (kp2, data_kp2)])
        final_solutions.append("{key}={solution}".format(key=key, solution=solution))

答案 1 :(得分:2)

求解a,b,d,e的前4个线性方程。这产生两种解决方案。将这些中的每一个替换为第5个等式(以这种形式:Eq(b**2*f, d**2*kp1**2*(a + b + 2*d + f + 13.16)))给出两个等式(e51和e52)。这两个等式在f中是非线性的,如果你在它们上使用unrad,你将最终得到2 f中的有序多项式 - 这可能就是为什么你没有得到解,因为一般只有四次方是可以解的。调用这两个方程e51u和e52u。

如果你对真正的根感兴趣,你可以使用real_roots给这些多项式赋予根,然后代入kp1和kp2的所需值,只留下f作为未知。例如,

>>> ans = solve(equations[:-1],a,b,d,e)
>>> l=equations[-1]  # modified as suggested
>>> l=l.lhs-l.rhs
>>> l
b**2*f - d**2*kp1**2*(a + b + 2*d + f + 13.16)
>>> e51=l.subs(ans[0]); e51u=unrad(e51)[0]
>>> e52=l.subs(ans[1]); e52u=unrad(e52)[0]
>>> import random
>>> for r1,r2 in [[random.random() for i in range(2)] for j in range(3)]:
...     print [i.n(2) for i in real_roots(e51u.subs(dict(kp1=r1,kp2=r2)))]
...     print [i.n(2) for i in real_roots(e52u.subs(dict(kp1=r1,kp2=r2)))]
...     print '^_r1,r2=',r1,r2
...     
[1.7, 2.9, 3.0, 8.2]
[1.7, 2.9, 3.0, 8.2]
^_r1,r2= 0.937748743197 0.134640776315
[1.3, 2.3, 4.7, 7.4]
[1.3, 2.3, 4.7, 7.4]
^_r1,r2= 0.490002815309 0.324553144174
[1.1, 2.1]
[1.1, 2.1]
^_r1,r2= 0.308803300429 0.595356213169

看来e51u和e52u都给出了相同的解决方案,所以也许你只需要使用其中一个。你应该检查原始方程中的答案,看看哪个是真正的解决方案:

>>> r1,r2
(0.30880330042869408, 0.59535621316941589)
>>> [e51.subs(dict(kp1=r1,kp2=r2,f=i)).n(2) for i in real_roots(e51u.subs(dict(kp1=r1,kp2=r2)))]
[1.0e-12, 13.]

所以在这里你看到只有第一个解决方案(从上面看来是1.1)实际上是一个解决方案; 2.1是一个虚假的解决方案。