Cast dynamic matrix to fixed matrix in Eigen - c++

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.

Related

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());

std::vector<Eigen::Vector3d> to Eigen::MatrixXd Eigen

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());

Eigen: Computing norms of matrix rowwise, is slower than computing them iteratively on vectors

I am trying to accelerate a computation of vector norms using Eigen.
Tried doing it in two ways:
Way 1: Storing the vectors separately in an array (std::vector)
std::vector<Eigen::Matrix<double, 1, VECTOR_SIZE>> my_vectors(num_vectors);
Eigen::Matrix<double, Eigen::Dynamic, 1> norms(num_vectors, 1);
for (int i = 0 ; i < my_vectors.size() ; i++) {
norms(i, 0) = my_vectors[i].norm();
}
Way 2: Storing the vectors as rows of the same matrix and using rowwise norm
Eigen::Matrix<double, Eigen::Dynamic, VECTOR_SIZE> my_vectors(num_vectors, VECTOR_SIZE);
Eigen::Matrix<double, Eigen::Dynamic, 1> norms = my_vectors.rowwise().norm();
I was surprised to see that whereas Way1 is slow, Way2 is even slower.
Am I doing something wrong? Is there a way to compute the norms faster?
In another test I made, the same was true for vector subtraction. An iteration over separate vectors, reducing the same vector from each, was faster than storing all the vectors as matrix rows and using .rowwise() - vector_to_subtract
From https://eigen.tuxfamily.org/dox/group__TopicStorageOrders.html
If the storage order is not specified, then Eigen defaults to storing the entry in column-major. This is also the case if one of the convenience typedefs (Matrix3f, ArrayXXd, etc.) is used.
My best guess is memory access issues: rowwise() is probably doing a bunch of "skipping" in memory, i.e. not reading consecutive regions - while storing each row separately does not suffer from this problem.
WARNING: While I wrote my answer with best of intentions, I couldn't test it myself, and apparently it would slow things down even further. Thanks SomethingSomething for testing the idea.

Creating an Eigen matrix from an array with row-major order

I have an array of doubles, and I want to create a 4-by-4 matrix using the Eigen library. I also want to specify that the data is stored in row-major order. How can I do this?
I have tried the following, but it does not compile:
double data[16];
Eigen::Matrix4d M = Eigen::Map<Eigen::Matrix4d>(data, 4, 4, Eigen::RowMajor);
You need to pass a row-major matrix type to Map, e.g.:
Map<Matrix<double,4,4,RowMajor> > M(data);
then you can use M as an Eigen matrix, and the values of data will be modified, e.g.:
M = M.inverse();
If you want to copy the data to a true column-major Eigen matrix, then do:
Matrix4d M = Map<Matrix<double,4,4,RowMajor> >(data);
Of course, you can also copy to a row-major matrix by using the right type for M.
RowMajor forms actually come in handy when using arrays to store data sometimes. Hence you can also prefer using a typedef to RowMajor type.
namespace Eigen{
typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> MatrixXfRowMajor;
}
You can replace by float by any datatype of choice. For a 4x4 matrix then, we can simply do
Eigen::MatrixXfRowMajor mat;
mat.resize(4,4);