Eigen入门之密集矩阵 8 - resharp & slicing切片

简介

Eigen还没有提供resharp或者slicing的处理函数,但是,可以使用Map 类来实现这些功能。

实现resharp

操作Resharp及修改Matrix的维度大小,而其系数保持不变。Resharp时,应该返回一个对象,而保留原对象不变。

Eigen提供了示例.

    MatrixXf M1(3,3);    // Column-major storage
    M1 << 1, 2, 3,
        4, 5, 6,
        7, 8, 9;
    Map<RowVectorXf> v1(M1.data(), M1.size());
    cout << "v1:" << endl << v1 << endl;

    Matrix<float,Dynamic,Dynamic,RowMajor> M2(M1);
    Map<RowVectorXf> v2(M2.data(), M2.size());
    cout << "v2:" << endl << v2 << endl;

    cout << endl;
    MatrixXf M1(2,6);    // Column-major storage
    M1 << 1, 2, 3,  4,  5,  6,
        7, 8, 9, 10, 11, 12;
    Map<MatrixXf> M2(M1.data(), 6,2);
    cout << "M2:" << endl << M2 << endl;

执行结果:

v1:
1 4 7 2 5 8 3 6 9
v2:
1 2 3 4 5 6 7 8 9

M2:
 1  4
 7 10
 2  5
 8 11
 3  6
 9 12

上面示例,从一个3X3的矩阵,创建得到了1X9的矩阵。后续的操作,将列优先的2X6矩阵转换,得到6X2的矩阵,需要注意它们在内存中的系数的顺序。

实现Slicing

切片slicing大致的操作如此: 在一个矩阵内,安装一定的间隔,取得一组的行、或者列、或部分元素。

下面示例使用Map来模拟:

For instance, one can skip every P elements in a vector:

    RowVectorXf v = RowVectorXf::LinSpaced(20,0,19);
    cout << "Input:" << endl << v << endl;
    Map<RowVectorXf,0,InnerStride<2> > v2(v.data(), v.size()/2);
    cout << "Even:" << v2 << endl;

查看结果:

Input:
 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
Even: 0  2  4  6  8 10 12 14 16 18

也可以根据存储顺序,使用合适的outer-strider、inner-strider,来获取矩阵的某些列。
这里先看一下Stride的定义:


/** \class Stride
  * \ingroup Core_Module
  *
  * \brief Holds strides information for Map
  *
  * This class holds the strides information for mapping arrays with strides with class Map.
  *
  * It holds two values: the inner stride and the outer stride.
  *
  * The inner stride is the pointer increment between two consecutive entries within a given row of a
  * row-major matrix or within a given column of a column-major matrix.
  *
  * The outer stride is the pointer increment between two consecutive rows of a row-major matrix or
  * between two consecutive columns of a column-major matrix.
  *
  * These two values can be passed either at compile-time as template parameters, or at runtime as
  * arguments to the constructor.
  *
  * Indeed, this class takes two template parameters:
  *  \tparam _OuterStrideAtCompileTime the outer stride, or Dynamic if you want to specify it at runtime.
  *  \tparam _InnerStrideAtCompileTime the inner stride, or Dynamic if you want to specify it at runtime.
  *
  * 
  */

 ... ... 

/** \brief Convenience specialization of Stride to specify only an inner stride
  * See class Map for some examples */
template<int Value>
class InnerStride : public Stride<0, Value>
{
    typedef Stride<0, Value> Base;
  public:
    EIGEN_DEVICE_FUNC InnerStride() : Base() {}
    EIGEN_DEVICE_FUNC InnerStride(Index v) : Base(0, v) {} // FIXME making this explicit could break valid code
};

/** \brief Convenience specialization of Stride to specify only an outer stride
  * See class Map for some examples */
template<int Value>
class OuterStride : public Stride<Value, 0>
{
    typedef Stride<Value, 0> Base;
  public:
    EIGEN_DEVICE_FUNC OuterStride() : Base() {}
    EIGEN_DEVICE_FUNC OuterStride(Index v) : Base(v,0) {} // FIXME making this explicit could break valid code
};

可以看到,InnerStride是第一个参数,作用于某种优先存储模式的优先级上的实体,比如行优先时,作用于行上的实体;列优先时,作用于列实体。
而OuterStride作用于行矩阵的行或者列,如行优先时作用于行,而列优先时,作用于列。

这是示例程序:

//matrix_sliding.cpp
#include 
#include 

using namespace std;
using namespace Eigen;


int main()
{
    MatrixXf M1 = MatrixXf::Random(3,8);
    cout << "Column major input:" << endl << M1 << "\n";

    cout << "M1's outerStride: " << M1.outerStride() << "    -- M1.cols(): " << M1.cols() << endl;

    Map<MatrixXf,0,OuterStride<> > M2(M1.data(), /*3*/ M1.rows(), /*3*/ (M1.cols()+2)/3, OuterStride<>(M1.outerStride()*3));
    cout << "1 column over 3:" << endl << M2 << "\n";
    
    typedef Matrix<float,Dynamic,Dynamic,RowMajor> RowMajorMatrixXf;
    RowMajorMatrixXf M3(M1);
    cout << "Row major input:" << endl << M3 << "\n";
    cout << "M3.outerStride(): " << M3.outerStride() << endl;
    Map<RowMajorMatrixXf,0,Stride<Dynamic,3> > M4(M3.data(), M3.rows(), (M3.cols()+2)/3,
                                                Stride<Dynamic,3>(M3.outerStride(),3));
    cout << "1 column over 3:" << endl << M4 << "\n";
}

执行结果:

$ g++   -I /usr/local/include/eigen3 matrix_sliding.cpp -o matrix_sliding
$ 
$ ./matrix_sliding 
Column major input:
 -0.999984 -0.0826997  -0.905911   0.869386   0.661931  0.0594004  -0.233169   0.373545
 -0.736924  0.0655345   0.357729  -0.232996  -0.930856   0.342299  -0.866316   0.177953
  0.511211  -0.562082   0.358593  0.0388328  -0.893077  -0.984604  -0.165028   0.860873
M1's outerStride: 3    -- M1.cols(): 8
1 column over 3:
-0.999984  0.869386 -0.233169
-0.736924 -0.232996 -0.866316
 0.511211 0.0388328 -0.165028
Row major input:
 -0.999984 -0.0826997  -0.905911   0.869386   0.661931  0.0594004  -0.233169   0.373545
 -0.736924  0.0655345   0.357729  -0.232996  -0.930856   0.342299  -0.866316   0.177953
  0.511211  -0.562082   0.358593  0.0388328  -0.893077  -0.984604  -0.165028   0.860873
M3.outerStride(): 8
1 column over 3:
-0.999984  0.869386 -0.233169
-0.736924 -0.232996 -0.866316
 0.511211 0.0388328 -0.165028

示例里使用Outstride,M1是缺省的列优先。M2映射M1得到,指定了OuterStride,取1个列,然后跳过2个列,得到新的矩阵。M1 --(Map)-->M2

M3是指定了行优先,拷贝M1构建的矩阵,系数与M1相同。从M3 映射得到M4时,指定了Stride(M3.outerStride(),3)M3 --(Map)-->M4

从输出中,我们可以知道,在缺省未指定的情况下,Outstride的参数为其对应的行(行优先)或者列(列优先)的元素数量。如M1的OuterStride为3(每列3个元素),M3位8(每行8个列元素)。

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