65

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.

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175

5 Answers5

66

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.

awesoon
  • 32,469
  • 11
  • 74
  • 99
  • 7
    And more generally, there is the Map<> class to deal with raw buffers: [doc](http://eigen.tuxfamily.org/dox-devel/group__TutorialMapClass.html). – ggael Jun 11 '13 at 06:44
  • @soon Is there any way to convert the data type in this process? E.g. this doesn't work: `std::vector v = {1,2,3}; Eigen::Vector3d eigenVd(v.data());` – David Doria Feb 11 '16 at 19:09
  • @DavidDoria, will the **gongzhitaao**'s answer work for you? Cannot check right now, unfortunately. – awesoon Feb 11 '16 at 22:08
  • @soon I ended up creating a `Matrix`, calling that constructor from `v.data()`, then using `.cast` to convert. It's 2 steps, but it works :) – David Doria Feb 11 '16 at 22:16
  • 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 ? – Wesley Ranger Jun 25 '16 at 06:56
  • @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. – awesoon Jun 25 '16 at 07:11
  • @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::Vector3d` – awesoon Jun 25 '16 at 07:41
  • @soon I think I've got the right solution: `v2 = Eigen::Map(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. – Wesley Ranger Jun 25 '16 at 10:35
  • 2
    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). – Sobi Jan 05 '18 at 23:29
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
gongzhitaao
  • 6,566
  • 3
  • 36
  • 44
  • 27
    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). – Sobi Jan 05 '18 at 23:27
35

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());
keineahnung2345
  • 2,635
  • 4
  • 13
  • 28
Mr. White
  • 571
  • 5
  • 12
  • 6
    If the `a` is instead a `const std::vector`, then change `Eigen::VectorXd` to `const Eigen::VectorXd`. – apdnu Oct 14 '17 at 21:38
  • 3
    do you need `Eigen::Unaligned` ? why – Alec Jacobson Jul 09 '20 at 15:43
  • 3
    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. – Mr. White Jul 10 '20 at 16:03
  • Does `b` copy the values from `a` to its own memory? Specifically, is it okay to use `b` after `a` goes out of scope? – Charles Jun 23 '21 at 22:21
  • 2
    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. – Mr. White Aug 12 '21 at 16:03
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);
Pengyao
  • 817
  • 10
  • 15
-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());
Lee David
  • 69
  • 7