Skip to content

Instantly share code, notes, and snippets.

@mlund
Last active February 25, 2018 13:00
Show Gist options
  • Save mlund/0b74c6951d92897042e8c1225e75fb75 to your computer and use it in GitHub Desktop.
Save mlund/0b74c6951d92897042e8c1225e75fb75 to your computer and use it in GitHub Desktop.
Eigen facade or view for structured data in STL vector/array (Eigen3 and C++14 required)
#include <vector>
#include <iostream>
#include <type_traits>
#include <Eigen/Eigen>
/**
* @brief Eigen::Map facade to access data members in STL vectors/arrays
*
* No data is copied and modifications of the Eigen object
* modifies the original container and vice versa.
*
* Example:
*
* struct Particle {
* double mass=2.0;
* Eigen::Vector3d velocity;
* int type;
* };
*
* std::vector<Particle> v(10);
* auto m1 = asEigenVector(v.begin, v.end(), &Particle::velocity); --> 3x10 maxtix view
* auto m2 = asEigenMatrix(v.begin, v.end(), &Particle::mass); --> 1x10 vector view
*
* @warning Be careful that objects are properly aligned and divisible with `sizeof<double>`
*/
template<typename matrix=Eigen::MatrixXd, typename dbl=typename matrix::Scalar, class iter, class memberptr>
auto asEigenMatrix(iter begin, iter end, memberptr m) {
typedef typename std::iterator_traits<iter>::value_type T;
static_assert( sizeof(T) % sizeof(dbl) == 0, "value_type size must multiples of double");
const size_t s = sizeof(T) / sizeof(dbl);
const size_t cols = sizeof(((T *) 0)->*m) / sizeof(dbl);
return Eigen::Map<matrix, 0, Eigen::Stride<1,s>>((dbl*)&(*begin.*m), end-begin, cols).array();
}
template<typename matrix=Eigen::MatrixXd, typename dbl=typename matrix::Scalar, class iter, class memberptr>
auto asEigenVector(iter begin, iter end, memberptr m) {
typedef typename std::iterator_traits<iter>::value_type T;
static_assert( std::is_same<dbl&, decltype(((T *) 0)->*m)>::value, "member must be a scalar");
return asEigenMatrix<matrix>(begin, end, m).col(0);
}
struct Particle {
double mass=2.0;
Eigen::Vector3d velocity;
int type;
};
int main() {
std::vector<Particle> d(5);
auto m = asEigenVector( d.begin(), d.end(), &Particle::mass); // 1x5 vector
auto v = asEigenMatrix( d.begin(), d.end(), &Particle::velocity);// 3x5 matrix
d[1].mass = 0; // Map points to original data
v = v.setRandom(); // random positions
auto p = v.colwise() * m; // momenta, p=mv
std::cout << "masses:\n\n" << m << "\n\n";
std::cout << "velocities:\n\n" << v << "\n\n";
std::cout << "momenta:\n\n" << p << "\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment