Dense Matrix 8 - resharp & slicing slices for introducing Eigen

brief introduction

Eigen does not yet provide resharp or slicing handlers, but you can use Map classes to do so.

Implement resharp

Operate Resharp and modify the dimension size of Matrix while keeping its coefficients constant.When Resharp, an object should be returned, leaving the original object unchanged.

Eigen provides an example.

    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;

Execution results:

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

The example above creates a 1X9 matrix from a 3X3 matrix.Subsequent operations convert column-first 2X6 matrices to 6X2 matrices, noting the order of their coefficients in memory.

Implement Slicing

slicing roughly works like this: Install a certain interval within a matrix to get a set of rows, columns, or some elements.

The following example uses Map to simulate:

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;

View the results:

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

Some columns of the matrix can also be obtained by using an appropriate outer-strider or inner-strider, depending on the storage order.
Let's first look at the definition of 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
};

As you can see, InnerStride is the first parameter that acts on entities on a priority storage mode, such as those on rows when row priority occurs, and on column entities when column priority occurs.
OuterStride acts on rows or columns of a row matrix, such as rows in preference and columns in preference.

This is a sample program:

//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";
}

Execution results:

$ 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

In the example using Outstride, M1 is the default column priority.M2 maps M1 to get, specifies OuterStride, takes one column, and skips two columns to get a new matrix.M1 -- (Map) -->M2.

M3 is a matrix constructed by copying M1, with the same coefficients as M1.When M4 is derived from an M3 map, Stride <Dynamic, 3> (M3.outerStride(), 3), M3 --(Map) -->M4 is specified.

From the output, we know that the parameters of Outstride are the number of elements for their respective rows (row first) or columns (column first) when not specified by default.For example, the OuterStride of M1 is 3 (three elements per column), and M3 is 8 (eight column elements per row).

113 original articles were published, 108 were praised, 670,000 visits+
His message board follow

Posted by andy75180 on Sun, 23 Feb 2020 17:17:39 -0800