Python sympy nonlinsolve依赖于简单的方程组
我是Symphy的新手,正在尝试用它来解一个相对简单的方程组:Python sympy nonlinsolve依赖于简单的方程组,python,sympy,Python,Sympy,我是Symphy的新手,正在尝试用它来解一个相对简单的方程组: import sympy A, B, I, AI, BI, A0, B0, I0, k1, k2, k3, k4 = sympy.symbols('A B I AI BI A_0 B_0 I_0 k1 k2 k3 k4', real=True) eqs = [A0 - AI - A, B0 - BI - B, I0 - AI - BI - I, k1*(A0 - AI)*I - k2*AI, k3*(B0 - BI)*I - k4*
import sympy
A, B, I, AI, BI, A0, B0, I0, k1, k2, k3, k4 = sympy.symbols('A B I AI BI A_0 B_0 I_0 k1 k2 k3 k4', real=True)
eqs = [A0 - AI - A,
B0 - BI - B,
I0 - AI - BI - I,
k1*(A0 - AI)*I - k2*AI,
k3*(B0 - BI)*I - k4*BI]
如果我为a、B、I
寻找解决方案,它会起作用:
# this works
result = sympy.nonlinsolve(eqs, (A,B,I))
print(result)
给出结果FiniteSet((-AI+A_0,-BI+B_0,-AI-BI+I_0))
,但如果我要求解决变量AI,BI,A,B,I
中的其他变量,它似乎挂起:
# this hangs
result = sympy.nonlinsolve(eqs, (AI,BI,A,B,I))
我做错了什么
(使用的是sympy'1.6.2'
)
编辑:为了回应@Oscar Benjamin的有益建议,这里尝试用两种方法来解决原始系统:(1)将具有线性解的变量代入方程中,(2)简化问题,并假设我们希望我们的解是其函数的7个变量中有3个已知。这两种方法都给出了错误的答案:非真实解和非真实解。有办法解决这个问题吗
import sympy
from sympy import solve, factor, roots, nonlinsolve
A, B, I, AI, BI, A0, B0, I0, k1, k2, k3, k4 = sympy.symbols('A B I AI BI A_0 B_0 I_0 k1 k2 k3 k4', real=True)
eqs = [A0 - AI - A,
B0 - BI - B,
I0 - AI - BI - I,
k1*(A0 - AI)*I - k2*AI,
k3*(B0 - BI)*I - k4*BI]
print("trying to solve original system:")
# solve linear equations and substitute their solutions in
((As, Bs, Is),) = nonlinsolve(eqs, (A,B,I))
eqs2 = [eq.subs({A:As,B:Bs,I:Is}) for eq in eqs]
eq1, eq2 = eqs2[3:]
p = eq1.subs(AI, solve(eq2, AI)[0]).as_numer_denom()[0].expand().collect(BI)
BI1, BI2, BI3, BI4 = roots(p, BI)
def eval_solns(inputs, roots):
for vals in inputs:
for n, root in enumerate(roots):
print("root %d yields: " %(n+1))
print(root.subs(vals))
inputs = [{A0: 100, B0: 100, I0: 100, k1: 0.1, k2: 0.1, k3: 0.1, k4: 0.1},
{A0: 100, B0: 100, I0: 100, k1: 0.2, k2: 0.1, k3: 0.3, k4: 0.4}]
# all of these give wrong, non-real solutions to the system
orig_roots = [BI1, BI2, BI3, BI4]
eval_solns(inputs, orig_roots)
# second try: simplify the problem by assuming A0, B0, I0 are given
# substitute them in
eqs2 = [eq.subs({A:As,B:Bs,I:Is}) for eq in eqs2]
eqs2 = [eq.subs({A0: 100, B0: 100, I0: 100}) for eq in eqs2]
eq1, eq2 = eqs2[3:]
print("*\ntrying simpler system with A0,B0,I0 given: ")
print(eqs2)
p = eq1.subs(AI, solve(eq2, AI)[0]).as_numer_denom()[0].expand().collect(BI)
BI1, BI2, BI3, BI4 = roots(p, BI)
new_roots = [BI1, BI2, BI3, BI4]
# solve the simpler system
new_inputs = [{k1: 0.1, k2: 0.1, k3: 0.1, k4: 0.1},
{k1: 0.2, k2: 0.1, k3: 0.3, k4: 0.4},
{k1: 0.05, k2: 1.0, k3: 1.0, k4: 1.2}]
# all of these answers are wrong
eval_solns(new_inputs, new_roots)
我得到的输出包括:
...
trying simpler system with A0,B0,I0 given:
[0, 0, 0, -AI*k2 + k1*(100 - AI)*(-AI - BI + 100), -BI*k4 + k3*(100 - BI)*(-AI - BI + 100)]
root 1 yields:
100
root 2 yields:
nan
root 3 yields:
nan
root 4 yields:
nan
root 1 yields:
100
root 2 yields:
-6.22222222222222 - 33.1666666666667*(9.77105856678793 + 8.49476415953825*I)**(1/3) - 182.875860785409/(9.77105856678793 + 8.49476415953825*I)**(1/3)
root 3 yields:
-6.22222222222222 - 33.1666666666667*(-1/2 + sqrt(3)*I/2)*(9.77105856678793 + 8.49476415953825*I)**(1/3) - 182.875860785409/((-1/2 + sqrt(3)*I/2)*(9.77105856678793 + 8.49476415953825*I)**(1/3))
root 4 yields:
-6.22222222222222 - 182.875860785409/((-1/2 - sqrt(3)*I/2)*(9.77105856678793 + 8.49476415953825*I)**(1/3)) - 33.1666666666667*(-1/2 - sqrt(3)*I/2)*(9.77105856678793 + 8.49476415953825*I)**(1/3)
root 1 yields:
100
root 2 yields:
104.655319148936 - 100*(-0.00146514175733681 + 0.00423691411709115*I)**(1/3) - 2.718847623359/(-0.00146514175733681 + 0.00423691411709115*I)**(1/3)
root 3 yields:
104.655319148936 - 100*(-1/2 + sqrt(3)*I/2)*(-0.00146514175733681 + 0.00423691411709115*I)**(1/3) - 2.718847623359/((-1/2 + sqrt(3)*I/2)*(-0.00146514175733681 + 0.00423691411709115*I)**(1/3))
root 4 yields:
104.655319148936 - 2.718847623359/((-1/2 - sqrt(3)*I/2)*(-0.00146514175733681 + 0.00423691411709115*I)**(1/3)) - 100*(-1/2 - sqrt(3)*I/2)*(-0.00146514175733681 + 0.00423691411709115*I)**(1/3)
在这个系统中,所有变量都是正实数,所有解都应该是实的。将第一部分声明为与正数=True
一致,如下所示,没有任何区别:
A, B, I, AI, BI, A0, B0, I0, k1, k2, k3, k4 = sympy.symbols('A B I AI BI A_0 B_0 I_0 k1 k2 k3 k4', real=True, positive=True)
所有的答案仍然不正确
编辑2:为了澄清,我对解析解很感兴趣,但仍然不明白为什么它太复杂,无法在Symphy中导出(然后与插入的实际值一起使用)。我想要解析解的原因是,我可以直接求解k1,k2,k3,k4的特定值,给定A0,B0,I0的特定设置。这就是为什么在已知A0、B0和I0的情况下,可以得到解析解。然而,当所有的A0,B0,I0,k1,k2,k3,k4都给定时,得到数值解并不是我想要的。它看起来可能很简单,但这可以归结为一个具有符号系数的立方体,所以尽管可以通过代数方法找到解,但它并不简单。在这种情况下,
nonlinsolve
在计算较大的Groebner基时速度较慢。不过,有一种更快的方法可以解决这个问题
首先求解A
、B
和I
的平凡线性方程组:
In [55]: ((As, Bs, Is),) = nonlinsolve(eqs, (A,B,I))
In [56]: As
Out[56]: -AI + A₀
In [57]: Bs
Out[57]: -BI + B₀
In [58]: Is
Out[58]: -AI - BI + I₀
我们现在可以从系统中消除这些未知数和方程:
In [59]: eqs2 = [eq.subs({A:As,B:Bs,I:Is}) for eq in eqs]
In [60]: eqs2
Out[60]: [0, 0, 0, -AI⋅k₂ + k₁⋅(-AI + A₀)⋅(-AI - BI + I₀), -BI⋅k₄ + k₃⋅(-BI + B₀)⋅(-AI - BI + I₀)]
In [61]: eq1, eq2 = eqs2[3:]
In [62]: eq1
Out[62]: -AI⋅k₂ + k₁⋅(-AI + A₀)⋅(-AI - BI + I₀)
In [63]: eq2
Out[63]: -BI⋅k₄ + k₃⋅(-BI + B₀)⋅(-AI - BI + I₀)
此时,我们在AI
和BI
中有一个二次多元多项式系统。我们可以为AI
求解eq2
(因为它在AI
中是线性的),并将其代入eq1
,以仅在BI
中得到一个方程:
In [68]: solve(eq2, AI)
Out[68]:
⎡ 2 ⎤
⎢- BI ⋅k₃ + BI⋅B₀⋅k₃ + BI⋅I₀⋅k₃ + BI⋅k₄ - B₀⋅I₀⋅k₃⎥
⎢─────────────────────────────────────────────────⎥
⎣ k₃⋅(BI - B₀) ⎦
In [69]: eq1.subs(AI, solve(eq2, AI)[0])
Out[69]:
⎛ 2 ⎞ ⎛ 2 ⎞ ⎛ 2
⎜ - BI ⋅k₃ + BI⋅B₀⋅k₃ + BI⋅I₀⋅k₃ + BI⋅k₄ - B₀⋅I₀⋅k₃⎟ ⎜ - BI ⋅k₃ + BI⋅B₀⋅k₃ + BI⋅I₀⋅k₃ + BI⋅k₄ - B₀⋅I₀⋅k₃⎟ k₂⋅⎝- BI ⋅k₃ + B
k₁⋅⎜A₀ - ─────────────────────────────────────────────────⎟⋅⎜-BI + I₀ - ─────────────────────────────────────────────────⎟ - ────────────────
⎝ k₃⋅(BI - B₀) ⎠ ⎝ k₃⋅(BI - B₀) ⎠
⎞
I⋅B₀⋅k₃ + BI⋅I₀⋅k₃ + BI⋅k₄ - B₀⋅I₀⋅k₃⎠
──────────────────────────────────────
k₃⋅(BI - B₀)
我们可以将其简化为四分之一:
In [73]: p = eq1.subs(AI, solve(eq2, AI)[0]).as_numer_denom()[0].expand().collect(BI)
In [74]: p
Out[74]:
4 ⎛ 2 3⎞ 3 ⎛ 2 2 3 2 3 2 2 ⎞ 2 ⎛
BI ⋅⎝- k₁⋅k₃ ⋅k₄ + k₂⋅k₃ ⎠ + BI ⋅⎝- A₀⋅k₁⋅k₃ ⋅k₄ + 2⋅B₀⋅k₁⋅k₃ ⋅k₄ - 3⋅B₀⋅k₂⋅k₃ + I₀⋅k₁⋅k₃ ⋅k₄ - I₀⋅k₂⋅k₃ + k₁⋅k₃⋅k₄ - k₂⋅k₃ ⋅k₄⎠ + BI ⋅⎝2⋅
2 2 2 2 3 2 3 2 2 ⎞ ⎛ 2 2
A₀⋅B₀⋅k₁⋅k₃ ⋅k₄ - B₀ ⋅k₁⋅k₃ ⋅k₄ + 3⋅B₀ ⋅k₂⋅k₃ - 2⋅B₀⋅I₀⋅k₁⋅k₃ ⋅k₄ + 3⋅B₀⋅I₀⋅k₂⋅k₃ - B₀⋅k₁⋅k₃⋅k₄ + 2⋅B₀⋅k₂⋅k₃ ⋅k₄⎠ + BI⋅⎝- A₀⋅B₀ ⋅k₁⋅k₃ ⋅k₄
3 3 2 2 2 3 2 2 ⎞ 3 3
- B₀ ⋅k₂⋅k₃ + B₀ ⋅I₀⋅k₁⋅k₃ ⋅k₄ - 3⋅B₀ ⋅I₀⋅k₂⋅k₃ - B₀ ⋅k₂⋅k₃ ⋅k₄⎠ + B₀ ⋅I₀⋅k₂⋅k₃
对factor
的简单调用显示四个根中的一个就是BI=B0
:
In [84]: factor(p)
Out[84]:
⎛ 2 3 3 2 2 2 2 2 2
-k₃⋅(BI - B₀)⋅⎝A₀⋅BI ⋅k₁⋅k₃⋅k₄ - A₀⋅BI⋅B₀⋅k₁⋅k₃⋅k₄ + BI ⋅k₁⋅k₃⋅k₄ - BI ⋅k₂⋅k₃ - BI ⋅B₀⋅k₁⋅k₃⋅k₄ + 2⋅BI ⋅B₀⋅k₂⋅k₃ - BI ⋅I₀⋅k₁⋅k₃⋅k₄ + BI ⋅I₀
2 2 2 2 2 2 2 2 2⎞
⋅k₂⋅k₃ - BI ⋅k₁⋅k₄ + BI ⋅k₂⋅k₃⋅k₄ - BI⋅B₀ ⋅k₂⋅k₃ + BI⋅B₀⋅I₀⋅k₁⋅k₃⋅k₄ - 2⋅BI⋅B₀⋅I₀⋅k₂⋅k₃ - BI⋅B₀⋅k₂⋅k₃⋅k₄ + B₀ ⋅I₀⋅k₂⋅k₃ ⎠
也许这个解决方案对你来说已经足够了。其他三个则要复杂得多。您可以通过以下方式获得所有信息:
In [85]: BI1, BI2, BI3, BI4 = roots(p, BI)
In [86]: BI1
Out[86]: B₀
我不会显示BI2
等的输出,因为它太复杂了。并不是所有这些根都一定是原始系统的解决方案,因为需要进行转换才能找到它们,所以您必须反向工作以找出哪些是
我认为这意味着BI=B0
解决方案只有在B0
或k4
为零时才有效,例如:
In [99]: eq2.subs(BI, BI1)
Out[99]: -B₀⋅k₄
编辑:我上面的答案旨在说明如何获得一般的符号答案,但这似乎不是你真正想要的(答案太复杂了,无论如何都没有多大用处)。因为你想得到特定数字的答案,你应该把这些数字代入方程式。如果您不是在寻找分析解决方案,则可以使用nsolve:
In [29]: import sympy
...: from sympy import solve, factor, roots, nonlinsolve
...: A, B, I, AI, BI, A0, B0, I0, k1, k2, k3, k4 = sympy.symbols('A B I AI BI A_0 B_0 I_0 k1 k2 k3 k4', positive=True)
...: eqs = [A0 - AI - A,
...: B0 - BI - B,
...: I0 - AI - BI - I,
...: k1*(A0 - AI)*I - k2*AI,
...: k3*(B0 - BI)*I - k4*BI]
In [30]: inputs = [{A0: 100, B0: 100, I0: 100, k1: 0.1, k2: 0.1, k3: 0.1, k4: 0.1},
...: {A0: 100, B0: 100, I0: 100, k1: 0.2, k2: 0.1, k3: 0.3, k4: 0.4}]
In [31]: eqs_sub = [eq.subs(inputs[0]) for eq in eqs]
In [32]: solve(eqs_sub, [A, B, I, AI, BI])
Out[32]: [(50.4902894311622, 50.4902894311622, 0.980578862324382, 49.5097105688378, 49.5097105688378)]
In [33]: nsolve(eqs_sub, [A, B, I, AI, BI], [1, 1, 1, 1, 1])
Out[33]:
⎡50.4902894311622 ⎤
⎢ ⎥
⎢50.4902894311622 ⎥
⎢ ⎥
⎢0.980578862324382⎥
⎢ ⎥
⎢49.5097105688378 ⎥
⎢ ⎥
⎣49.5097105688378 ⎦
In [34]: eqs_sub = [eq.subs(inputs[1]) for eq in eqs]
In [35]: nsolve(eqs_sub, [A, B, I, AI, BI], [1, 1, 1, 1, 1])
Out[35]:
⎡38.3817627411582⎤
⎢ ⎥
⎢62.4209392826439⎥
⎢ ⎥
⎢0.80270202380213⎥
⎢ ⎥
⎢61.6182372588418⎥
⎢ ⎥
⎣37.5790607173561⎦
谢谢,但我对A、B、I、AI、BI的表达式感兴趣,因为它们是剩余变量(A0、B0、I0、k1、k2、k3、k4),所以任何使用A、B、I、AI或BI的表达式都是无用的。我(主要)向您展示了如何达到您想要的效果。然而,最终结果是相当复杂的。看看
BI2
。这将根据您要求的剩余变量给出BI
。这是一个复杂的表达方式,其他的也一样。这就是我没有给出最终答案的原因。谢谢。你能不能再多说一点,为什么在nonlinsolve使用的自动程序挂起的时候,这些手部替代似乎起作用?我不这么认为,还有BI2和其余的根看起来不正确<代码>BI2.subs({A0:100,B0:100,I0:100,k1:1.0,k2:1.0,k3:1.0,k4:1.0})产生nan
。所有正实数都应该给出一个正实数的答案。不确定出了什么问题。nonlinsolve函数在这种情况下速度很慢,因为正如我所说,它正在计算一个大的Groebner基。