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

Read-Only Array View of Multiple Vectors

Tags: None
(comma "," separated)
mattd
Registered Member
Posts
28
Karma
0
Hi!

I'm trying to create an Eigen object with array semantics (need it only for a storage passed by const ref to a code that expects an Eigen::ArrayXXd) that is a view of the contents of multiple vectors.

Basically, in the attached code I'd like for Eigen::ArrayXXd X to refer to the contents of a bunch of vectors (here -- three of them with Eigen::VectorXd type, but in real app. a bit more (and a bit larger, but still all of the same length)).

Because of the large size of the data, I'd like to avoid allocating any additional memory for X (i.e., I only want it to be a view, not a copy), to avoid allocation and copying overhead.

The intention is in the comment -- but only to some extent (including that the code right now won't compile, since data mem.-fun. only returns an r-value) since I'd like to avoid X assuming the ownership of the memory of vectors a, b, c.

After I pass it to a code (that won't modify it, but will read only), I'm happy to discard X.

// Well, as a last-resort scenario I'd be also fine with discarding a, b, c -- so even _move_ would be preferable to _copy_ for me.

I understand that the way I've written it now (the uncommented part) I'm performing a _copy_ of the contents of a, b, c into consecutive columns of X, and I presume there's no copy-on-write optimization for this?

Any ideas on how to create a read-only view instead?

In the docs I was only able to find information on TriangularView /* http://eigen.tuxfamily.org/dox/QuickRefPage.html */ (which isn't what I want at all) and Eigen::Map /* http://eigen.tuxfamily.org/dox/classEigen_1_1Map.html */ (which seems to be able to take only one pointer to one object containing one piece of data -- while I need multiple ones).

Code: Select all
#include <iostream>
#include <Eigen/Dense>

int main()
{
   Eigen::VectorXd a(2), b(2), c(2);
   a << 1, 2;
   b << 11, 22;
   c << 100, 200;
   std::cout << "Vector a:\n" << a << std::endl;
   std::cout << "Vector b:\n" << b << std::endl;
   std::cout << "Vector c:\n" << c << std::endl;
   
   Eigen::ArrayXXd X(2, 3);
   X.col(0) << a;
   X.col(1) << b;
   X.col(2) << c;
   std::cout << "Array X:\n" << X << std::endl;

   /*
   X.col(0).data() = a.data();
   X.col(1).data() = b.data();
   X.col(2).data() = c.data();
   std::cout << "Array X:\n" << X << std::endl;
   */
}


Intended output:
Vector a:
1
2
Vector b:
11
22
Vector c:
100
200
Array X:
1 11 100
2 22 200
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
to do so you would have to write your own expression that would basically store a std::vector<Map<...> >, and your function should be templatized to accept any kind of array objects.
mattd
Registered Member
Posts
28
Karma
0
Ah, that's an interesting solution, thanks.
A question -- does Eigen::Map have value-semantics or reference-semantics?
And if value, is it lightweight or fat?
Basically, I'm wondering if I shouldn't still use std::vector<Eigen::Map<...>*> instead of std::vector<Eigen::Map<...>> if I want to avoid all the overheads that I can?
Or, perhaps, boost::ptr_vector<Eigen::Map<...>>; incidentally, is it safe to use Eigen::Map with Boost.Pointer Containers, http://www.boost.org/doc/libs/release/l ... ainer.html?

Completely alternatively, would either std::vector<Eigen::VectorXd*> or boost::ptr_vector<Eigen::VectorXd> be a better idea for this application than the Eigen::Map approach -- and if so, which one and why?
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
A Map<VectorXd> object only stores a pointer plus an integer (size), so it is very lightweight though the size information will be duplicated many times. Also note that Map<>::operator= copies the values, not the pointers, just like any Eigen's object, so a std::vector<Map<>> could work but some care has to be taken. For instance, one could implement a setInnerVector(i, vec) method with overloads for VectorXd and MapBase objects. The Map elements stored in the std::vector<Map<>> would be initialized with the placement new mechanism:
new (&m_innerVectors[i]) Map<...>(data,size);
hope that helps.
mattd
Registered Member
Posts
28
Karma
0
ggael, thanks for the reply, I'm still not sure how to insert eigen-maps into std-vectors.

For
Code: Select all
Eigen::VectorXd v0;
std::vector<Eigen::Map<Eigen::VectorXd>> X;

neither
Code: Select all
Eigen::Map<Eigen::VectorXd> mv0(v0.data());
X.push_back(mv0);

nor
Code: Select all
X.push_back(Eigen::Map<Eigen::VectorXd>(v0.data()));

work.

Both error out with:
/Core/MapBase.h(142) : error C2338: YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR; /Core/MapBase.h(140) : while compiling class template member function 'Eigen::MapBase<Derived,Level>::MapBase(double *) with [Derived=Eigen::
Map<Eigen::Matrix<double,-1,1>,0>,Level=0]'; /Core/MapBase.h(184) : see re
ference to class template instantiation 'Eigen::MapBase<Derived,Level> with [Derived=Eigen::Map<Eigen::Matrix<double,-1,1>,0>,Level=0]' being compiled; /Core/Map.h(119) :
see reference to class template instantiation 'Eigen::MapBase<Derived> with [Derived=Eigen::Map<Eigen::Matrix<double,-1,1>,0>]' being compiled; vecsarray.cpp(24) : see reference to class template instantiation 'Eigen::Map<PlainObjectType,MapOptions> with [PlainObjectType=Eigen::Matrix<double,-1,1>,MapOptions=0]' being compiled


An attempt to use placement new on
Code: Select all
Eigen::Map<Eigen::VectorXd> mv0;

either by
Code: Select all
new (&mv0) Eigen::Map<Eigen::VectorXd>(v0.data());

or
Code: Select all
new (&mv0) Eigen::Map<Eigen::VectorXd>(v0.data(), v0.size());

results with
error C2512: 'Eigen::Map<PlainObjectType,MapOptions> with [PlainObjectType=Eigen::Matrix<double,-1,1>,MapOptions=0]' : no appropriate default constructor available
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
here is a working example:

Code: Select all
  VectorXd v(5);
  v.setOnes();
 
  std::vector<Map<VectorXd> > vm;
  vm.resize(4, Map<VectorXd>(0, 0));
  new (&vm[0]) Map<VectorXd>(v.data(), v.size());
mattd
Registered Member
Posts
28
Karma
0
Thanks! This worked!

I've done a mini-benchmark and data-initialization step (basically, setting up the pointers) was much faster -- while initialization took roughly 0.070 s for the copy (that was still faster than I expected, I guess you must have done a pretty good job vectorizing the copy operation on Eigen data-structures?), it took (within measurement & display precision) only "0 s" for the map.
Traversal took 0.021..0.025 s for both.

In case anyone wants to look at the code, I've left it on Ideone.com's pastebin.

http://www.ideone.com/ZswrI
copy:
0.077 s // initialization
Array X.sum(): -434.035
0.021 s // traversal

0.073 s
Array X.sum(): -434.035
0.021 s

0.065 s
Array X.sum(): -434.035
0.025 s

http://www.ideone.com/63iYj
map:
0 s // initialization
Array X.sum(): -434.035
0.021 s // traversal

0 s
Array X.sum(): -434.035
0.021 s

0 s
Array X.sum(): -434.035
0.021 s


Bookmarks



Who is online

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