// Define the IO format to print on one lineEigen::IOFormateigen_1_line_fmt(Eigen::StreamPrecision,Eigen::DontAlignCols,", ",", ","",""," [","] ");// Print the vector using the defined formatstd::cout<<"p1: "<<p1.format(eigen_1_line_fmt)<<std::endl;
Attention! Eigen Quirks
[Quirk 1] Writable Vectors Can Be Written Directly As A Copy
[Quirk 2] Lazy Evaluation Could Cause Issues in Eigen (Version 3.4.0)
In Eigen, expressions like:
1
getter(item)-mean
may not be immediately evaluated due to lazy evaluation. getter(item)-mean is an Eigen::CwiseBinaryOp expression object that just stores references to sum and getter(item). The subtraction might not execute as expected, potentially leading to unexpected behavior—such as returning a zero vector instead of the intended result.
The fix is:
1
(getter(item)-mean).eval()
Even this does not work:
1
2
3
4
5
6
7
mean=std::accumulate(data.begin(),data.end(),VectorType::Zero().eval(),// init value, a *concrete vector*[&getter](constVectorType&sum,constauto&item){returnsum+getter(item);// <-- returns a *lazy expression*}).eval()/static_cast<double>(N);
[Quirk 3] Eigen Matrix Does NOT support dynamic matrix appending Efficiently
If we want to dynamically add rows to a matrix, unfortunately, I think it’d be more efficient to have a vector<vector<double>>, then convert it into a matrix all at once. This is because Eigen assumes that we know the size of the matrix beforehand. So otherwise, we need to resize the matrix constantly. One quirk of eigen::matrix::resize is that it resets values as well.
1
2
3
4
5
Eigen::MatrixXdmat(2,2);mat<<1,2,3,4;std::cout<<"Before resize:\n"<<mat<<"\n\n";mat.resize(2,2);// resize to the same size!
In this snippet, it was observed that eigen vectors in std::accumulate could produce garbage values. std::accumulate creates a temporary vector using the object’s copy constructor. One assumption I’m making here is Eigen vector’s copy constructor may not be super robust. So, write this piece using += instead
Sophus
In Sophus, the SE(2) group represents a rigid 2D transformation, which consists of both a rotation and a translation. The operation you’re looking for, SE(2) * Eigen::Vector2d, is a common need when transforming 2D points between coordinate frames.
1
2
3
4
5
6
usingVec2d=Eigen::Vector2d;usingSE2=Sophus::SE2d;// Example: SE(2) transformationSE2transform(Eigen::Rotation2Dd(M_PI/4),Vec2d(1.0,2.0));// 45-degree rotation and translation (1,2)Vec2dpoint(3.0,4.0);Vec2dtransformed_point=transform*point;
Sophus SO2 uses a unit complex number: [cos(θ), sin(θ)] as its internal representation instead of a single value. This is because:
Sophus SE3 stores an Eigen Quaternion (4 scalars, 32B) and a vector3d (3 scalars, 24B). Because they are fixed-size obj, they are packed into 16 byte boundaries. So in total, an sophus::SE3 is 64B.
1
2
3
4
5
classSE3{SO3Memberso3_;// has QuaternionMember unit_quaternion_; where QuaternionMember is Eigen::Quaternion<Scalar, Options>TranslationMembertranslation_;// Vector3<Scalar, Options>};
Sophus Quirks
It was observed that sophus SE3 multiplications and inverse are not very stable. On some machines, there were garbage values after multiplying.. in Release mode, there’s uninitialized memory being used somewhere that’s causing incorrect computation.
So when I use it, I would provide below overrides