how can I convert a vector to an eigen arrayxd in c++?
The only way I found involve doing:
Eigen::ArrayXd newEigen = Eigen::ArrayXd::Zero(oldVector.size());
and then making a loop to replace each element individually. Is there a better way?
I tried a loop. expecting simple way to copy the data, like:
Eigen::ArrayXd newEigen(oldVector.data());
While this is probably the most commonly asked question in the [eigen] tag, a surprising number of answers are not optimal. So here is the shortest, cleanest version:
Eigen::ArrayXd newEigen = Eigen::ArrayXd::Map(
oldVector.data(), static_cast<Eigen::Index>(oldVector.size()));
If you don't want to copy the data, an Eigen::Map borrows the data in the vector so you can access or change it in-place.
Eigen::Map<Eigen::ArrayXd> mapped(
oldVector.data(), static_cast<Eigen::Index>(oldVector.size()));
Eigen::Map is to Eigen::Array what std::string_view is to std::string if that helps explaining.
Related
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.
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());
I have a matrix like this:
array<array<double, DISMAX>, DISMAX> Md;
and a vector like this:
array<double, DISMAX> matrixLine;
DISMAX is a constant.
My question: How can I copy that vector to one line of the matrix without using a for loop? Is it possible?
The simplest method is to do the obvious:
Md[0] = matrixLine;
There is still a loop but the std::array hides the details.
Copy assignment, e.g., Md[0] = matrixLine, should work just fine.
I have an std matrix defined as:
std::vector<std::vector<double> > Qe(6,std::vector<double>(6));
and a vector v that is:
v{0, 1, 3, 2, 4, 5};
I would like to swap the columns 3 and 2 of matrix Qe like indicated in vector v.
In Matlab this is as easy as writing Qe=Qe(:,v);
I wonder if there is an easy way other than a for loop to do this in c++.
Thanks in advance.
Given that you've implemented this as a vector of vectors, you can use a simple swap:
std::swap(Qe[2], Qe[3]);
This should have constant complexity. Of course, this will depend on whether you're treating your data as column-major or row-major. If you're going to be swapping columns often, however, you'll want to arrange the data to suit that (i.e., to allow the code above to work).
As far as doing the job without a for loop when you're using row-major ordering (the usual for C++), you can technically eliminate the for loop (at least from your source code) by using a standard algorithm instead:
std::for_each(Qe.begin(), Qe.end(), [](std::vector<double> &v) {std::swap(v[2], v[3]); });
This doesn't really change what's actually happening though--it just hides the for loop itself inside a standard algorithm. In this case, I'd probably prefer a range-based for loop:
for (auto &v : Qe)
std::swap(v[2], v[3]);
...but I've never been particularly fond of std::for_each, and when C++11 added range-based for loops, I think that was a superior alternative to the vast majority of cases where std::for_each might previously have been a reasonable possibility (IOW, I've never seen much use for std::for_each, and see almost none now).
Depends on how you implement your matrix.
If you have a vector of columns, you can swap the column references. O(1)
If you have a vector of rows, you need to swap the elements inside each row using a for loop. O(n)
std::vector<std::vector<double>> can be used as a matrix but you also need to define for yourself whether it is a vector of columns or vector of rows.
You can create a function for this so you don't write a for loop each time. For example, you can write a function which receives a matrix which is a vector of columns and a reordering vector (like v) and based on the reordering vector you create a new matrix.
//untested code and inefficient, just an example:
vector<vector<double>> ReorderColumns(vector<vector<double>> A, vector<int> order)
{
vector<vector<double>> B;
for (int i=0; i<order.size(); i++)
{
B[i] = A[order[i]];
}
return B;
}
Edit: If you want to do linear algebra there are libraries that can help you, you don't need to write everything yourself. There are math libraries for other purposes too.
If you are in a row scenario. The following would probably work:
// To be tested
std::vector<std::vector<double> >::iterator it;
for (it = Qe.begin(); it != Qe.end(); ++it)
{
std::swap((it->second)[2], (it->second)[3]);
}
In this scenario I don't see any other solution that would avoid doing a loop O(n).
I'm trying to learn the Eigen C++ library, and was wondering if there is some nice shorthand for initializing dynamic vectors and matrices. It would be really nice to write something like you would using a std::vector
std::vector<int> myVec = {1,2,3,6,5,4,6};
i.e.
VectorXi x = {1,2,3,4,7,5,7};
The closest (ugly) equivalent I can find involves Map . .
int xc[] = {2,3,1,4,5};
Map<VectorXi> x(xc,sizeof(xc)/sizeof(xc[0]));
What other initialization methods are there?
By the code you showed, you are OK in writing const items. So maybe you can do something like
std::vector<int> vec;
const int init_vec[5] = {1,2,3,4,5}
vec.assign(init_vec, init_vec + 5);
See this post of how use array to populate vectors.
EDIT: Correct a wrong link formating.
For fixed size matrices/vectors, you can use the comma initializer:
Matrix3f m;
m<<1,2,3,4,5,6,7,8,9;
I can't test it right now, but it should work similarly for your situation:
VectorXi x(5);
x << 2,3,1,4,5;
If it does not, you could use a temporary Vector, fill it with the five elements using the comma initializer and then assign it to the VectorXi.
edit:
You might also be interested in this page: Eigen: Advanced Initialization