user674155
user674155

Reputation:

Making a reshape function in Eigen

Here's the code for a reshape function in Eigen. It works.

typedef MatrixXd mat;
typedef VectorXd vec;

Map<mat> reshape (vec b, const uint n, const uint m) {
    return Map<mat>(b.data(), n, m);
}

I was trying to decide the right type for the first argument.

vec & b still works, but I get strange errors with const vec & b or const vec b:

error: invalid conversion from 'const Scalar* {aka const double*}' to 'Eigen::Map<Eigen::Matrix<double, -1, -1> >::PointerArgType {aka double*}' [-fpermissive]
     return Map<mat>(b.data(), n, m);
                 ~~~~~~^~

I suspect this is due to mutability and the fact that the reshape function doesn't allocate new memory, but I would like to learn a more detailed explanation.

Hmm, it seems that vec && b is the right type for this, but I'm out of my depth.

Upvotes: 2

Views: 2762

Answers (2)

kangshiyin
kangshiyin

Reputation: 9771

You are right that it is a mutability issue. If you use const vec&, you can only map it to a const mat as

Map<const mat> reshape (const vec& b, const uint n, const uint m) {
    return Map<const mat>(b.data(), n, m);
}

otherwise you can modify the components of a const vec via the mapped matrix. It has nothing to do with allocating memory.

Actually both vec and const vec are wrong. Both of them mean mapping to a temp copy of the original vector, whose life ends after the function call, as Avi Ginsburg said, resulting in an undefined behavior.

Please note the above code is only correct when the input is an Eigen::VectorXd.

In fact both vec& and const vec& can be wrong, if your input b is an expression. Using vec& will fail compiling as the components of an expression are not mutable. Using const vec& will force the expression to be evaluated into a temp const vector during the function call and you are mapping to a temp vector again.

Map<mat> reshape (vec& b, const uint n, const uint m) {
    return Map<const mat>(b.data(), n, m);
}

Map<const mat> reshape_const (const vec& b, const uint n, const uint m) {
    return Map<const mat>(b.data(), n, m);
}

vec a(100), b(100);
Map<mat> c1 = reshap(a, 10, 10);                  // ok
Map<mat> c2 = reshap(a + b, 10, 10);              // error, expression not mutable
Map<const mat> c3 = reshap_const(a, 10, 10);      // ok
Map<const mat> c4 = reshap_const(a + b, 10, 10);  // error, mapping to temp vec

In this case you need to use the expression type as the parameter type, although you probably do not plan to use your reshape with expressions. You could find more details here.

http://eigen.tuxfamily.org/dox-devel/TopicFunctionTakingEigenTypes.html

Upvotes: 3

Avi Ginsburg
Avi Ginsburg

Reputation: 10596

It's just a matter of scope. Let's create a MCVE and use that to explain:

#include <Eigen/Core>
#include <iostream>

using namespace Eigen;

typedef MatrixXd mat;
typedef VectorXd vec;

Map<mat> reshapeCopy (vec b, const size_t n, const size_t m) {
    return Map<mat>(b.data(), n, m);
}

Map<mat> reshape (vec &b, const size_t n, const size_t m) {
    return Map<mat>(b.data(), n, m);
}

int main()
{
    vec tr;
    tr.setLinSpaced(4,1,4);
    std::cout << tr << "\n\n";
    Map<mat> m = reshape(tr, 2,2);
    std::cout << m << "\n\n";
    return 0;
}

Using g++ 4.9.3 on Ubuntu outputs:

1
2
3
4

4.94066e-324 3
4.94066e-324 4

1 3
2 4

In reshapeCopy,b is a copy of tr. Its lifetime is until the end of the reshapeCopy function. Therefore, when used in main, the output is gibberish/undefined behavior. In the reshape function tr is passed by reference and therefore the bs lifetime is as long as tr and the output is as expected.

kangshiyin is correct in pointing out that the specific error you're getting is when you define the function with const vec b or const vec &b that b is const, i.e. not mutable, and the return type is a mutable Map<mat>.

Upvotes: 2

Related Questions