I'm tearing my hair out trying to access a column of data in an Eigen::Tensor<double, 3> as a Eigen::VectorXd.
Slicing, as according to this answer, works fine to get me the column I want. But I can't then assign that to a vector.
What I have:
Eigen::Tensor<double, 3> my_tens(2, 3, 4);
my_tens.setRandom();
Eigen::array<Eigen::Index, 3> dims = my_tens.dimensions();
Eigen::array<Eigen::Index, 3> offsets = {0, 1, 0};
Eigen::array<Eigen::Index, 3> extents = {dims[0], 1, 1};
// This works perfectly, and is exactly the column I want:
std::cout << my_tens.slice(offsets, extents);
// ... and I want it as a VectorXd, so:
Eigen::VectorXd my_vec(dims[0]);
The following things I've tried all FAIL:
// Direct assignment (won't compile, no viable overloaded '=')
my_vec = my_tens.slice(offsets, extents);
// Initialisation (won't compile, no viable overloaded '<<')
my_vec << my_tens.slice(offsets, extents);
// Same problem with reshaping:
g_a = signature_a.g.slice(offsets, extents).reshape(Eigen::array<Eigen::Index, 2>{dims[0], 1});
// Converting the base (won't compile, no member 'matrix')
my_vec << my_tens.slice(offsets, extents).matrix();
I also tried mapping as in this answer, but that doesn't work either (EDIT: I thought this was due to the to the storage ordering but actually is due to incorrect offset, see my answer):
// This produces a part of a row of the tensor, not a column. Gah!
auto page_offset = offsets[2] * dims[0] * dims[1];
auto col_offset = offsets[1] * dims[0];
auto bytes_offset = sizeof(double) * (page_offset + col_offset)
Eigen::Map<Eigen::VectorXd> my_mapped_vec(my_tens.data() + bytes_offset, dims[0]);
Should it really be this hard, or am I missing something simple? Thanks for any and all help!
Answered my own question: Yes, I was missing something simple. By comparing what numbers I got out of the Map operation I realised the offsets were a factor of 8 out; i.e. out by sizeof(double).
I hadn't realised that operation my_tens.data() + bytes_offset takes my_tens.data(), a const double *, and rather than adding a fixed number of bytes to offset the pointer, offsets it by that number of elements.
Here's the correct code:
Eigen::Tensor<double, 3> my_tens(2, 3, 4);
my_tens.setRandom();
Eigen::array<Eigen::Index, 3> dims = my_tens.dimensions();
Eigen::array<Eigen::Index, 3> offsets = {0, 1, 0};
Eigen::array<Eigen::Index, 3> extents = {dims[0], 1, 1};
// Compute the offset, correctly this time!
auto page_offset = offsets[2] * dims[0] * dims[1];
auto col_offset = offsets[1] * dims[0];
auto elements_offset = page_offset + col_offset;
// Map into the array
Eigen::Map<Eigen::VectorXd> my_mapped_vec(my_tens.data() + elements_offset, dims[0]);
// Compare the two:
std::cout << my_tens.slice(offsets, extents) << std::endl;
std::cout << my_mapped_vec.transpose() << std::endl;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With