python中方程组的自动创建和求解(以符号形式)

时间:2021-04-14 13:18:49

标签: python scipy sympy

告诉我,如何解决以下问题:我需要在 python(scipy、sympy 或使用其他库)中求解非线性方程组。问题不在于python中求解方程组的能力,而在于方程的数量是另一个问题的解(N),并且事先不知道。从k方程自动生成系统对我来说并不难(例如,我之前问过问题solution system of linear equations in sympy,但没有得到答案)。

我把上面链接里的代码改写成表格(方程组是手工写的):

scipy 变体:

 def soleq(n):
     def equations(p):
         if n==4:
             x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4= p
             a1=1 ### 1/kT1
             a2=2 ### 1/kT2
             a3=3 ### 1/kT3
             a4=4 ### 1/kT4
             a5=5 ### 1/kT5
             a6=6 ### 1/kT6
             a7=7 ### 1/kT7
             a8=8 ### 1/kT8
             a9=9 ### 1/kT9
             a10=10 ### 1/kT10
             a11=11 ### 1/kT11
             a12=12 ### 1/kT12
             mui1_exp=1 
             mui2_exp=2
             mui3_exp=3
             mui4_exp=4
             mui5_exp=5
             mui6_exp=6
             mui7_exp=7
             mui8_exp=8
             mui9_exp=9
             mui10_exp=10
             mui11_exp=11
             mui12_exp=12
             eq1=(a1*x1-y1)*z1+(a1*x2-y2)*z2+(a1*x3-y3)*z3+(a1*x4-y4)*z4-mui1_exp*(z1+z2+z3+z4)
             eq2=(a2*x1-y1)*z1+(a2*x2-y2)*z2+(a2*x3-y3)*z3+(a2*x4-y4)*z4-mui2_exp*(z1+z2+z3+z4)
             eq3=(a3*x1-y1)*z1+(a3*x2-y2)*z2+(a3*x3-y3)*z3+(a3*x4-y4)*z4-mui3_exp*(z1+z2+z3+z4)
             eq4=(a4*x1-y1)*z1+(a4*x2-y2)*z2+(a4*x3-y3)*z3+(a4*x4-y4)*z4-mui4_exp*(z1+z2+z3+z4)
             eq5=(a5*x1-y1)*z1+(a5*x2-y2)*z2+(a5*x3-y3)*z3+(a5*x4-y4)*z4-mui5_exp*(z1+z2+z3+z4)
             eq6=(a6*x1-y1)*z1+(a6*x2-y2)*z2+(a6*x3-y3)*z3+(a6*x4-y4)*z4-mui6_exp*(z1+z2+z3+z4)
             eq7=(a7*x1-y1)*z1+(a7*x2-y2)*z2+(a7*x3-y3)*z3+(a7*x4-y4)*z4-mui7_exp*(z1+z2+z3+z4)
             eq8=(a8*x1-y1)*z1+(a8*x2-y2)*z2+(a8*x3-y3)*z3+(a8*x4-y4)*z4-mui8_exp*(z1+z2+z3+z4)
             eq9=(a9*x1-y1)*z1+(a9*x2-y2)*z2+(a9*x3-y3)*z3+(a9*x4-y4)*z4-mui9_exp*(z1+z2+z3+z4)
             eq10=(a10*x1-y1)*z1+(a10*x2-y2)*z2+(a10*x3-y3)*z3+(a10*x4-y4)*z4-mui10_exp*(z1+z2+z3+z4)
             eq11=(a11*x1-y1)*z1+(a11*x2-y2)*z2+(a11*x3-y3)*z3+(a11*x4-y4)*z4-mui11_exp*(z1+z2+z3+z4)
             eq12=(a12*x1-y1)*z1+(a12*x2-y2)*z2+(a12*x3-y3)*z3+(a12*x4-y4)*z4-mui12_exp*(z1+z2+z3+z4)
         return (eq1,eq2,eq3,eq4,eq5,eq6,eq7,eq8,eq9,eq10,eq11,eq12)
     x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4 = fsolve(equations, (1, 1,1, 1,1, 1,1, 1,1, 1,1, 1))
     sol=equations((x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4))
     print(np.abs(sol))
     return np.nan
 n=4
 a=soleq(n)

提供的 scipi-option 有效,但使用此选项不方便,因为结构 "if n == 4: ...." 必须多次指定,N 可以是 10 或 50 (事先不知道)。 要查找的变量是 x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4 这些变量可以是 N

这里是等式的相同版本,仅在 sympy 中:

 eq1=sp.Eq((a1*x1-y1)*z1+(a1*x2-y2)*z2+(a1*x3-y3)*z3+(a1*x4-y4)*z4-mui1_exp*(z1+z2+z3+z4))
 eq2=sp.Eq((a2*x1-y1)*z1+(a2*x2-y2)*z2+(a2*x3-y3)*z3+(a2*x4-y4)*z4-mui2_exp*(z1+z2+z3+z4))
 eq3=sp.Eq((a3*x1-y1)*z1+(a3*x2-y2)*z2+(a3*x3-y3)*z3+(a3*x4-y4)*z4-mui3_exp*(z1+z2+z3+z4))
 eq4=sp.Eq((a4*x1-y1)*z1+(a4*x2-y2)*z2+(a4*x3-y3)*z3+(a4*x4-y4)*z4-mui4_exp*(z1+z2+z3+z4))
 eq5=sp.Eq((a5*x1-y1)*z1+(a5*x2-y2)*z2+(a5*x3-y3)*z3+(a5*x4-y4)*z4-mui5_exp*(z1+z2+z3+z4))
 eq6=sp.Eq((a6*x1-y1)*z1+(a6*x2-y2)*z2+(a6*x3-y3)*z3+(a6*x4-y4)*z4-mui6_exp*(z1+z2+z3+z4))
 eq7=sp.Eq((a7*x1-y1)*z1+(a7*x2-y2)*z2+(a7*x3-y3)*z3+(a7*x4-y4)*z4-mui7_exp*(z1+z2+z3+z4))
 eq8=sp.Eq((a8*x1-y1)*z1+(a8*x2-y2)*z2+(a8*x3-y3)*z3+(a8*x4-y4)*z4-mui8_exp*(z1+z2+z3+z4))
 eq9=sp.Eq((a9*x1-y1)*z1+(a9*x2-y2)*z2+(a9*x3-y3)*z3+(a9*x4-y4)*z4-mui9_exp*(z1+z2+z3+z4))
 eq10=sp.Eq((a10*x1-y1)*z1+(a10*x2-y2)*z2+(a10*x3-y3)*z3+(a10*x4-y4)*z4-mui10_exp*(z1+z2+z3+z4))
 eq11=sp.Eq((a11*x1-y1)*z1+(a11*x2-y2)*z2+(a11*x3-y3)*z3+(a11*x4-y4)*z4-mui11_exp*(z1+z2+z3+z4))
 eq12=sp.Eq((a12*x1-y1)*z1+(a12*x2-y2)*z2+(a12*x3-y3)*z3+(a12*x4-y4)*z4-mui12_exp*(z1+z2+z3+z4))

我试图用来解决的求解器选项,例如,这样的系统: sol = sp.solve([eq1,eq2,eq3,eq4,eq5,eq6,eq7,eq8,eq9,eq10,eq11,eq12]) sol = 解决(equ, x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4,dict=True, manual=True, check=False) sol = nonlinsolve(equ,x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4) eq=(eq1,eq2,eq3,eq4,eq5,eq6,eq7,eq8,eq9,eq10,eq11,eq12) sol = sp.solve(equ,x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4,rational=False) sol = sp.solve((eq1,eq2,eq3,eq4,eq5,eq6,eq7,eq8,eq9,eq10,eq11,eq12) (x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4))

代码是用这些 sympy-solver 启动的,但无法等待解决方案,错误不会出现; sympy,原则上适合我,但如何让他解决这样的系统??? 在这两个示例中,要查找的变量是 x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4 并且这些变量可以是 N 。 换句话说,我需要一种算法来自动创建和求解(符号)方程组

1 个答案:

答案 0 :(得分:0)

您提供的代码没有按照您的预期工作,因为您尝试求解 equations 但这是一个定义方程的函数。要生成方程,您需要将变量传递给它以用作 p,如 equations(symbols('x1:%s,y1:%s,z1:%s'%tuple([n+1]*3)))。因此,对于所有 1 的初始猜测,调用看起来像 fsolve(equations(symbols('x1:%s,y1:%s,z1:%s'%tuple([n+1]*3))), (1,)*12)

以下是我如何根据您为 n=4 提供的示例生成您的方程组:

from sympy.abc import *
from sympy import *

def neq(n): 
    x=symbols('x1:' + str(n+1))
    y=symbols('y1:' + str(n+1))
    z=symbols('z1:' + str(n+1))
    a = symbols('a1:%s' % (3*n+1)) 
    muiexp = symbols('muiexp1:%s' % (3*n+1))
    v = x+y+z 
    ysum = sum(z) 
    eq = []
    for i in range(3*n): 
        terms = [] 
        for j in range(n): 
            terms.append((a[i]*x[j]-y[j])*z[j]) 
        eq.append(Add(*terms) - muiexp[i]*ysum) 
    return eq,v

>>> e, v = neq(2)
>>> for i in e: print(i)
-muiexp1*(z1 + z2) + z1*(a1*x1 - y1) + z2*(a1*x2 - y2)
-muiexp2*(z1 + z2) + z1*(a2*x1 - y1) + z2*(a2*x2 - y2)
-muiexp3*(z1 + z2) + z1*(a3*x1 - y1) + z2*(a3*x2 - y2)
-muiexp4*(z1 + z2) + z1*(a4*x1 - y1) + z2*(a4*x2 - y2)
-muiexp5*(z1 + z2) + z1*(a5*x1 - y1) + z2*(a5*x2 - y2)
-muiexp6*(z1 + z2) + z1*(a6*x1 - y1) + z2*(a6*x2 - y2)

>>> solve(*neq(2))
[(x2, x2, y2, y2, -z2, z2)]
>>> solve(*neq(4))
[((x2*z2 + x3*z3 + x4*z4)/(z2 + z3 + z4), x2, x3, x4, (y2*z2 + y3*z3 + y4*z4)/(z2 + z3 + z4), y2, y3, y4, -z2 - z3 - z4, z2, z3, z4)]

让我们看看当 n = 1 时最简单的系统:

>>> e, v = neq(1)
>>> for i in e:i
... 
-muiexp1*z1 + z1*(a1*x1 - y1)
-muiexp2*z1 + z1*(a2*x1 - y1)
-muiexp3*z1 + z1*(a3*x1 - y1)

>>> from sympy import nonlinsolve
>>> nonlinsolve(e, v)
FiniteSet((x1, y1, 0))

这是一个微不足道的解决方案,因为 z1 从每个方程中分解出来。因此,如果它是 0,那么 x1 和 y1 是什么并不重要。有没有非平凡的解决方案?求解第一个方程的 x1 并代入第二个,然后求解第二个方程的 y1 并代入第三个。求解 z1,你发现它是 0。没有非平凡的解决方案。

>>> solve(e[0],x1)
[(muiexp1 + y1)/a1]
>>> _x1=_[0];solve(e[1].subs(x1,_x1),y1)
[(-a1*muiexp2 + a2*muiexp1)/(a1 - a2)]
>>> _y1=_[0];solve(e[2].subs(x1,_x1).subs(y1,_y1),z1)
[0]
>>> Tuple(*e).subs(z1,0)
(0, 0, 0)

当 n=2 时情况类似:

>>> solve(*neq(2))
[(x2, x2, y2, y2, -z2, z2)]

解表示当 z1 和 z2 符号相反(或都为 0)时,唯一的解是当 x1 = x2 且 y1 = y2 时。

如果您认为求解器没有告诉您真相,那么它只举一个反例:找到与描述的模式不匹配的解决方案,然后 SymPy 的求解器存在问题。如果不是,那就是我们的理解有问题。

然而,符号系统的强大之处在于它可以用来证明通用解决方案的真实性。

e, v = neq(4)
sol = nonlinsolve(e, v)
gen = list(sol)[0]  # there is only one general solution
reps = dict(zip(v, gen))
[i.xreplace(reps).factor() for i in e]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

所以一般的解决方案是正确的。您可以查看任意数量的特定解决方案。这是一个:

from random import random
from symyp import Rationa, Tuple
arb = {i: Rational(str(round(random(),2))) for i,j in zip(v, gen) if i == j}
for i,j in zip(v, gen):
    arb[i] = j.xreplace(arb)
print(arb)
print(Tuple(*eq).xreplace(arb))

碰巧是

{x2: 89/100, x3: 73/100, x4: 6/25, y2: 83/100, y3: 3/20, y4: 13/50, z2: 
1/100, z3: 11/25, z4: 3/5, x1: 4741/10500, y1: 329/1500, z1: -21/20}
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)