Reputation:
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
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
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
44.94066e-324 3
4.94066e-324 41 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 b
s 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