Initialise Eigen::vector with std::vector
Asked Answered
L

5

66

I have seen it done before but I cannot remember how to efficiently initialize an Eigen::Vector of known length with a std::vector of the same length. Here is a good example:

std::vector<double> v1 = {1.0, 2.0, 3.0};

Eigen::Vector3d v2; // Do I put it like this in here: v2(v1) ?
v2 << v1[0], v1[1], v1[2]; // I know you can do it like this but 
                           // I am sure i have seen a one liner.

I have perused this page about advanced matrix initialization but there is not a clear explanation of the method to perform this action.

Lochner answered 11/6, 2013 at 5:6 Comment(2)
Try Eigen::Vector3d v2(v1.data());.Whitefly
Map<ArrayXf> v2(v1.data(), 3)Scrubby
W
68

According to Eigen Doc, Vector is a typedef for Matrix, and the Matrix has a constructor with the following signature:

Matrix (const Scalar *data)

Constructs a fixed-sized matrix initialized with coefficients starting at data.

And vector reference defines the std::vector::data as:

std::vector::data

T* data();
const T* data() const;

Returns pointer to the underlying array serving as element storage. The pointer is such that range [data(); data() + size()) is always a valid range, even if the container is empty.

So, you could just pass the vector's data as a Vector3d constructor parameter:

Eigen::Vector3d v2(v1.data());

Also, as of Eigen 3.2.8, the constructor mentioned above defined as:

template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
inline Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>
  ::Matrix(const Scalar *data)
{
  this->_set_noalias(Eigen::Map<const Matrix>(data));
}

As you can see, it also uses Eigen::Map, as noted by @ggael and @gongzhitaao.

Whitefly answered 11/6, 2013 at 6:22 Comment(9)
And more generally, there is the Map<> class to deal with raw buffers: doc.Coakley
@soon Is there any way to convert the data type in this process? E.g. this doesn't work: std::vector<float> v = {1,2,3}; Eigen::Vector3d eigenVd(v.data());Facsimile
@DavidDoria, will the gongzhitaao's answer work for you? Cannot check right now, unfortunately.Whitefly
@soon I ended up creating a Matrix<OtherType, 3,1>, calling that constructor from v.data(), then using .cast<double> to convert. It's 2 steps, but it works :)Facsimile
What is the difference between v2(v1.data()); and v2(v1.data(),v1.data()+v1.size()); ? And, v1.data() seems return a raw T* pointer, how do eigen knows how long the vector is ?Gratt
@WesleyRanger, The documentation link seems to be broken and I'll update the answer as soon as possible. how do eigen knows how long the vector is - I suppose, Eigen expects an array with at least 3 elements, otherwise the behavior is undefined.Whitefly
@WesleyRanger, I've fixed the link, however, the Matrix documentation says nothing about the v1.data() size. Also, v2(v1.data(),v1.data()+v1.size()); is invalid constructor for Eigen::Vector3dWhitefly
@soon I think I've got the right solution: v2 = Eigen::Map<Eigen::VectorXd>(stdvector.data(), stdvector.size()); . I am using ligigl currently, and neither v2(v1.data()) nor v2(v1.data(),v1.data()+v1.size()) compiles with vs2015. I am not sure if Eigen updated something about this.Gratt
WARNING: this is cool, but also dangerous! Because the Eigen object will NOT create its own memory. It will operate on the memory provided by "data". In other words, working with the Eigen object when the "data" object is out of scope will result in a segmentation fault (or memory access violation).Manager
B
39

Just to extend @ggael answer in case others didn't notice it:

From Quick Reference Guide: Mapping External Array:

float data[] = {1,2,3,4};
Map<Vector3f> v1(data);       // uses v1 as a Vector3f object
Map<ArrayXf>  v2(data,3);     // uses v2 as a ArrayXf object
Map<Array22f> m1(data);       // uses m1 as a Array22f object
Map<MatrixXf> m2(data,2,2);   // uses m2 as a MatrixXf object
Believe answered 14/11, 2013 at 0:10 Comment(1)
WARNING: this is cool, but also dangerous! Because the Eigen object will NOT create its own memory. It will operate on the memory provided by "data". In other words, working with the Eigen object when the "data" object is out of scope will result in a segmentation fault (or memory access violation).Manager
N
36

The following one-liner should be more correct:

#include <Eigen/Dense>
#include <Eigen/Core>

std::vector<double> a = {1, 2, 3, 4};
Eigen::VectorXd b = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(a.data(), a.size());
Naught answered 18/6, 2017 at 8:17 Comment(5)
If the a is instead a const std::vector<double>, then change Eigen::VectorXd to const Eigen::VectorXd.Crystacrystal
do you need Eigen::Unaligned ? whyKnack
In practice not, although std::vector<> is not guaranteed to do aligned allocation, in practice it will typically be 8 or 16 byte aligned. On x86 you wouldn't notice, on arm your program could crash. So the unaligned is for correctness sake.Naught
Does b copy the values from a to its own memory? Specifically, is it okay to use b after a goes out of scope?Froggy
Yes b copies the data, so it can be used after a goes out of scope. Any Eigen::Map<> refers to other memory, so needs to be used with care. Any Eigen::Vector has it's own memory, so can be used independently.Naught
E
25

I found a better answer by this link:

https://forum.kde.org/viewtopic.php?f=74&t=94839

Basically first create a pointer to the std vector, and then pass the pointer and length to the constructor using Map.

This method works with dynamic Vector object in Eigen. While I tried using .data() function from std vector as the first answer suggest, it gives me an error: static assertion failed: YOU_CALLED_A_FIXED_SIZE_METHOD_ON_A_DYNAMIC_SIZE_MATRIX_OR_VECTOR

But using this method it works!

I just copy and paste the relevant code from the link here:

std::vector<double> v(4, 100.0);
double* ptr = &v[0];
Eigen::Map<Eigen::VectorXd> my_vect(ptr, 4);
Endorse answered 26/8, 2016 at 3:27 Comment(0)
R
-4

There are two options. If you want Eigen::VectorXd to share memory with std::vector, using

Eigen::Map<Eigen::VectorXd> b(v1.data(), v1.size());

otherwise (make a deep copy), using

Eigen::VectorXd a = Eigen::Map<Eigen::VectorXd>(v1.data(), v1.size());
Religieuse answered 4/12, 2018 at 6:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.