從Eigen 3.3開始,LU,Cholesky和QR分解can operate inplace,即直接在給定的輸入矩陣內進行。
當處理大型矩陣或可用內存非常有限(嵌入式系統)時,此功能特別有用。
爲此,必須instantiated with a Ref<> matrix type,同時使用輸入矩陣作爲參數來構造分解對象。
作爲示例,讓我們考慮an inplace LU decomposition with partial pivoting.
Let's start with the basic inclusions, and declaration of a 2x2 matrix A:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
No surprise here! Then, 聲明我們的 inplace LU 對象 lu
, and check the content of the matrix A:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here, the lu對象計算和保存
the L
and U
因子 within the memory held by the matrix A
. 矩陣 A中的元素
被破壞了during the factorization, and replaced by the L and U factors as one can verify:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
然後,可以像往常一樣使用lu對象,例如解決Ax = b問題:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl;
MatrixXd A0(2,2); A0 << 2, -1, 1, 3;
VectorXd b(2); b << 1, 2;
VectorXd x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
Residual: 0
在這裏,由於原始矩陣A的內容已丟失,因此我們必須聲明一個新矩陣A0
以驗證結果。
由於在A
和lu之間共享內存
,因此修改矩陣A
將lu
無效。
This can easily be verified by modifying the content of A
and trying to solve the initial problem again:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl;
MatrixXd A0(2,2); A0 << 2, -1, 1, 3;
VectorXd b(2); b << 1, 2;
VectorXd x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A << 3, 4, -2, 1;
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
Residual: 0
Residual: 15.8114
注意:沒有共享的指針, it is the responsibility of the user to keep the input matrix A
in life as long as lu
is living.
如果要使用修改後的A更新因式分解,則必須像往常一樣調用compute方法:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl;
MatrixXd A0(2,2); A0 << 2, -1, 1, 3;
VectorXd b(2); b << 1, 2;
VectorXd x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A << 3, 4, -2, 1;
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A0 = A; // save A
lu.compute(A);
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
Residual: 0
Residual: 15.8114
Residual: 0
請注意,調用compute不會更改lu
對象引用的內存。因此,如果使用不同於A的另一個矩陣A1調用計算方法,then the content of A1
won't be modified. This is still the content of A
that will be used to store the L and U factors of the matrix A1
. This can easily be verified as follows:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl;
MatrixXd A0(2,2); A0 << 2, -1, 1, 3;
VectorXd b(2); b << 1, 2;
VectorXd x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A << 3, 4, -2, 1;
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A0 = A; // save A
lu.compute(A);
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
MatrixXd A1(2,2);
A1 << 5,-2,3,4;
lu.compute(A1);
cout << "Here is the input matrix A1 after decomposition:\n" << A1 << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
Residual: 0
Residual: 15.8114
Residual: 0
Here is the input matrix A1 after decomposition:
5 -2
3 4
矩陣A1
不變,因此可以求解A1 * x = b,and one can thus solve A1*x=b, and directly check the residual without any copy of A1:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
Residual: 0
Residual: 15.8114
Residual: 0
Here is the input matrix A1 after decomposition:
5 -2
3 4
輸出:
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd A(2,2);
A << 2, -1, 1, 3;
cout << "Here is the input matrix A before decomposition:\n" << A << endl;
PartialPivLU<Ref<MatrixXd> > lu(A);
cout << "Here is the input matrix A after decomposition:\n" << A << endl;
cout << "Here is the matrix storing the L and U factors:\n" << lu.matrixLU() << endl;
MatrixXd A0(2,2); A0 << 2, -1, 1, 3;
VectorXd b(2); b << 1, 2;
VectorXd x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A << 3, 4, -2, 1;
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
A0 = A; // save A
lu.compute(A);
x = lu.solve(b);
cout << "Residual: " << (A0 * x - b).norm() << endl;
MatrixXd A1(2,2);
A1 << 5,-2,3,4;
lu.compute(A1);
cout << "Here is the input matrix A1 after decomposition:\n" << A1 << endl;
x = lu.solve(b);
cout << "Residual: " << (A1 * x - b).norm() << endl;
}
輸出:
Here is the input matrix A before decomposition:
2 -1
1 3
Here is the input matrix A after decomposition:
2 -1
0.5 3.5
Here is the matrix storing the L and U factors:
2 -1
0.5 3.5
Residual: 0
Residual: 15.8114
Residual: 0
Here is the input matrix A1 after decomposition:
5 -2
3 4
Residual: 2.48253e-16
Here is the list of matrix decompositions supporting this inplace mechanism:
- class LLT
- class LDLT
- class PartialPivLU
- class FullPivLU
- class HouseholderQR
- class ColPivHouseholderQR
- class FullPivHouseholderQR
- class CompleteOrthogonalDecomposition