enter image description hereThe methods for solving systems of linear equations themselves work correctly. Tested with solve. But when trying to solve a large number of matrices, some solution vectors do not converge with the true ones, and therefore a normal distribution for the error does not obtain. The histograms above show that several values ​​are very large - these are incorrectly solved systems of linear equations. Such cases were derived and solved separately by the same functions, but the correct solution was obtained

import numpy as np
import matplotlib.pyplot as plt

def calculate_relative_error(true_solution, computed_solution):
    n = len(true_solution)

    rmse = np.sqrt(np.sum((true_solution - computed_solution)**2))/n
    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) == 0:
        generate_random_matrix(n)

    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) == 0:
        tridiagonal_matrix(n=6)

    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]]

        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 = [0] * n

    for i in range(1, n):
        if i != n - 1:
            gamma.append(-A[i][i + 1] / (A[i][i - 1] * gamma[i - 1] + A[i][i]))
        beta.append((b[i] - A[i][i - 1] * beta[i - 1]) / (A[i][i - 1] * gamma[i - 1] + A[i][i]))

    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):
        A_random = generate_random_matrix(6)
        A = A_random.copy()
        A_tridiagonal = tridiagonal_matrix(6)

        b = np.array([1, 1, 1, 1, 1, 1]).astype(np.float64)
     
        true_solution = gauss(A_random, b, pivoting=True)

        computed_solution = None
        if method == "gauss_no_pivoting":
            computed_solution = gauss(A_random.copy(), b.copy(), pivoting=False)
        elif method == "thomas":
            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()

我不明白异常大的sup_NORAME和RMSE值​​出现在哪里,它们阻止了正态分布的获得.正如您在直方图中看到的那样,所有真值​​都接近第一列,因此它们累积在图形上的一个位置.我想要消除这样的大错误

推荐答案

你没有在你的随机 Select 中纠正被阻止的奇异矩阵.

如果您try 绘制np.linalg.det(A)vsrmse,您将会看到,只有当决定式非常接近0时,才会出现RMSE的高值

增列

determinants.append(np.linalg.det(A))

errors_rmseerrors_sup_norm的相似线之后,

然后如果你策划

plt.scatter(determinants, errors_rmse)

enter image description here

Or in logarithmic scale enter image description here

try 限制随机 Select 的矩阵,以明确非奇异矩阵,那么你永远不会看到均方根误差

您试图防止奇异矩阵的方法中有两个错误

错误1:递归错误

以下代码无效:

    while np.linalg.det(A) == 0:
        tridiagonal_matrix(n=6)
    return A

它递归地回调tridiagonal_matrix,但会丢弃结果. 所以你在最后返回的只是原始的A,即使它的行列式是0.

注意,一个校正可以是

    while np.linalg.det(A) == 0:
        A=tridiagonal_matrix(n=6)
    return A

但如果你认为它是从递归噩梦开始的. while和递归在这里有点多余 如果你想使用递归,你可以这样做

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)
    if np.linalg.det(A) == 0:
        return tridiagonal_matrix(n)
    return A

这将是在方案或Caml中做到这一点的优雅方式. 但在Python 领域,情况就没那么糟了.因为Python不是一种终端递归语言.这意味着如果它在找到矩阵之前持续太长时间,它将因为堆栈溢出而失败(同名错误)

因此,最好放弃递归,保留While

def tridiagonal_matrix(n):
    while True:
        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)
        if np.linalg.det(A)!=0:
            return A

如果你真的想避免这while True: ... if ...: break条(有些人教条地拒绝任何while True条),你可以

def tridiagonal_matrix(n):
    A=np.array([[0]])
    while np.linalg.det(A)==0:
        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

错误2:从不将浮点数与==进行比较

不是==0岁不是一个充分条件.首先,浮点数不是精确的数字.参见臭名昭著的0.1+0.2!=0.3.

其次,因此,即使与精确的数字(如0)进行比较,由于数字误差的累积,大多数0永远不是精确的0.

为了在线性代数上下文中重用我之前的0.1+0.2-0.3示例, np.linalg.det(0.1*np.identity(6)+0.2*np.identity(6)-0.3*np.identity(6))不是0.

所以你总是需要宽容.在这种情况下,因为你显然只是想判断方法的数值误差(而不是初始矩阵的误差),所以公差没有理由非常宽松.

所以我会

def generate_random_matrix(n = 6 ):
    while True:
        A = (np.random.random((n, n)).astype(np.float64) * 2 - 1).astype(np.float64)
        if not np.isclose(np.linalg.det(A),0, atol=0.1):
            return A

def tridiagonal_matrix(n):
    while True:
        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)
        if not np.isclose(np.linalg.det(A),0, atol=0.1):
            return A

但如果这对你的需求来说"太容易",你可以减少atol

用这种方法确保矩阵不是奇异的,你就得到了你想要的"高斯"方法的结果

enter image description here

并证明您的Thomas实现存在问题 (您最初的直方图似乎显示了一些几乎总是有效的东西.但这是因为由于奇异矩阵导致的巨大均方根误差的情况很少.但是,如果您删除奇异矩阵,从而放大"0"条,您会发现一般情况下RMSE总是太大.其中"RMSE≈0"只是一个随机的RMSE值,不比其他值更有可能)

enter image description here

tl;dr

  1. 这种分布是由奇异矩阵引起的
  2. 当矩阵是单数时,您的"重试"方式被忽略,因为您总是返回第一次try
  3. 您测试矩阵是否为单一矩阵(DET==0)的方法过于严格.在浮点数的数值计算中,总是有一个公差
  4. 一旦真正避免了奇异矩阵,您会看到分布集中在非常低的Gauss误差值上.即使这种分布的极少数极值也仍然很低(最多10⁻?⁰的数量级)
  5. 另一方面,一旦托马斯真正避免了奇异矩阵,你会看到这个分布,当然,不包含错误的疯狂值,但RMSE 1是一个非常典型的情况,简单地证明你的托马斯实现不起作用(它不是"在某些奇怪的情况下不起作用";它永远不起作用,而且几个0 -很明显,如果你只放大第一个条,你会看到这个0条是由很多0.2,0.3,0.4,0.8,...... - 极少数的"在数值误差范围内=0"就像一天中有两次停止的时钟是正确的).

因为这不是您的问题,而且我有点懒,所以我不会试图理解为什么Thomas实现不起作用,但它不起作用.我猜你最初的目标是看看它是否工作,所以任务完成了:d

Python相关问答推荐

如何确保Flask应用程序管理面板中的项目具有单击删除功能?

在有限数量的唯一字母的长字符串中,找到包含重复不超过k次的所有唯一字母的最长子字符串

使用decorator 自动继承父类

解析讨论论坛只给我第一个用户 comments ,但没有给我其他用户回复

pandas DataFrame中类型转换混乱

"Discord机器人中缺少所需的位置参数ctx

使用matplotlib pcolormesh,如何停止从一行绘制的磁贴连接到上下行?

基本链合同的地址是如何计算的?

如何防止Plotly在输出到PDF时减少行中的点数?

仅从风格中获取 colored颜色 循环

使用SciPy进行曲线匹配未能给出正确的匹配

try 与gemini-pro进行多轮聊天时出错

如何获取TFIDF Transformer中的值?

用合并列替换现有列并重命名

C#使用程序从Python中执行Exec文件

Julia CSV for Python中的等效性Pandas index_col参数

Python虚拟环境的轻量级使用

导入...从...混乱

无法在Docker内部运行Python的Matlab SDK模块,但本地没有问题

pysnmp—lextudio使用next()和getCmd()生成器导致TypeError:tuple对象不是迭代器''