Suppose I have
Eigen::VectorXd x; //{1,2,3,4,5,6,7,8}
and
Eigen::VectorXd ind_vec; //{0,2,4,5}
Is there a way an easy way to extract the ind_vec
elements of x?
Something like:
x.extract(ind_vec) returning {1, 3, 5, 6}
Since the current answer was not satisfactory for me, I googled a bit and I found this tutorial in the Eigen documentation.
#include <Eigen/Dense>
#include <iostream>
using namespace std;
int main()
{
Eigen::ArrayXf v(6);
v << 1, 2, 3, 4, 5, 6;
cout << "v.head(3) =" << endl << v.head(3) << endl << endl;
cout << "v.tail<3>() = " << endl << v.tail<3>() << endl << endl;
v.segment(1,4) *= 2;
cout << "after 'v.segment(1,4) *= 2', v =" << endl << v << endl;
}
Will output:
v.head(3) =
1
2
3
v.tail<3>() =
4
5
6
after 'v.segment(1,4) *= 2', v =
1
4
6
8
10
6
I haven't tested it with vectors, but I guess should be possible as well.
In C++ 11 (and up) do this:
ind_vec.unaryExpr(x);
You can make use of unaryExpr(Functor)
since we are taking an index array and applying a functor to each element of the array. The result type will have the same dimensions as the index array. For the functor, we need an object with an operator:
Scalar operator() (Index index) const {
return x[index];
}
As it happens, Eigen::Matrix
has just such an operator already. Here's a full example:
Eigen::VectorXd x(8); x << 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8;
Eigen::Array4i ind_vec(0,2,4,5);
// result has dimensions as ind_vec matrix/array, and scalar type from x
Eigen::Array4d result = ind_vec.unaryExpr(x);
std::cout << "result^T = " << result.transpose() << std::endl;
// Output:
// result^T = 1.1 3.3 5.5 6.6
The only caveat is that this requires at least C++11 to work. The problem is that eigen internally relies upon std::result_of
to get the scalar result type. Without that, you might get errors stating that a cast is required.
Seems like it'd be easy to write yourself if it's just for vectors:
#include "Eigen/Core"
template <typename T, typename T2>
T extract(const T2& full, const T& ind)
{
int num_indices = ind.innerSize();
T target(num_indices);
for (int i = 0; i < num_indices; i++)
{
target[i] = full[ind[i]];
}
return target;
}
int main()
{
Eigen::VectorXd full(8);
full << 1, 2, 3, 4, 5, 6, 7, 8;
Eigen::Vector4d ind_vec(4);
ind_vec << 0, 2, 4, 5;
std::cout << "full:" << full<< std::endl;
std::cout << "ind_vec:" << ind_vec<< std::endl;
std::cout << "extracted" << extract(full,ind_vec) << std::endl;
}
That should work for most cases
edit: for cases where your index scalar type is different than your source and target scalar type the following will work (for all build-in Eigen types).
template <typename T, typename T2>
Eigen::Matrix<typename T2::Scalar,T::RowsAtCompileTime,T::ColsAtCompileTime,T::Options>
extract2(const Eigen::DenseBase<T2>& full, const Eigen::DenseBase<T>& ind)
{
using target_t = Eigen::Matrix < T2::Scalar, T::RowsAtCompileTime, T::ColsAtCompileTime, T::Options > ;
int num_indices = ind.innerSize();
target_t target(num_indices);
for (int i = 0; i < num_indices; i++)
{
target[i] = full[ind[i]];
}
return target;
}
(this is different from the other one in that you can use a vector of ints as indices and a vector of doubles as source and get a vector of doubles returned instead of a vector of ints as extract()
above would do)
This is now supported in Eigen 3.4 via slicing and indexing:
Eigen::VectorXd x(8); x<<1,2,3,4,5,6,7,8;
Eigen::VectorXi ind_vec(4); ind_vec<<0,2,4,5;
Eigen::VectorXd x_slice = x(ind_vec);
As the docs note, ind_vec
can also be
an arbitrary list of row or column indices stored as either an ArrayXi, a std::vector, std::array<int,N>, etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With