如何用Python求解各种复杂的线性/非线性方程组
Python求解各种复杂的线性/非线性方程组
本文将要介绍几种方法去求解各种复杂的方程组,包括实数域和复数域的线性、非线性方程组,并对比这几种方法的优缺点。本文用到了numpy、scipy、sympy这三个科学计算包。
一、线性方程组。
线性方程组可以用numpy去求解。
1.实数域。
import numpy as np
a=np.mat('1,2,3;2,4,8;9,6,3')
b=np.mat('1;1;3')
c=np.linalg.solve(a,b)
输出如下:
2.复数域。
import numpy as np
a=np.mat('1,-1j;1j,-1')
b=np.mat('1;1')
c=np.linalg.solve(a,b)
输出如下:
二、非线性方程组。
scipy和sympy不但可以解线性方程(组),还可以求解非线性方程(组),但是也有各自的优缺点。
1.scipy求解
scipy.optimize里面有两个函数可以数值求解方程组,分别是root和solve,这两个函数会找到方程组的一个近似解。下面通过例子介绍这两个函数的使用。
(1).root
scipy.optimize.root(fun, x0, args=(), method=‘hybr’, jac=None, tol=None, callback=None, options=None)
其中参数fun是一个函数,你需要定义这个函数,并且你定义的这个函数返回一个方程组。 参数x0是方程组解的初始猜测值,是必须要指定的参数,root函数将找到最靠近x0的一个解。参数args是函数fun的额外参数。参数method默认是‘hybr’,此参数还可以取 ‘lm’ ‘broyden1’ ‘broyden2’ ‘anderson’ ‘linearmixing’ ‘diagbroyden’ ‘excitingmixing’ ‘krylov’ ‘df-sane’,代表采用不同的算法去求解。参数tol可以认为是精度。
先来看看实数域的例子
from scipy.optimize import root
def f1(x):
return [x[0]+x[0]*x[1]-2,x[0]-x[1]-2]
print(root(f1,[0,-1]).x)#初始猜测值[0,-1]
print(root(f1,[0,0]).x)#初始猜测值[0,0]
输出如下:
求出的近似解与真解相差非常小。设置不同的初始猜测值可能得到不同的解,这是因为有的方程组的解不一定只有一个,可能有多个解,root函数会得到最接近初始猜测值的一个解。
此外,在上面的基础上我们可以设置参数jac来提高运算速度(尤其是计算量很大时效果很明显)。
我们需要再定义一个函数,这个函数返回值是方程组对应的雅可比矩阵,通过下面的例子说明。
from numpy import array,mat,sin,cos,exp
from scipy.optimize import root
def f(x):
eqs=[]
eqs.append(x[0]*x[1]+x[1]*x[2]+sin(x[0])*exp(x[1])+x[1])
eqs.append(x[0]*x[1]-exp(x[0])*x[1]+1)
eqs.append(x[1]*x[2]+exp(x[1])*x[2]+1)
return eqs
def jac1(x):#方程组对应的雅可比矩阵
return mat([[x[1]+cos(x[0])*exp(x[1]), x[0]+x[2]+sin(x[0])*exp(x[1])+1, x[1]],
[x[1]-exp(x[0