You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线性方程组求解中高斯/追赶法异常大误差问题排查

问题排查与修复方案

核心错误分析

你的代码存在三个关键问题,直接导致批量测试时出现异常大误差:

1. 矩阵生成函数未正确替换奇异矩阵

generate_random_matrix和tridiagonal_matrix中,当生成的矩阵行列式接近0(奇异矩阵)时,递归调用自身但未将新矩阵赋值给原变量,最终返回的还是初始的奇异矩阵。奇异矩阵无法唯一求解方程组,会引发消去过程中除以0或数值溢出,产生极大误差。

2. Thomas方法的真实解与求解方程组不匹配

测试Thomas方法时,你用随机矩阵A_random的解作为真实解,但Thomas实际求解的是三对角矩阵A_tridiagonal对应的方程组——这是完全不同的两个线性系统,计算出的误差毫无意义,必然出现大量异常值。

3. RMSE计算不符合标准定义

你的RMSE计算是np.sqrt(np.sum((true - computed)**2))/n,但标准RMSE应为平方误差平均值的平方根,即np.sqrt(np.mean((true - computed)**2))。这虽不是异常值的核心原因,但会导致误差数值解读偏差。

修复后的完整代码

import numpy as np
import matplotlib.pyplot as plt

def calculate_relative_error(true_solution, computed_solution):
    n = len(true_solution)
    # 修正RMSE为标准定义
    rmse = np.sqrt(np.mean((true_solution - computed_solution)**2))
    sup_norm = np.max(np.abs(true_solution - computed_solution))
    return rmse, sup_norm

def generate_random_matrix(n = 6 ):
    A = (np.random.random((n, n)).astype(np.float64) * 2 - 1).astype(np.float64)
    # 用循环替换递归,避免栈溢出,同时用阈值判断奇异矩阵
    while np.linalg.det(A) < 1e-10:
        A = (np.random.random((n, n)).astype(np.float64) * 2 - 1).astype(np.float64)
    return A

def tridiagonal_matrix(n):
    main_diag = (np.random.random(n).astype(np.float64) * 2 - 1).astype(np.float64)
    sub_diag = (np.random.random(n-1).astype(np.float64) * 2 - 1).astype(np.float64)
    super_diag = (np.random.random(n-1).astype(np.float64) * 2 - 1).astype(np.float64)

    A = np.diag(main_diag) + np.diag(sub_diag, k=-1) + np.diag(super_diag, k=1)
    # 循环生成非奇异三对角矩阵
    while np.linalg.det(A) < 1e-10:
        main_diag = (np.random.random(n).astype(np.float64) * 2 - 1).astype(np.float64)
        sub_diag = (np.random.random(n-1).astype(np.float64) * 2 - 1).astype(np.float64)
        super_diag = (np.random.random(n-1).astype(np.float64) * 2 - 1).astype(np.float64)
        A = np.diag(main_diag) + np.diag(sub_diag, k=-1) + np.diag(super_diag, k=1)
    return A

def gauss(A, b, pivoting):
    n = len(b)
    a = np.hstack((A, b[:, np.newaxis])).astype(np.float64)

    for i in range(n):
        if pivoting:
            max_index = np.argmax(np.abs(a[i:, i])) + i
            a[[i, max_index]] = a[[max_index, i]]
        
        # 添加极小值判断,避免除以0导致数值溢出
        if np.abs(a[i, i]) < 1e-15:
            raise ValueError("Singular matrix encountered in Gaussian elimination")

        for j in range(i + 1, n):
            factor = a[j, i] / a[i, i]
            a[j, i:] -= factor * a[i, i:]

    x = np.zeros(n, dtype=np.float64)
    for i in range(n - 1, -1, -1):
        x[i] = (a[i, -1] - np.dot(a[i, i + 1:-1], x[i + 1:])) / a[i, i]
    return x

def thomas(A, b):
    gamma = [-A[0][1] / A[0][0]]
    beta = [b[0] / A[0][0]]

    n = len(b)
    x = np.zeros(n, dtype=np.float64)  # 改用numpy数组提升效率

    for i in range(1, n):
        denominator = A[i][i - 1] * gamma[i - 1] + A[i][i]
        # 避免分母过小导致数值不稳定
        if np.abs(denominator) < 1e-15:
            raise ValueError("Singular tridiagonal matrix encountered")
        if i != n - 1:
            gamma.append(-A[i][i + 1] / denominator)
        beta.append((b[i] - A[i][i - 1] * beta[i - 1]) / denominator)

    x[n - 1] = beta[n - 1]

    for i in range(n - 2, -1, -1):
        x[i] = gamma[i] * x[i + 1] + beta[i]

    return x

num_matrices = 1000
methods = ["gauss_no_pivoting", "thomas"]

for method in methods:
    errors_rmse = []
    errors_sup_norm = []

    for _ in range(num_matrices):
        b = np.array([1, 1, 1, 1, 1, 1]).astype(np.float64)
        computed_solution = None
        true_solution = None

        if method == "gauss_no_pivoting":
            A_random = generate_random_matrix(6)
            true_solution = gauss(A_random, b, pivoting=True)
            computed_solution = gauss(A_random.copy(), b.copy(), pivoting=False)
        elif method == "thomas":
            A_tridiagonal = tridiagonal_matrix(6)
            true_solution = gauss(A_tridiagonal, b, pivoting=True)  # 修正真实解对应正确矩阵
            computed_solution = thomas(A_tridiagonal.copy(), b.copy())

        rmse, sup_norm = calculate_relative_error(true_solution, computed_solution)
        errors_rmse.append(rmse)
        errors_sup_norm.append(sup_norm)

    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.hist(errors_rmse, bins=20, color='blue', edgecolor='black')
    plt.title(f'{method} - RMSE Histogram')
    plt.xlabel('RMSE')
    plt.ylabel('Frequency')

    plt.subplot(1, 2, 2)
    plt.hist(errors_sup_norm, bins=20, color='green', edgecolor='black')
    plt.title(f'{method} - Sup Norm Histogram')
    plt.xlabel('Sup Norm')
    plt.ylabel('Frequency')

    plt.tight_layout()
    plt.show()

额外优化说明

  1. 替换递归为循环:矩阵生成用循环代替递归,避免栈溢出且效率更高。
  2. 浮点精度兼容:用极小阈值(如1e-10)判断奇异矩阵,避免浮点计算中严格等于0的误判。
  3. 数值稳定性防护:在消去算法中添加分母极小值判断,提前抛出异常避免数值溢出。
  4. 数据结构优化:Thomas方法中x改用numpy数组,提升计算效率和一致性。

修复后,批量测试的误差会呈现正态分布,异常大误差的情况将被消除。

内容的提问来源于stack exchange,提问作者Elena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:05:54