This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Functions accpts Eigen::Matrix but not Eigen::Map< Matrix >

Tags: None
(comma "," separated)
Webertob
Registered Member
Posts
2
Karma
0
OS
Hello,
I'm using Eigen for programming a lib interacting with a properitery FEM-programm. Therefore all values i/o to the lib is provided by pointers to plain array's. Of course I'm using Eigen::Map< Eigen::Matrix< ... > > to wrapp the plain data to more convienent objects. The lib itself and all its internal functions relies on Eigen::Matrix types.

But now I'm faced with the following problem:

Functions expecting Eigen::Matrix as arguments do not accept Eigen::Map< Eigen::Matrix< ... > >. If I try to do that, the compiler complains about incompatible types. Even is the object mapped TO is of the same type.

I would expect that a function taking a Matrix<double,6,6> would also take Map< Matrix< double, 6,6 > >
Please see code below:

Code: Select all
#include <iostream>
#include <Eigen>
using namespace std;
typedef Eigen::Matrix<double, 6, 6> Matrix6x6;

void createStiffness(Matrix6x6 &stiffness)
{
     stiffness << 11, 12, 13, 14, 15, 16,
                  12, 22, 23, 24, 25, 26,
                  13, 23, 33, 34, 35, 36,
                  14, 24, 34, 44, 45, 46,
                  15, 25, 35, 45, 55, 56,
                  16, 26, 36, 46, 56, 66;
}

int main()
{
    double plainArray[36];
    for(int i=0; i<6; i++) {
        for(int j=0; j<6; j++) {
            plainArray[i+j*6] = 0.0;
        }
    }

    Eigen::Map< Matrix6x6 > mappedArray(plainArray);
    cout << "MappedArray before:" << endl;
    cout << mappedArray << endl;


    createStiffness(mappedArray);
    cout << "MappedArray after:" << endl;
    cout << mappedArray << endl;

    Matrix6x6 stiff;
    createStiffness(stiff);
    cout << "Stiffness:" << endl;
    cout << stiff << endl;
    return 0;
}


Compiler says:
Code: Select all
../EigenMappingExample/main.cpp: In function 'int main()':
../EigenMappingExample/main.cpp:33: error: invalid initialization of reference of type 'Matrix6x6&' from expression of type 'Eigen::Map<Eigen::Matrix<double, 6, 6, 0, 6, 6>, 0, Eigen::Stride<0, 0> >'
../EigenMappingExample/main.cpp:9: error: in passing argument 1 of 'void createStiffness(Matrix6x6&)'


Reading around in the Eigen Docs I found, that the compiler prevents functions to take references on temporary objects. Thus I modifiyed the source following the "const" hack. The code compails with this, but provides wrong output, please see below:

Code: Select all
#include <iostream>
#include <Eigen>
using namespace std;
typedef Eigen::Matrix<double, 6, 6> Matrix6x6;

void createStiffness(const Matrix6x6 &stiffness)
{
     const_cast< Matrix6x6&> (stiffness)
            << 11, 12, 13, 14, 15, 16,
               12, 22, 23, 24, 25, 26,
               13, 23, 33, 34, 35, 36,
               14, 24, 34, 44, 45, 46,
               15, 25, 35, 45, 55, 56,
               16, 26, 36, 46, 56, 66;
}

int main()
{
    double plainArray[36];
    for(int i=0; i<6; i++) {
        for(int j=0; j<6; j++) {
            plainArray[i+j*6] = 0.0;
        }
    }

    Eigen::Map< Matrix6x6 > mappedArray(plainArray);
    cout << "MappedArray before:" << endl;
    cout << mappedArray << endl;

    createStiffness(mappedArray);
    cout << "MappedArray after:" << endl;
    cout << mappedArray << endl;

    Matrix6x6 stiff;
    createStiffness(stiff);
    cout << "Stiffness:" << endl;
    cout << stiff << endl;
    return 0;
}


Output:
Code: Select all
MappedArray before:
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
MappedArray after:
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Stiffness:
11 12 13 14 15 16
12 22 23 24 25 26
13 23 33 34 35 36
14 24 34 44 45 46
15 25 35 45 55 56
16 26 36 46 56 66


Please can you provide any help on how to enable functions to take references to Eigen::Matrix and their compatible Eigen::Map< Eigen::Matrix< ... > types. I've experimented with templated functions and derived argument types, but this leads to completly open function interface with out any control about the arguments passed in. Thus I lose all the benefit a type validating language offers. Thus I would at least want to ensure that correct type (float/double) and dimensions are passed in.

Thank you for support!
Webertob
Registered Member
Posts
2
Karma
0
OS
Hello,
after searching the forum again I thing the following solution is the best, see below. I have to template the function and must make sure that each argument is able to get it own derived type to enable the mixture of Eigen::Map and Eigen::Matrix arguments to be passed in from the caller.

To make the function header as tight as possible I can use MatrixBase to define that a Matrix must be passed in Dimensions have to be checked after wards in the function body by STATIC_ASSERTS.

Thank you for the greate library and that everything need was already in place.

May be it would be helpful do extend the tutorial page 10 about this example.

Code: Select all
#include <iostream>
#include <Eigen>
using namespace std;
typedef Eigen::Matrix<double, 6, 6> Matrix6x6;

template<typename M1, typename M2>
void createStiffness( Eigen::MatrixBase<M1> &stiffness, const Eigen::MatrixBase<M2> &damages)
{
     EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(M1, 6, 6);
     EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(M2, 6, 6);

     stiffness << 11, 12, 13, 14, 15, 16,
                  12, 22, 23, 24, 25, 26,
                  13, 23, 33, 34, 35, 36,
                  14, 24, 34, 44, 45, 46,
                  15, 25, 35, 45, 55, 56,
                  16, 26, 36, 46, 56, 66;

     stiffness.array()*=damages.array();
}

int main()
{
    double plainArray[36];
    for(int i=0; i<6; i++) {
        for(int j=0; j<6; j++) {
            plainArray[i+j*6] = 0.0;
        }
    }

    Matrix6x6 damage = Matrix6x6::Random();

    Eigen::Map< Matrix6x6 > mappedArray(plainArray);
    cout << "MappedArray before:" << endl;
    cout << mappedArray << endl;

    createStiffness(mappedArray, damage);
    cout << "MappedArray after:" << endl;
    cout << mappedArray << endl;

    Matrix6x6 stiff;
    createStiffness(stiff, damage);
    cout << "Stiffness:" << endl;
    cout << stiff << endl;
    return 0;
}
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
EDIT: oops I did not see you found the solution by yourself, great.

Well you can still control the input types of template functions using static assertion and/or enable_if constructs.

Now if you really don't want to have template public code you can still have a simple public template function calling an internal version that take a Map<> object as argument. The template public function will simply convert the user input into a Map<>, eg.:

template <typename Derived> void createStiffness(MatrixBase<Derived> &stiffness)
{
Map<Matrix6x6> tmp(stiffness.data(), stiffness.rows(), stiffness.cols());
createStiffness_impl(tmp);
}

void createStiffness_impl(Map<Matrix6x6>& stiffness) { ... }

You can also generalize this to Map<> objects with a stride such that you can also accept block expressions as input.

For the next version we plan to allow to automatically construct Map<> objects from compatible objects such that the above template wrapper won't be needed anymore.

Note that storage order will still have to match.


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Yahoo [Bot]