如何使用Python解决一对非线性方程式?


73

使用Python解决一对非线性方程式的(最佳)方法是什么?(Numpy,Scipy或Sympy)

例如:

  • x + y ^ 2 = 4
  • e ^ x + xy = 3

解决以上问题的代码片段会很棒


是的,我知道。.我希望在python中执行此操作,因为我想针对不同的方程组重复执行该操作
AIB 2012年

您可以import sage从任何Python脚本中获取。
Blender 2012年

2
sage通过作为sympy和maxima的包装器来做到这一点,因此您可以直接使用它们。
endlith 2014年

Answers:



30

如果您喜欢sympy,则可以使用nsolve

>>> nsolve([x+y**2-4, exp(x)+x*y-3], [x, y], [1, 1])
[0.620344523485226]
[1.83838393066159]

第一个参数是方程式列表,第二个参数是变量列表,第三个参数是初始猜测。


1
我在此答案中的代码中收到错误“名称y未定义”。
Sander Heinsalu '18年

@SanderHeinsalu,请按照错误消息的意思进行操作。如果“名称y未定义”,则对其进行定义(python无法神奇地知道您想要的未定义变量是什么)。例如,在这里您希望y是一个符号对象,可以用来构建更大的符号对象:y = Symbol('symbol_name_string')。可能您想要保留相同的符号名称,因此y = Symbol('y')
克拉斯坦诺夫'18

8

简短答案:使用fsolve

正如其他答案中提到的那样,针对您提出的特定问题的最简单解决方案是使用类似以下内容的方法fsolve

from scipy.optimize import fsolve
from math import exp

def equations(vars):
    x, y = vars
    eq1 = x+y**2-4
    eq2 = exp(x) + x*y - 3
    return [eq1, eq2]

x, y =  fsolve(equations, (1, 1))

print(x, y)

输出:

0.6203445234801195 1.8383839306750887

分析解决方案?

您说了如何“解决”,但是有不同的解决方案。既然你提到SymPy我要指出什么之间这个最大的区别可能意味着这是之间的分析数字解决方案。您给出的特定示例是一个没有(简单)解析解的示例,而其他非线性方程组则具有。当有现成的分析解决方案时,SymPY通常可以为您找到它们:

from sympy import *

x, y = symbols('x, y')
eq1 = Eq(x+y**2, 4)
eq2 = Eq(x**2 + y, 4)

sol = solve([eq1, eq2], [x, y])

输出:

⎡⎛ ⎛  517⎞ ⎛317⎞    √17   1⎞  ⎛ ⎛  517⎞ ⎛317117⎞  ⎛ ⎛  313⎞ ⎛√13   5113⎞  ⎛ ⎛513⎞ ⎛  √13   3113⎞⎤
⎢⎜-⎜- ─ - ───⎟⋅⎜─ - ───⎟, - ─── - ─⎟, ⎜-⎜- ─ + ───⎟⋅⎜─ + ───⎟, - ─ + ───⎟, ⎜-⎜- ─ + ───⎟⋅⎜─── + ─⎟, ─ + ───⎟, ⎜-⎜─ - ───⎟⋅⎜- ─── - ─⎟, ─ - ───⎟⎥
⎣⎝ ⎝  2    2 ⎠ ⎝2    22    2⎠  ⎝ ⎝  2    2 ⎠ ⎝2    22    2 ⎠  ⎝ ⎝  2    2 ⎠ ⎝ 2    22    2 ⎠  ⎝ ⎝2    2 ⎠ ⎝   2    22    2 ⎠⎦

请注意,在此示例中,SymPy查找所有解决方案,不需要给出初始估计。

您可以使用以下方法对这些解决方案进行数字评估evalf

soln = [tuple(v.evalf() for v in s) for s in sol]
[(-2.56155281280883, -2.56155281280883), (1.56155281280883, 1.56155281280883), (-1.30277563773199, 2.30277563773199), (2.30277563773199, -1.30277563773199)]

数值解的精度

但是,大多数非线性方程组系统都没有合适的解析解,因此,如上使用SymPy可以很好地工作,但通常不适用。这就是为什么即使有数值解,我们最终还是要寻找数值解的原因:1)我们不能保证我们找到了所有解或有很多解的“正确”解。2)我们必须提供一个初步的猜测,但这并不总是那么容易。

接受了我们想要数值解法之后,fsolve通常会做您需要的所有事情。对于此类问题,SymPy可能会慢得多,但它可以提供其他一些可以更精确地找到(数字)解决方案的方法:

from sympy import *

x, y = symbols('x, y')
nsolve([Eq(x+y**2, 4), Eq(exp(x)+x*y, 3)], [x, y], [1, 1])
0.620344523485226⎤
⎢                 ⎥
⎣1.83838393066159

精度更高:

nsolve([Eq(x+y**2, 4), Eq(exp(x)+x*y, 3)], [x, y], [1, 1], prec=50)
0.62034452348522585617392716579154399314071550594401⎤
⎢                                                    ⎥
⎣ 1.838383930661594459049793153371142549403114879699

1
不知道为什么这不是最投票的答案,但是,有没有办法将SymPy提供的分析解决方案转换为近似数值列表?据我了解,找到所有解决方案的唯一方法是通过分析方法,但是将这些解决方案转换可能会非常有用。
爱德华多·塞拉

1
您可以使用expr.evalf()以下方法
Oscar Benjamin,

2
我添加了一个关于逃逸的例子
奥斯卡·本杰明

非常感谢你!
Edoardo Serra

抱歉,另一个问题。我如何才能将实际解决方案与复杂解决方案分开,例如仅显示实际解决方案?
Edoardo Serra

4

试试这个,我向您保证它会完美运行。

    import scipy.optimize as opt
    from numpy import exp
    import timeit

    st1 = timeit.default_timer()

    def f(variables) :
        (x,y) = variables

        first_eq = x + y**2 -4
        second_eq = exp(x) + x*y - 3
        return [first_eq, second_eq]

    solution = opt.fsolve(f, (0.1,1) )
    print(solution)


    st2 = timeit.default_timer()
    print("RUN TIME : {0}".format(st2-st1))

->

[ 0.62034452  1.83838393]
RUN TIME : 0.0009331008900937708

仅供参考。如上所述,您也可以通过将“ fsolve”替换为“ broyden1”来使用“ Broyden近似”。有用。我做的。

我不确切知道Broyden的近似值是如何工作的,但是花了0.02 s。

而且我建议您不要使用Sympy的功能<-确实很方便,但是就速度而言,它相当慢。你会看见。


3

我得到了Broyden的方法用于IDL中耦合非线性方程(通常涉及多项式和指数)的方法,但是我没有在Python中尝试过:

http://docs.scipy.org/doc/scipy/reference/generation/scipy.optimize.broyden1.html#scipy.optimize.broyden1

scipy.optimize.broyden1

scipy.optimize.broyden1(F, xin, iter=None, alpha=None, reduction_method='restart', max_rank=None, verbose=False, maxiter=None, f_tol=None, f_rtol=None, x_tol=None, x_rtol=None, tol_norm=None, line_search='armijo', callback=None, **kw)[source]

使用Broyden的第一个Jacobian逼近找到一个函数的根。

这种方法也被称为“布罗登的好方法”。


2
为什么这被否决了?似乎是合法的前进方法……
aquirdturtle

2

您可以使用openopt软件包及其NLP方法。它有许多动态编程算法来解决由非线性代数方程组:
goldenSection,scipy_fminbound,scipy_bfgs,scipy_cg,scipy_ncg,amsg2p,scipy_lbfgsb,scipy_tnc,bobyqa,ralg,ipopt,scipy_slsqp,scipy_cobyla,lincher,algencan,您可以从中选择。
后一种算法可以解决约束非线性规划问题。因此,您可以使用以下函数将方程组引入openopt.NLP()

lambda x: x[0] + x[1]**2 - 4, np.exp(x[0]) + x[0]*x[1]


2
from scipy.optimize import fsolve

def double_solve(f1,f2,x0,y0):
    func = lambda x: [f1(x[0], x[1]), f2(x[0], x[1])]
    return fsolve(func,[x0,y0])

def n_solve(functions,variables):
    func = lambda x: [ f(*x) for f in functions]
    return fsolve(func, variables)

f1 = lambda x,y : x**2+y**2-1
f2 = lambda x,y : x-y

res = double_solve(f1,f2,1,0)
res = n_solve([f1,f2],[1.0,0.0])

2

的替代方法fsolveroot

import numpy as np
from scipy.optimize import root    

def your_funcs(X):

    x, y = X
    # all RHS have to be 0
    f = [x + y**2 - 4,
         np.exp(x) + x * y - 3]

    return f

sol = root(your_funcs, [1.0, 1.0])
print(sol.x)

这将打印

[0.62034452 1.83838393]

如果您再检查

print(your_funcs(sol.x))

你得到

[4.4508396968012676e-11, -1.0512035686360832e-11]

确认解决方案正确。


0

您可以使用nsolvesympy意思numerical solver

示例片段:

from sympy import *

L = 4.11 * 10 ** 5
nu = 1
rho = 0.8175
mu = 2.88 * 10 ** -6
dP = 20000
eps = 4.6 * 10 ** -5

Re, D, f = symbols('Re, D, f')

nsolve((Eq(Re, rho * nu * D / mu),
       Eq(dP, f * L / D * rho * nu ** 2 / 2),
       Eq(1 / sqrt(f), -1.8 * log ( (eps / D / 3.) ** 1.11 + 6.9 / Re))),
      (Re, D, f), (1123, -1231, -1000))

在哪里(1123, -1231, -1000)找到根的初始向量。它给出了:

在此处输入图片说明

虚部很小,均为10 ^(-20),因此我们可以认为它们为零,这意味着根都是实数。稀土〜13602.938,D〜0.047922和f〜0.0057。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.