Eigen入門之密集矩陣 5 - 再談Matrix初始化

簡介

這裏將討論一下高級些的矩陣初始化方法。

comma-initializer

逗號初始化器 comma-initializer方法很簡單,可以一下把矩陣/向量的係數全部設置完。語法很簡單,使用逗號分隔每個係數。前面的介紹文檔中已經多次使用了。只是要求在前面定義對象時,要知道矩陣/向量的維度和大小,賦值時注意數量要匹配。

而且,在初始化時,逗號分隔的對象可以時矩陣或者向量。

結合前面介紹的各種操作,綜合示例:

//matrix_initial1.cpp
#include <Eigen/Dense>
#include <iostream>

using namespace std;
using namespace Eigen;

int main()
{
  
    RowVectorXd vec1(3);
    vec1 << 1, 2, 3;
    cout << "vec1 = " << vec1 << endl;

    RowVectorXd vec2(4);
    vec2 << 1, 4, 9, 16;
    cout << "vec2 = " << vec2 << endl;
    
    RowVectorXd joined(7);
    joined << vec1, vec2;
    cout << "joined = " << joined << endl;
  
    cout << "-----------------------" << endl;
    
    MatrixXf m(3,3);
    m << 1,2,3,
        4,5,6,
        7,8,9;
    cout << "Here is the initialed matrix m:" << endl << m << endl;
  
    //
    Matrix3f mf;
    mf.row(0) << 1, 2, 3;
    mf.block(1,0,2,2) << 4, 5, 7, 8;
    mf.col(2).tail(2) << 6, 9;                   
    cout << "Here is the other initialed matrix mf:" << endl << mf << endl;
  
}

執行:

$ g++   -I /usr/local/include/eigen3 matrix_initial1.cpp -o matrix_initial1
$ 
$ ./matrix_initial1 
vec1 = 1 2 3
vec2 =  1  4  9 16
joined =  1  2  3  1  4  9 16
-----------------------
Here is the initialed matrix m:
1 2 3
4 5 6
7 8 9
Here is the other initialed matrix mf:
1 2 3
4 5 6
7 8 9

特別的矩陣和數組

Zero

Eigen內的Matrix和Array類有一些特殊的方法,比如Zero(),可以把所有的係數初始化爲0。
zero方法有3中變體:

  • 對固定尺寸大小的對象:不需要參數,如直接Array33f a = matrix3f.Zero();
  • 對動態尺寸大小的一維對象:需要一個參數。如ArrayXf a = ArrayXf::Zero(3);
  • 對動態尺寸大小的二維對象: 需要2個參數。如ArrayXXf a = ArrayXXf::Zero(3, 4);

Constant & Random

類似於zero,靜態static方法Constant(value)將把所有的係數設置爲指定的value值。如果要指定尺寸大小,則使用MatrixXd::Constant(rows, cols, value).初始化時指定尺寸。

而Random會將對象填充隨機值。

單位矩陣Identity & LinSpaced

單位矩陣,顧名思義,只是產生矩陣的。
而 LinSpaced(size, low, high) ,只用於向量vector或者一維的Array數組。它會使用low到high之間的值,按照size,平均數值間距,得到各個係數,創建向量/數組。

其他輔助方法

Eigen定義了輔助方法,用於上述的方法的對應方法: setZero(), MatrixBase::setIdentity() and DenseBase::setLinSpaced() to do this conveniently.

示例

請參考示例。

//matrix_initial3.cpp

#include <Eigen/Dense>
#include <iostream>

using namespace std;
using namespace Eigen;

int main()
{
    // 
    ArrayXXf table(10, 4);
    table.col(0) = ArrayXf::LinSpaced(10, 0, 99);
    table.col(1) = M_PI / 180 * table.col(0);
    table.col(2) = table.col(1).sin();
    table.col(3) = table.col(1).cos();
    cout << "  Degrees   Radians      Sine    Cosine\n";
    cout << table << endl;

    //
    cout << "-------------------------------" << endl;

    // 快捷方法
    const int size = 6;
    MatrixXd mat1(size, size);
    mat1.topLeftCorner(size/2, size/2)     = MatrixXd::Zero(size/2, size/2);
    mat1.topRightCorner(size/2, size/2)    = MatrixXd::Identity(size/2, size/2);
    mat1.bottomLeftCorner(size/2, size/2)  = MatrixXd::Identity(size/2, size/2);
    mat1.bottomRightCorner(size/2, size/2) = MatrixXd::Zero(size/2, size/2);
    cout << " mat1 "<< endl;
    cout << mat1 << endl << endl;

    // 輔助方法
    MatrixXd mat2(size, size);
    mat2.topLeftCorner(size/2, size/2).setZero();
    mat2.topRightCorner(size/2, size/2).setIdentity();
    mat2.bottomLeftCorner(size/2, size/2).setIdentity();
    mat2.bottomRightCorner(size/2, size/2).setZero();
    cout << " mat2 "<< endl;
    cout << mat2 << endl << endl;

    // 
    MatrixXd mat3(size, size);
    mat3 << MatrixXd::Zero(size/2, size/2), MatrixXd::Identity(size/2, size/2),
            MatrixXd::Identity(size/2, size/2), MatrixXd::Zero(size/2, size/2);
    cout << " mat3 "<< endl;
    cout << mat3 << endl;

}


執行結果:

$ g++   -I /usr/local/include/eigen3 matrix_initial3.cpp -o matrix_initial3
$
$ ./matrix_initial3
  Degrees   Radians      Sine    Cosine
        0         0         0         1
       11  0.191986  0.190809  0.981627
       22  0.383972  0.374607  0.927184
       33  0.575959  0.544639  0.838671
       44  0.767945  0.694658   0.71934
       55  0.959931  0.819152  0.573576
       66   1.15192  0.913545  0.406737
       77    1.3439   0.97437  0.224951
       88   1.53589  0.999391 0.0348995
       99   1.72788  0.987688 -0.156434
-------------------------------
 mat1 
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0

 mat2 
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0

 mat3 
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0

臨時對象及Finish()

在上面的示例,Zero() , Constant() 可以在聲明一個便利時,初始化對象; 也可以作爲右值用來做賦值操作。看起來,好像它們會返回一個對象(矩陣或者數組)。但實際上,它們返回的是一個表達式對象(expression object),然後在需要時,纔會對該表達式進行求值。這樣對性能不會產生什麼不好的影響。在前面的示例中,也有這樣的情況。
比如代碼:

MatrixXd m = MatrixXd::Random(3,3);
m = (m + MatrixXd::Constant(3,3,1.2))*10;

代碼中的m + MatrixXd::Constant(3,3,1.2),創建了一個3X3的,係數都爲1.2的常量矩陣,這時爲express-object,在和m進行矩陣加法運算時,纔會真正求職計算。

而下面的逗號初始化器使用也是如此,其構造了一個臨時對象,是一個2X3的隨機矩陣,然後在輸出時,被求值得到結果。最重要的是mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat;,在裏面有一個反對角單位矩陣:KaTeX parse error: No such environment: smallmatrix at position 14: \bigl[ \begin{̲s̲m̲a̲l̲l̲m̲a̲t̲r̲i̲x̲}̲ 0 & 1 \\ 1 & 0…。這裏的.finish()是必須的,表示需要對表達式對象進行求值。

這是一個2X2的單位對角矩陣乘以2X3的矩陣:

//matrix_initial4.cpp
#include <Eigen/Dense>
#include <iostream>

using namespace std;
using namespace Eigen;

int main()
{
    // random matrix.
    MatrixXf mat = MatrixXf::Random(2, 3);
    std::cout <<" random matrix: " << endl << mat << std::endl << std::endl;

    //
    //mat = (MatrixXf(2,2) << 0, 1, 1, 0) * mat;      // compile error: invalid operands to binary expression
    mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat;
    std::cout << " new matrix: " << endl << mat << std::endl;
}

執行結果:

$ g++   -I /usr/local/include/eigen3 matrix_initial4.cpp -o matrix_initial4
$ 
$ ./matrix_initial4
 random matrix: 
 -0.999984   0.511211  0.0655345
 -0.736924 -0.0826997  -0.562082

 new matrix: 
 -0.736924 -0.0826997  -0.562082
 -0.999984   0.511211  0.0655345
發佈了110 篇原創文章 · 獲贊 108 · 訪問量 67萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章