Eigen入门之密集矩阵 5 - 再谈Matrix初始化

简介

这里将讨论一下高级些的矩阵初始化方法。

comma-initializer

逗号初始化器 comma-initializer方法很简单,可以一下把矩阵/向量的系数全部设置完。语法很简单,使用逗号分隔每个系数。前面的介绍文档中已经多次使用了。只是要求在前面定义对象时,要知道矩阵/向量的维度和大小,赋值时注意数量要匹配。

而且,在初始化时,逗号分隔的对象可以时矩阵或者向量。

结合前面介绍的各种操作,综合示例:

//matrix_initial1.cpp
#include 
#include 

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 
#include 

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 
#include 

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

你可能感兴趣的:(eigen,matrix,线性代数)