配合物64分解LU的数值精度

时间:2019-11-28 20:54:47

标签: numpy precision

我正在寻找用于解决复杂 floats 类型(又称为np.complex64)的线性方程组的最准确的类似于C的实现。正要进行LU分解。我想先用numpy实现它,看看一切顺利,然后将实现转换为C。

这是我目前得到的:

import scipy.linalg as la
import numpy as np


def lu_factor(A):
    L, U = np.empty_like(A), np.empty_like(A)
    n = A.shape[0]
    for k in range(n):
        L[k, k] = 1
        U[k, k] = A[k, k] - L[k, :k] @ U[:k, k]
        for j in range(k + 1, n):
            U[k, j] = A[k, j] - L[k, :k] @ U[:k, j]
        for i in range(k + 1, n):
            L[i, k] = (A[i, k] - L[i, :k] @ U[:k, k]) / U[k, k]
    return L, U


def forward_sub(L, b):
    x = np.empty_like(b)
    for i in range(b.size):
        x[i] = (b[i] - L[i, :i] @ x[:i]) / L[i, i]
    return x


def backward_sub(U, b):
    x = np.empty_like(b)
    for i in reversed(range(b.size)):
        x[i] = (b[i] - U[i, i + 1:] @ x[i + 1:]) / U[i, i]
    return x


def lu_solve(A, b):
    L, U = lu_factor(A)
    return backward_sub(U, forward_sub(L, b))


b = np.array([6 + 1j, -4 + 2j, 27 + 3j], dtype=np.complex128)
A = np.array([
    [1 + 4j, 1 + 5j,  1 + 6j],
    [0 + 7j, 2 + 8j,  5 + 9j],
    [2 + 1j, 5 + 2j, -1 + 3j],
], dtype=np.complex128)


x_expected = la.lu_solve(la.lu_factor(A), b)
x = lu_solve(A, b)
np.testing.assert_allclose(x_expected, x)

Ab是随机选择的。注意-它们的类型为np.complex128(复数双精度),“天真的”实现的结果与scipy的实现足够接近。

将类型更改为np.complex64(复杂浮点数)时,我们得到:

Mismatch: 66.7%
Max absolute difference: 1.0612305e-06
Max relative difference: 6.8692873e-07
x: array([ 1.387071-0.680237j,  3.673277+1.09019j , -3.683192-1.225474j], dtype=complex64)
y: array([ 1.387072-0.680236j,  3.673277+1.090189j, -3.683192-1.225474j], dtype=complex64)

e-06对我来说似乎很高。除了“双精度浮点精度”之外,还有很好的解释吗?我到底不是什么numpy / BLAS?可以使用基本操作复制吗?

注意:性能对我来说不是问题,我只关心精度。

1 个答案:

答案 0 :(得分:1)

编码鲁棒且准确的数值线性代数过程可能非常棘手。 我的第一个建议是使用像Lapack

这样的成熟库

如果您要编写自己的LU,则绝对必须至少使用"partial pivoting"来建立可靠的过程,否则:

  

如果矩阵中没有适当的顺序或排列,则   因式分解可能无法实现。

注意: wikepedia建议确实可以作为一个很好的起点的实现。您只需要修改它即可支持复数而不是双精度数。

一旦解决了系统问题,就可以通过执行iterative refinement的一两个步骤来提高精度

Compute the residual: r = b − A.x
Solve the system:     A.d = r
Add the correction:   x = x + d

只需使用您的LU代码应用前面的过程即可解决A.d = r系统。如果您要追求高精度,请不要忽略最后一步,通常在实践中效果很好。