矩阵计算全过程(矩阵迭代求解方法)
矩阵的求解可以分为直接求解方法和迭代求解方法,这里对部分常用的方法进行了列举主要分为迭代法和直接求解法两类,语言基于python,把这些算法做了相应的封装写成了一个类,并给出了一些方程组供测试,很多算法来自互联网,就不一一致谢了。
迭代求解算法,主要有雅克比,高斯-赛德尔,超松弛,共轭梯度,并与numpy库中自带的一些函数做了对比,主要是求解时间和求解结果的。有时间再把原理相关的描述写下来。
"""
Created on 2022/1/25 10:45
@Author: 123
@Email: 985040320@qq.com
@Describe: **加入文件描述, 要实现的功能, 注意事项等**
"""
import numpy as np
import time
from scipy.sparse import csr_matrix
import scipy
class Iteration:
def __init__(self, A, x, b):
self.A = A
self.b = b
self.x = x
def Jacobi(self, n):
# 设Ax= b,其中A=D L U为非奇异矩阵,且对角阵D也非奇异,则当迭代矩阵J的谱半径ρ(J)<1时,雅克比迭代法收敛。
times = 0
# D = np.diag(np.diag(self.A))
L = -np.array(np.tril(self.A, -1))
U = -np.array(np.triu(self.A, 1))
D_inv = np.diag(1/np.diag(self.A))
while times < n:
xnew = self.x
self.x = D_inv.dot(self.b L.dot(self.x) U.dot(self.x))
if abs(self.x-xnew).max() < 0.000000001:
break
times = 1
return self.x.flatten()
def Gauss_Seidel(self, n):
# 需要系数矩阵对称正定或者严格对角占优
times = 0
D = np.diag(np.diag(self.A))
L = -np.array(np.tril(self.A, -1))
U = -np.array(np.triu(self.A, 1))
D_L_inv = np.linalg.inv((D - L))
while times < n:
xnew = self.x
self.x = D_L_inv.dot((b U.dot(self.x)))
if abs(self.x-xnew).max() < 0.000000001:
break
times = 1
return self.x.flatten()
def Successive_Over_Relaxation(self, omega, n):
# 限定条件较少,适用性更普遍
times = 0
D = np.diag(np.diag(self.A))
L = -np.array(np.tril(self.A, -1))
U = -np.array(np.triu(self.A, 1))
D_omega_inv = np.linalg.inv((D - omega * L))
while times < n:
xnew = self.x
self.x = D_omega_inv.dot((omega * b) ((1 - omega) * D).dot(self.x) (omega * U).dot(self.x))
if abs(self.x-xnew).max() < 0.0000000001:
break
times = 1
return self.x.flatten()
def conj_gradient(self, tol, limit):
# 系数矩阵必须对称正定,对称正定可以Cholesky分解
n = self.A.shape[0]
p = np.zeros((n, 1))
r = np.zeros((n, 1))
u = np.zeros((n, 1))
xnew = np.zeros((n, 1))
r = b - np.dot(A, self.x) # 计算r0
p = r.copy() # 计算p0
iters = 0
while True:
iters = iters 1
u = np.dot(self.A, p)
up = np.dot(r.T, r)
alpha = np.dot(r.T, r) / np.dot(p.T, u)
# print("alpha", alpha.flatten())
r = r - u * alpha
# print("r", r.flatten())
xnew = self.x p * alpha
# print("x", xnew.flatten())
beta = np.dot(np.transpose(r), r) / up
p = r p * beta
# print("p", p.flatten())
if abs(xnew - self.x).max() < tol or iters == limit:
break
self.x = xnew
return self.x.flatten()
if __name__ == "__main__":
n = 800
emega = 0.5
tol = 0.0000001
itertimemax = 100
# 测试方程组1
A = np.array([[2, -1, 0], [-1, 3, -1], [0, -1, 2]])
x = np.array([[1], [8], [5]])
b = np.array([[1], [8], [5]])
# 测试方程组2
# A = np.array([[1., 1.], [1., -1.]])
# x = np.array([[0.], [0.]])
# b = np.array([[5.], [1.]])
# 测试方程组3
# A = np.array([[16, 4, 8], [4, 5, -4], [8, -4, 22]], dtype=float)
# b = np.array([[4], [2], [5]], dtype=float)
# x = np.array([[1], [1], [1]], dtype=float)
#测试方程组4
# A = np.array([[1, -1, 0, 0], [-0.1, 1, -0.9, 0], [0, -0.9, 1, -0.1], [0, 0, 0, 1]], dtype=float)
# b = np.array([[9], [0], [0], [0]], dtype=float)
# x = np.array([[19], [10], [1],[0]], dtype=float)
# 共轭梯度
t1 = time.time()
Obj = Iteration(A, x, b)
results1 = Obj.conj_gradient(tol, itertimemax)
t2 = time.time()
# 超松弛
t1 = time.time()
Obj = Iteration(A, x, b)
results = Obj.Successive_Over_Relaxation(emega, n)
t2 = time.time()
print(results, f"超松弛耗时{t1-t2}")
# 高斯赛德尔
t1 = time.time()
Obj = Iteration(A, x, b)
results = Obj.Gauss_Seidel(n)
t2 = time.time()
print(results, f"高斯赛德尔耗时{t1-t2}")
# 雅克比
t1 = time.time()
Obj = Iteration(A, x, b)
results = Obj.Jacobi(n)
t2 = time.time()
print(Obj.Jacobi(n), f"雅克比耗时{t1-t2}")
# 测试函数
t1 = time.time()
results = np.linalg.solve(A, b)
t2 = time.time()
print(results.flatten(), f"测试函数耗时{t1 - t2}")
除了上面所用到的迭代算法,这里还介绍一种处理CFD这种会遇到的三对角或者五对角矩阵的迭代求解算法,三对角算法,也算迭代算法只不过这种矩阵刚好容易出现在网格离散之后的方程组里面。
import numpy as np
class IntSlve:
def __init__(self, A, b):
self.A = A.copy()
self.b = b.copy()
self.nf = len(b)
def TDMASolver(self):
a_1 = np.zeros(self.nf-1)
b_1 = np.zeros(self.nf)
c_1 = np.zeros(self.nf)
for i in range(self.nf): # 矩阵分解为三条对角线上的元素
if i < self.nf-1:
c_1[i] = self.A[i, i 1]
a_1[i] = self.A[i 1, i]
b_1[i] = self.A[i, i]
else:
b_1[i] = self.A[i, i]
ac, bc, cc, dc = map(np.array, (a_1, b_1, c_1, self.b))
for it in range(1, self.nf):
mc = ac[it - 1] / bc[it - 1]
bc[it] = bc[it] - mc * cc[it - 1]
dc[it] = dc[it] - mc * dc[it - 1]
xc = bc
xc[-1] = dc[-1] / bc[-1]
for il in range(self.nf - 2, -1, -1):
xc[il] = (dc[il] - cc[il] * xc[il 1]) / bc[il]
return xc
if __name__ == "__main__":
A = np.array([[10, 2, 0, 0],[3,10,4,0],[0,1,7,5],[0,0,3,4]],dtype=float)
d = np.array([3, 4, 5, 6.])
sol = IntSlve(A, d)
print(sol.TDMASolver())
# 数据对比
print(np.linalg.solve(A, d))
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com