矩阵求解方法(矩阵迭代求解方法)
矩阵求解方法(矩阵迭代求解方法)
矩阵的求解可以分为直接求解方法和迭代求解方法,这里对部分常用的方法进行了列举主要分为迭代法和直接求解法两类,语言基于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))          




