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

时间:2012-01-05 07:49:49

标签: python numpy scipy sympy

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

例如:

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

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

9 个答案:

答案 0 :(得分:65)

对于数值解,你可以使用fsolve:

http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.fsolve.html#scipy.optimize.fsolve

from scipy.optimize import fsolve
import math

def equations(p):
    x, y = p
    return (x+y**2-4, math.exp(x) + x*y - 3)

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

print equations((x, y))

答案 1 :(得分:27)

如果您更喜欢同情,可以使用nsolve

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

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

答案 2 :(得分:2)

试试这个,我向你保证它会完美运作。

    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

FYI。如上所述,您也可以使用'broyden1'替换'fsolve'来代表'Broyden'。有用。我做到了。

我不确切知道Broyden的近似是如何工作的,但它需要0.02秒。

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

答案 3 :(得分: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])

答案 4 :(得分:1)

您可以使用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]

答案 5 :(得分:1)

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

http://docs.scipy.org/doc/scipy/reference/generated/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的第一个雅可比近似值找到函数的根。

     

这种方法也被称为“Broyden的好方法”。

答案 6 :(得分:0)

fsolve的替代方法是root

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]

确认解决方案正确。

答案 7 :(得分:0)

简短答案:使用fsolve

如其他答案所述,针对您所提出的特定问题的最简单解决方案是使用类似fsolve的内容:

from scipy.optimize import fsolve
from math import exp

def f(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通常可以为您找到它们:

In [29]: from sympy import *                                                                                                                                  

In [30]: x, y = symbols('x, y')                                                                                                                               

In [31]: eq1 = Eq(x+y**2, 4)                                                                                                                                  

In [32]: eq2 = Eq(x**2 + y, 4)                                                                                                                                

In [33]: solve([eq1, eq2], [x, y])                                                                                                                            
Out[33]: 
⎡⎛ ⎛  5   √17⎞ ⎛3   √17⎞    √17   1⎞  ⎛ ⎛  5   √17⎞ ⎛3   √17⎞    1   √17⎞  ⎛ ⎛  3   √13⎞ ⎛√13   5⎞  1   √13⎞  ⎛ ⎛5   √13⎞ ⎛  √13   3⎞  1   √13⎞⎤
⎢⎜-⎜- ─ - ───⎟⋅⎜─ - ───⎟, - ─── - ─⎟, ⎜-⎜- ─ + ───⎟⋅⎜─ + ───⎟, - ─ + ───⎟, ⎜-⎜- ─ + ───⎟⋅⎜─── + ─⎟, ─ + ───⎟, ⎜-⎜─ - ───⎟⋅⎜- ─── - ─⎟, ─ - ───⎟⎥
⎣⎝ ⎝  2    2 ⎠ ⎝2    2 ⎠     2    2⎠  ⎝ ⎝  2    2 ⎠ ⎝2    2 ⎠    2    2 ⎠  ⎝ ⎝  2    2 ⎠ ⎝ 2    2⎠  2    2 ⎠  ⎝ ⎝2    2 ⎠ ⎝   2    2⎠  2    2 ⎠⎦

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

数值解的精度

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

已经接受我们希望像fsolve这样的数值解通常可以满足您的所有需求。对于此类问题,SymPy可能会慢得多,但它可以提供其他一些东西,可以更精确地找到(数字)解决方案:

In [50]: from sympy import *                                                                                                                                  

In [51]: x, y = symbols('x, y')                                                                                                                               

In [52]: nsolve([Eq(x+y**2, 4), Eq(exp(x)+x*y, 3)], [x, y], [1, 1])                                                                                           
Out[52]: 
⎡0.620344523485226⎤
⎢                 ⎥
⎣1.83838393066159 ⎦

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

答案 8 :(得分:0)

您可以使用nsolve中的sympy,表示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)是查找根的初始向量。它给出了:

enter image description here

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