std::vector<Eigen::Vector3d> to Eigen::MatrixXd Eigen - c++

I would like to know whether is there an easier way to solve my problem rather than use a for loop. So here is the situation:
In general, I would like to gather data points from my sensor (the message is of type Eigen::Vector3d and I can't change this, because it's a huge framework)
Gathered points should be saved in Eigen MatrixXd (in order to process them further as the Matrix in the optimization algorithm), the dimensions apriori of the Matrix are partially unknown, because it depends of me how many measurements I will take (one dimension is 3 because there are x,y,z coordinates)
For the time being, I created a std::vector<Eigen::Vector3d> where I collect points by push_back and after I finished collecting points I would like to convert it to MatrixXd by using the operation Map .
sensor_input = Eigen::Map<Eigen::MatrixXd>(sensor_input_vector.data(),3,sensor_input_vector.size());
But I have an error and note : no known conversion for argument 1 from Eigen::Matrix<double, 3, 1>* to Eigen::Map<Eigen::Matrix<double, -1, -1>, 0, Eigen::Stride<0, 0> >::PointerArgType {aka double*}
Can you tell me how I could implement this by using a map function?

Short answer: You need to write (after making sure that your input is not empty):
sensor_input = Eigen::Map<Eigen::MatrixXd>(sensor_input_vector[0].data(),3,sensor_input_vector.size());
The reason is that Eigen::Map expects a pointer to the underlying Scalar type (in this case double*), whereas std::vector::data() returns a pointer to the first element inside the vector (i.e., an Eigen::Vector3d*).
Now sensor_input_vector[0].data() will give you a pointer to the first (Vector3d) entry of the first element of your std::vector. Alternatively, you could reinterpret_cast like so:
sensor_input = Eigen::Map<Eigen::MatrixXd>(reinterpret_cast<double*>(sensor_input_vector.data()),3,sensor_input_vector.size());
In many cases you can actually avoid copying the data to a Eigen::MatrixXd but instead directly work with the Eigen::Map, and instead of MatrixXd you can use Matrix3Xd to express that it is known at compile time that there are exactly 3 rows:
// creating an Eigen::Map has O(1) cost
Eigen::Map<Eigen::Matrix3Xd> sensor_input_mapped(sensor_input_vector[0].data(),3,sensor_input_vector.size());
// use sensor_input_mapped, the same way you used sensor_input before
You need to make sure that the underlying std::vector will not get re-allocated while sensor_input_mapped is used. Also, changing individual elements of the std::vector will change them in the Map and vice versa.

This solution should work:
Eigen::MatrixXd sensor_input = Eigen::MatrixXd::Map(sensor_input_vector[0].data(),
3, sensor_input_vector.size());
Since your output will be a matrix of 3 x N (N is the number of 3D vectors), you could use the Map function of Eigen::Matrix3Xd too:
Eigen::Matrix3Xd sensor_input = Eigen::Matrix3Xd::Map(sensor_input_vector[0].data(),
3, sensor_input_vector.size());

Related

How to convert std::vector<std::pair<double, double>> dataVector to Eigen::MatrixXd rtData(dataVector.size(), 2)

Is there a fast way to make conversion below?
use "std::vector<std::pair<double, double>> dataVector" to initialize "Eigen::MatrixXd rtData(dataVector.size(), 2)"
Assuming sizeof(std::pair<int,int>) == 2*sizeof(int) (i.e., std::pair is not adding any padding) you can use an Eigen::Map of a row-major integer matrix, then cast it to double. Something like this:
typedef Eigen::Matrix<int, Eigen::Dynamic, 2, Eigen::RowMajor> MatrixX2i_r;
Eigen::MatrixXd rtData
= Eigen::Map<MatrixX2i_r const>(&(dataVector[0].first), dataVector.size(), 2).cast<double>();
You can also use that expression directly without storing it into a MatrixXd (conversion will happen on the fly, every time the expression is used -- so if you use rtData multiple times, it could still be better to store it once).
I am assuming you wish to create a two column matrix from bunch of pairs stacked in a vector.
As far I can see in the documentation MatrixXd is typedef of Matrix<double,dynamic,dynamic> so first potential issue is that you wish to fill matrix of double by int values.
Since MatrixXd is merely a typedef I don't think there is a suitable constructor in Eigen library for you to do quick conversion.
Simply write a code or a function that iterates through your vector and populates the matrix. In C++14:
int itt=0;
for (const auto& [first, second] : dataVector)
{
rtData(itt,0) = first;
rtData(itt,1) = second;
itt++;
}
That is a neat for loop that can go through vector of pairs, you still need the index of the elements, as Eigen matrices do not have push_back methods as STL.
Note again that I would advise MatrixXi if you are populating it with integers and not doubles.

Is there a way to switch the dimensions order in a multi-dimensional vector?

I have a 3D vector and I want to be able to chose which dimension to plot as a function of another dimension.
So far, I am doing this manually: I create a second 3D vector and re-organize the data accordingly. This solution is not very practical since I need to switch the indexes (inside the nested loop) every time I want to switch the dimensions...
Is there a better/cleaner solution ?
Thanks.
C++ does not provide multidimensional containers for the same reason that containers like std::vector do not provide a standard operator+ etc.: there is no standard that fits everyone's needs (in the case of a + operator, this could be concatenation, element-wise addition, increasing the dimensionality, who knows). If instead of a vector you take a class
<template typename T>
class volume {
private:
std::vector<T> data; // e.g. 3x2 array { 0, 1, 2, 3, 4, 5 }
std::vector<size_t> sizes; // e.g. 3x2 array { 3, 2 }
std::vector<size_t> strides; // e.g. 3x2 array { 1, 3 }
};
then you have all the flexibility you want - no need to stop at 3D!
As an example the data vector of a 3x2 array could be the first 6 natural numbers, the sizes vector would be { 3, 2 } and the strides array { 1, 3 }: in a row (of which there are 2) the elements are next to each other, to increase the row you need to move 3 positions forward.
In the general n-dimensional case you can make an at() operator that takes a vector (or an initializer_list) as a position argument, and the offset corresponding to that position is its inner product with strides.
If you don't feel like programming this from scratch then libraries like Blitz++ already provide this functionality.
No.
<RANT> C++ has no notion of multidimensional vectors. And has poor support for multidimensional arrays, because arrays are far from first class objects. So you are left with vectors of vectors [of vectors ...] and have to carefully control that all vectors in a containing vector have the same size (the language will not help you there). Or with multidimentional raw arrays... provided that the size for all dimensions but the last are known at compile time. </RANT>
As the number of dimensions are known (3D) I would go with a dedicated container using a 1D vector of size l*m*n (where l, m, and n are the size in the 3 dimensions). And a dedicated accessor function data(i,j,k). For there, it is possible to build another accessor tool that gives the data in one dimension starting from another one...
If you do not really like all that boiler plate code, you could have a look at the boost libraries. I do not use it, but if I correctly remember it contains a matrix class...

Conversion from std::vector<Eigen::Vector3d> to std::vector<Eigen::Vector3f>

I came across the problem that I want to convert from a std::vector<Eigen::Vector3d> to a std::vector<Eigen::Vector3f>. I was wondering if there is a solution where I dont have to iterate over the points.
// mapping using iteration
std::vector< Eigen::Vector3d> tf{ {1,1,1},{1,1,1},{1,1,1} };
std::vector< Eigen::Vector3f> tf2;
tf2.reserve(tf.size());
std::transform(tf.begin(), tf.end(), std::back_inserter(tf2), [](const Eigen::Vector3d& p) {
return p.cast<float>();
});
I tried some things like tf.data() and tried to cast that, but I didnt found a solution. I also looked into Eigen::Map<> class, but didnt really find a solution.
I don't think what you are asking is possible. Eigen::Map allows you to construct an Eigen data structure without needing to copy or move, it merely takes a view on existing contiguous data (typically from a std::array or std::vector). The operation you are looking to do, casting from doubles to float, two distinct types with different memory layouts, is an explicit operation. You would be shrinking the size of the vector in half. It is not possible to achieve this by taking a different view on the same data.
Assuming Vector3d and Vector3f don't introduce any padding (which is true for all compilers which Eigen supports), you could use an Eigen::Map<const Matrix3Xd> and .cast<float>() that into an Eigen::Map<Matrix3Xf> over the destination vector:
std::vector< Eigen::Vector3d> tf{ {1,1,1},{1,1,1},{1,1,1} };
std::vector< Eigen::Vector3f> tf2(tf.size()); // target needs to be actually allocated
Eigen::Matrix3Xf::Map(tf2[0].data(), 3, tf2.size())
= Eigen::Matrix3Xd::Map(tf[0].data(), 3, tf.size()).cast<float>();
With the upcoming 3.4 branch of Eigen you can also use iterators over the casted-map, like so:
Eigen::Map<Eigen::Matrix3Xd> input(tf[0].data(), 3, tf.size());
std::vector<Eigen::Vector3f> tf2(input.cast<float>().colwise().begin(),
input.cast<float>().colwise().end());

Cast dynamic matrix to fixed matrix in Eigen

For flexibility, I'm loading data into dynamic-sized matrices (e.g. Eigen::MatrixXf) using the C++ library Eigen. I've written some functions which require mixed- or fixed-sized matrices as parameters (e.g. Eigen::Matrix<float, 3, Eigen::Dynamic> or Eigen::Matrix4f). Assuming I do the proper assertions for row and column size, how can I convert the dynamic matrix (size set at runtime) to a fixed matrix (size set at compile time)?
The only solution I can think of is to map it, for example:
Eigen::MatrixXf dyn = Eigen::MatrixXf::Random(3, 100);
Eigen::Matrix<float, 3, Eigen::Dynamic> fixed =
Eigen::Map<float, 3, Eigen::Dynamic>(dyn.data(), 3, dyn.cols());
But it's unclear to me if that will work either because the fixed size map constructor doesn't accept rows and columns as parameters in the docs. Is there a better solution? Simply assigning dynamic- to fixed-sized matrices doesn't work.
You can use Ref for that purpose, it's usage in your case is simpler, and it will do the runtime assertion checks for you, e.g.:
MatrixXf A_dyn(4,4);
Ref<Matrix4f> A_fixed(A_dyn);
You might even require a fixed outer-stride and aligned memory:
Ref<Matrix4f,Aligned16,OuterStride<4> > A_fixed(A_dyn);
In this case, A_fixed is really like a Matrix4f.

How to get dimensions of a multidimensional vector in C++

all
I am using multidimensional STL vector to store my data in C++. What I have is a 3D vector
vector<vector<vector<double>>> vec;
What I want to retrieve from it is :
&vec[][1][]; // I need a pointer that points to a 2D matrix located at column 1 in vec
Anyone has any idea to do so? I would be extremly appreciate any help!
Regards
Long
It is best to consider vec just as a vector whose elements happen to be
vectors-of-vectors-of-double, rather than as a multi-dimensional structure.
You probably know, but just in case you don't I'll mention it,
that this datatype does not necessarily represent a rectangular cuboid.
vec will only have that "shape" if you ensure that all the vectors are
the same size at each level. The datatype is quite happy for the vector vec[j]
to be a different size from the one at vec[k] and likewise for vec[j][n]
to be a vector of different size from vec[j][m], so that your structure is "jagged".
So you want to get a pointer to the vector<vector<double>> that is at
index 1 in vec. You can do that by:
vector<vector<double>> * pmatrix = &vec[1];
However this pointer will be an unnecessarily awkward means of accessing that
vector<vector<double>>. You certainly won't be able to write the
like of:
double d = pmatrix[j][k];
and expect to get a double at coordinates (j,k) in the "matrix addressed
by a pmatrix". Because pmatrix is a pointer-to-a-vector-of-vector-of-double;
so what pmatrix[j] refers to is the vector-of-vector-of-double (not vector-of-double)
at index j from pmatrix, where the index goes in steps of
sizeof(vector<vector<double>>). The statement will reference who-knows-what
memory and very likely crash your program.
Instead, you must write the like of:
double d = (*pmatrix)[j][k];
where (*pmatrix) gives you the vector-of-vector-of-double addressed by pmatrix,
or equivalently but more confusingly:
double d = pmatrix[0][j][k];
Much simpler - and therefore, the natural C++ way - is to take a reference,
rather than pointer, to the vector<vector<double>> at index 1 in vec. You
do that simply by:
vector<vector<double>> & matrix = vec[1];
Now matrix is simply another name for the vector<vector<double>> at index 1 in vec,
and you can handle it matrix-wise just as you'd expect (always assuming
you have made sure it is a matrix, and not a jagged array).
Another thing to consider was raised in a comment by manu343726. Do you
want the code that receives this reference to vec[1] to be able to
use it to modify the contents of vec[1] - which would include changing its
size or the size of any of the vector<double>s within it?
If you allow modification, that's fine. If you don't then you want to get
a const reference. You can do that by:
vector<vector<double> > const & matrix = vec[1];
Possibly, you want the receiving code to be able to modify the doubles
but not the sizes of the vectors that contain them? In that case, std::vector
is the wrong container type for your application. If that's your position I
can update this answer to offer alternative containers.
Consider using matrix from some linear algebra library. There are some directions here