我目前正在尝试开发一个面向矩阵的小型数学库(我正在使用Eigen 3进行矩阵数据结构和操作)并且我想实现一些方便的Matlab函数,例如广泛使用的反斜杠运算符(相当于mldivide),以便计算线性系统的解(以矩阵形式表示)。
有关如何实现这一目标的详细解释吗? (我已经使用经典的SVD分解实现了Moore-Penrose伪逆pinv函数,但我读过A\b
并不总是pinv(A)*b
的某处,至少Matalb没有'只是这样做)
由于
答案 0 :(得分:35)
对于x = A\b
,backslash运算符包含许多algorithms来处理不同类型的输入矩阵。因此诊断矩阵A
并根据其特征选择执行路径。
当A
是一个完整矩阵时,以下page描述了伪代码:
if size(A,1) == size(A,2) % A is square
if isequal(A,tril(A)) % A is lower triangular
x = A \ b; % This is a simple forward substitution on b
elseif isequal(A,triu(A)) % A is upper triangular
x = A \ b; % This is a simple backward substitution on b
else
if isequal(A,A') % A is symmetric
[R,p] = chol(A);
if (p == 0) % A is symmetric positive definite
x = R \ (R' \ b); % a forward and a backward substitution
return
end
end
[L,U,P] = lu(A); % general, square A
x = U \ (L \ (P*b)); % a forward and a backward substitution
end
else % A is rectangular
[Q,R] = qr(A);
x = R \ (Q' * b);
end
对于非方形矩阵,使用QR decomposition。对于方形三角矩阵,它执行简单的forward/backward substitution。对于方形对称正定矩阵,使用Cholesky decomposition。否则LU decomposition用于一般方阵。
更新: MathWorks已使用一些不错的流程图更新了
mldivide
文档页面中的algorithm section。请参阅here和here(完整和稀疏案例)。
所有这些算法在LAPACK中都有相应的方法,实际上它可能是MATLAB正在做的事情(注意最近版本的MATLAB附带优化的Intel MKL实现)。
使用不同方法的原因在于它试图使用最具体的算法来求解利用系数矩阵的所有特征的方程组(因为它将更快或更数值稳定)。所以你当然可以使用一般解算器,但它不是最有效的。
事实上,如果你事先知道A
是什么样的,你可以通过调用linsolve
并直接指定选项来跳过额外的测试过程。
如果A
是矩形或单数,您还可以使用PINV查找最小范数最小二乘解(使用SVD decomposition实现):
x = pinv(A)*b
以上所有适用于密集矩阵,稀疏矩阵是完全不同的故事。通常iterative solvers用于此类情况。我相信MATLAB使用UMFPACK和SuiteSpase包中的其他相关库来进行直接求解。
使用稀疏矩阵时,您可以打开诊断信息,查看执行的测试和使用spparms
选择的算法:
spparms('spumoni',2)
x = A\b;
此外,反斜杠运算符也适用于gpuArray,在这种情况下,它依赖于cuBLAS和MAGMA在GPU上执行。
它也是在distributed arrays实现的,它在分布式计算环境中工作(工作分散在一组计算机中,每个工作者只有一部分数组,可能整个矩阵无法存储在内存中一旦)。底层实现使用ScaLAPACK。
如果你想自己实现所有这些,这是一个非常高的命令:)