python代码
先上代码,如果代码有不懂的地方,可以继续看后面的数学理论依据,算法参考西安交大数值分析教材(李乃成,梅立泉著)
import numpy as np
import matplotlib.pyplot as plt
class conjugate_gradient_method():
"""
共轭梯度法:A是n阶对称正定矩阵
输入:
A:系数矩阵
b:b就是b
n:矩阵阶数
x0:初始向量
precision:精度
输出:
求解结果
"""
def __init__(self,A,b,x0,n,precision):
self.A=np.array(A)
self.n=n
self.precision=precision
self.b=b
self.x0=np.array(x0)
self.x=[]
self.x.append(list(x0))
self.iter=0
#计算向量范数
def Norm2(self,p): #p为输入向量
sum_of_p=sum([i**2 for i in p])
return sum_of_p**0.5
#共轭梯度法求解
def calculate(self):
r0=self.b-np.dot(self.A,self.x0)
d0=r0
r_pre=r0
d_pre=d0
for k in range(self.n):
temp=np.dot(d_pre.T,self.A)
alpha=np.dot(r_pre.T,r_pre)/np.dot(temp,d_pre)
x=np.array(self.x[-1])+np.dot(alpha,d_pre)
r=self.b-np.dot(self.A,x)
self.x.append(list(x))
if self.Norm2(r)<=self.precision:
self.iter=k+1
break
else:
beta=(self.Norm2(r)**2)/(self.Norm2(r_pre)**2)
d=r+beta*d_pre
r_pre = r
d_pre = d
print("计算结果为:",self.x[-1])
#各个分量的差的绝对值求和
def c_error(self,a,b):
result=[]
for j,k in zip(a,b):
temp=np.array(j)-np.array(k)
temp_new=sum([abs(i) for i in temp])
result.append(np.log10(temp_new)) #计算log10
return(np.array(result))
def picture_show(self):
horizontal=np.linspace(0,self.iter-1,len(self.x)-1)
#print(horizontal)
vertical_1=self.x[0:len(self.x)-1]
vertical_2=[self.x[-1]]*(len(self.x)-1)
vertical=self.c_error(vertical_1,vertical_2)
#print(vertical)
plt.plot(horizontal,vertical)
plt.title("error")
plt.xlabel("iter")
plt.ylabel("log10-error")
plt.show()
#############测试################
if __name__ == "__main__":
n=200
#构造向量b
b=[0]*n
b[-1]=-1
b[0]=-1
#构造矩阵A
A=np.zeros((n,n))
for i in range(n):
for j in range(n):
if i==0:
A[i][0]=-2
A[i][1]=1
elif i==n-1:
A[i][n-1]=-2
A[i][n-2]=1
elif i==j:
A[i][j]=-2
A[i][j-1]=1
A[i][j+1]=1
print(A)
print(b)
x0=[0]*n #初始值向量
precision=0.001
my_cgm=conjugate_gradient_method(A,b,x0,n,precision) #初始化
my_cgm.calculate() #使用共轭梯度法求解
print("迭代次数:", my_cgm.iter)
my_cgm.picture_show() #显示收敛速度
共轭梯度法原理
共轭梯度法是把求解线性方程组的问题转化为求解一个与之等价的二次函数极小化的问题,从任意给定的初始点出发,沿一组关于矩阵A的共轭方向进行线性搜索,在无舍入误差的假定下,最多迭代n次(n为矩阵的阶数),就可以求得二次函数的极小点,也就求得了线性方程组Ax=b的解。
共轭梯度法在形式上具有迭代法的特征,给定初始向量x(0),由迭代格式
产生的迭代序列x(1),x(2),x(3),… 在无舍入误差的假定下,最多经过n次迭代就可求得f(x)的最小点。
算法伪代码