1、子矩阵操作简介

子矩阵操作又称块操作,在矩阵运算中,子矩阵的提取和操作应用也十分广泛。因此Eigen中也提供了相关操作的方法。提取的子矩阵在操作过程中既可以用作左值也可以用作

block of size (p,q) ,starting at (i,j)。

matrix.block(i,j,p,q);
matrix.block<p,q>(i,j);

2、块操作的一般使用方法

在Eigen中最基本的快操作运算是用.block()完成的。提取的子矩阵同样分为动态大小和固定大小。

块操作                        构建动态大小子矩阵
提取块大小为(p,q),起始于(i,j)    matrix.block(i,j,p,q)

同样需要注意的是在Eigen中,索引是从0开始。所有的操作方法都可以适用于Array.同样使用固定大小的操作方式在小型矩阵运算时更加的快,但要求在编译时就要知道矩阵的大小。
下面是一个使用示例:

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

using namespace std;
using namespace Eigen;

int main()
{
    MatrixXf m(4,4);
    m<< 1,2,3,4,
        5,6,7,8,
        9,10,11,12,
        13,14,15,16;
    cout<<"Block in the middle"<<endl;
    cout<<m.block<2,2>(1,1)<<endl<<endl;
    for(int i = 1;i <= 3;++i)
    {
        cout<<"Block of size "<<i<<"x"<<i<<endl;
        cout<<m.block(0,0,i,i)<<endl<<endl;
    }
}

执行结果如下:

Block in the middle
 6  7
10 11

Block of size 1x1
1

Block of size 2x2
1 2
5 6

Block of size 3x3
 1  2  3
 5  6  7
 9 10 11

上面的示例中,.block() 被应用为左值操作,即从中读取数据。事实上,它也可以被用作为右值操作,即也可往里面写入数据。下面是一个右值应用实例。

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

using namespace std;
using namespace Eigen;

int main()
{
    Array22f m;
    m<< 1,2,
        3,4;
    Array44f a = Array44f::Constant(0.6);
    cout<<"Here is the array a:"<<endl<<a<<endl<<endl;
    a.block<2,2>(1,1) = m;
    cout<<"Here is now a with m copied into its central 2x2 block:"<<endl<<a<<endl<<endl;
    a.block(0,0,2,3) = a.block(2,1,2,3);
    cout<<"Here is now a with bottom-right 2x3 block copied into top-left 2x2 block:"<<endl<<a<<endl<<endl;
}

执行结果如下:

Here is the array a:
0.6 0.6 0.6 0.6
0.6 0.6 0.6 0.6
0.6 0.6 0.6 0.6
0.6 0.6 0.6 0.6

Here is now a with m copied into its central 2x2 block:
0.6 0.6 0.6 0.6
0.6   1   2 0.6
0.6   3   4 0.6
0.6 0.6 0.6 0.6

Here is now a with bottom-right 2x3 block copied into top-left 2x2 block:
  3   4 0.6 0.6
0.6 0.6 0.6 0.6
0.6   3   4 0.6
0.6 0.6 0.6 0.6

.block()方法是一种非常通用的块操作方法。除了这个通用的方法以外,Eigen中还为一些常用的特殊操作提供了特殊的函数。从运行速度的方面来看,你应该在编译阶段尽可能的提供更多的信息。比如,如果你需要操作的块是一个列,那么你可以使用.col()函数。这样Eigen可以得知这个信息以便进行更多的优化。
这些特殊操作方法总结如下。

3.行子式和列子式

我们可以使用.col()和.row()方法来操作或者提取一个列或者行。

下面是一个使用示例:

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

using namespace std;
using namespace Eigen;

int main()
{
    MatrixXf m(3,3);
    m<< 1,2,3,
        4,5,6,
        7,8,9;
    cout<<"Here is the matrix m:"<<endl<<m<<endl;
    cout<<"2nd Row:"<<m.row(1)<<endl;
    m.col(2) += 3*m.col(0);
    cout<<"After adding 3 times the first column into third column,the matrix m is:\n";
    cout<<m<<endl;
}

执行结果如下:

Here is the matrix m:
1 2 3
4 5 6
7 8 9
2nd Row:4 5 6
After adding 3 times the first column into third column,the matrix m is:
 1  2  6
 4  5 18
 7  8 30

4、边角子矩阵

Eigen提供了从边角开始提取子矩阵的方法,比如.topLeftCorner()表示从左上角开始提取子矩阵。这些操作总结如下:

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

using namespace std;
using namespace Eigen;

int main()
{
    Matrix4f m;
    m<< 1,2,3,4,
        5,6,7,8,
        9,10,11,12,
        13,14,15,16;
    cout<<"m.leftCols(2)="<<endl<<m.leftCols(2)<<endl<<endl;
    cout<<"m.bottomRows<2>()="<<endl<<m.bottomRows<2>()<<endl<<endl;
    m.topLeftCorner(1,3) = m.bottomRightCorner(3,1).transpose();
    cout<<"After assignment,m="<<endl<<m<<endl;
}

执行结果如下:

m.leftCols(2)=
 1  2
 5  6
 9 10
13 14

m.bottomRows<2>()=
 9 10 11 12
13 14 15 16

After assignment,m=
 8 12 16  4
 5  6  7  8
 9 10 11 12
13 14 15 16

5、向量的子向量操作

Eigen中同样也为向量提供了一些子式的操作方法,总结如下:

再次说明一下,所有对矩阵的操作同样适用于Array,所有对列向量的操作同样适用于行向量。
下面是一个使用示例:

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

using namespace std;
using namespace Eigen;

int main()
{
    ArrayXf v(6);
    v<<1,2,3,4,5,6;
    cout<<"v.head(3)="<<endl<<v.head(3)<<endl<<endl;
    cout<<"v.tail<3>()="<<endl<<v.tail<3>()<<endl<<endl;
    v.segment(1,4) *= 2;
    cout<<"after 'v.segment(1,4) *= 2',v="<<endl<<v<<endl;
}

执行结果如下:

v.head(3)=
1
2
3

v.tail<3>()=
4
5
6

after 'v.segment(1,4) *= 2',v=
 1
 4
 6
 8
10
 6