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 <iostream>
#include <Eigen/Dense>

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<Dynamic,3>(M3.outerStride(),3)M3 --(Map)-->M4

從輸出中,我們可以知道,在缺省未指定的情況下,Outstride的參數爲其對應的行(行優先)或者列(列優先)的元素數量。如M1的OuterStride爲3(每列3個元素),M3位8(每行8個列元素)。

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