Eigen學習筆記23:Inplace matrix 分解

從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之間共享內存,因此修改矩陣Alu無效。

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:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章