Eigen Linear Algebra Library
repository·master·Indexed 22 days ago
https://github.com/px4/eigenA high-performance C++ template library for linear algebra, providing matrices, vectors, and numerical solvers. This documentation covers the Eigen Tensor module, including resizable Tensor, compile-time sized TensorFixedSize, and memory-mapping via TensorMap. It details lazy evaluation, memory layouts (ColMajor and RowMajor), execution devices (DefaultDevice, ThreadPoolDevice, GpuDevice), and tensor initialization methods.
What's inside px4-eigen
- Eigen is a C++ template library designed for linear algebra operations. It provides high-performance implementations for matrices, vectors, numerical solvers, and various related mathematical algorithms.
How Tensor operations and lazy evaluation work
masterMost Tensor methods return non-evaluated
Operationsrather than immediate results. These operations can be chained together (e.g.,a + b.constant(2.0f)).Lazy Evaluation: The chain of operations is evaluated lazily, meaning the actual computation typically only occurs when the operation is assigned to a
Tensorobject. This allows the library to optimize the execution of the entire expression chain.Avoid using C++ 'auto' with Tensor operations
masterUsing
autowith Tensor expressions does not result in aTensorobject; instead, it captures the non-evaluated expression tree (the "Operation"). You cannot access elements directly from anautovariable. To get the actual values, you must assign the expression to a concrete Tensor type.When to use
auto: Only useautowhen you intentionally want to delay evaluation to build a larger expression tree.Tensor<float, 3> t1(2, 3, 4); Tensor<float, 3> t2(2, 3, 4); auto t4 = t1 + t2; // t4 is an expression tree, NOT a Tensor. // cout << t4(0, 0, 0); // This will cause a COMPILATION ERROR! Tensor<float, 3> t3 = t4; // Now it is evaluated and works.Understand Eigen Tensor Datatypes
masterWhen working with Eigen Tensors, the documentation uses several pseudo-types to describe methods and operations:
<Tensor-Type>::Dimensions: An array-like object ofints representing the dimensions of a tensor. It has a.sizeattribute and supports array-style indexing. Seedimensions().<Tensor-Type>::Index: An integer type used for indexing tensors along their dimensions. Seeoperator(),dimension(), andsize().<Tensor-Type>::Scalar: The underlying data type of the individual tensor elements (e.g.,floatforTensor<float>).<Operation>: Indicates that a method returns a deferred tensor operation rather than a concrete tensor. An<Operation>must be evaluated (e.g., by assigning it to a tensor) before its values can be accessed, or it must be wrapped in aTensorRef.
Understand Eigen Tensor lazy evaluation
masterEigen Tensor operations (like
+,*,.exp()) do not perform computations immediately. Instead, they construct a lightweight "tensor operator" object (e.g.,TensorCwiseBinaryOp) that represents the expression tree. The actual computation is deferred until the expression is assigned to a concrete Tensor type (likeTensor,TensorFixedSize, orTensorMap). This mechanism enables lazy evaluation and high-performance optimizations.Tensor<float, 3> t1(2, 3, 4); Tensor<float, 3> t2(2, 3, 4); // t1 + t2 is a TensorCwiseBinaryOp object, NOT the sum itself. // The addition only happens during assignment to t3: Tensor<float, 3> t3 = t1 + t2;Configure and manage TensorLayout
masterEigen Tensors support two memory layouts:
ColMajor(default) andRowMajor.Important Constraints:
- Support: Only
ColMajoris currently fully supported;RowMajoris not recommended for all operations. - Compatibility: All operands in a tensor expression must use the same layout. Mixing layouts results in a compilation error.
- Specifying Layout: Layout is specified as a template argument in the tensor type.
Changing Layout: You can use the
swap_layout()method to change the layout. Note thatswap_layout()also reverses the order of the dimensions. To change the layout while preserving dimension order, combineswap_layout()with.shuffle()using a permutation array.// Explicitly specifying layouts Tensor<float, 3, ColMajor> col_major; // Default TensorMap<Tensor<float, 3, RowMajor>> row_major(data, ...); // Swapping layout (reverses dimension order) Tensor<float, 2, ColMajor> col_major(2, 4); Tensor<float, 2, RowMajor> row_major(2, 4); auto swapped = row_major.swap_layout(); // Dimensions are now 4x2 // Swapping layout while preserving dimension order array<int, 2> shuffle(1, 0); auto preserved = row_major.swap_layout().shuffle(shuffle);- Support: Only
How to use unsupported Eigen modules
masterThe
unsupported/directory contains modules provided "as is" without official support. To use these modules in your project, you must ensure the compiler can find the headers. You can use one of two methods:Add to include path: Add the
path_to_eigen/unsupporteddirectory to your project's include path. You can then include modules using the standard Eigen syntax:#include <Eigen/ModuleHeader>Direct include: Keep your include path pointing to the main Eigen directory and include the unsupported path explicitly:
#include <unsupported/Eigen/ModuleHeader>
#include <Eigen/ModuleHeader> // OR #include <unsupported/Eigen/ModuleHeader>Compile the BLAS library module
masterThe BLAS library module is built on top of Eigen but is not included in the default build. To compile this specific module, you must run themake blascommand from within your build directory.make blasControl when Tensor expressions are evaluated
masterYou can force the evaluation of a tensor expression using several methods:
- Assignment to a Tensor: Assigning an expression to
Tensor,TensorFixedSize, orTensorMaptriggers evaluation. - Using
.eval(): Inserts a call to materialize an intermediate value in the expression tree. This is useful for improving performance in complex expressions or avoiding aliasing issues. - Assigning to a
TensorRef: Allows accessing individual elements of an expression without materializing the entire tensor. This is efficient if you only need a subset of values, but slower if you access all values.
// 1. Assignment to Tensor Tensor<float, 3> result = (t1 + t2).exp(); // 2. Using .eval() to prevent redundant computation or aliasing // Example: preventing re-computation of maximum() Tensor<...> Y = ((X - X.maximum(depth_dim).eval().reshape(dims2d).broadcast(bcast)) * beta).exp(); // Example: preventing aliasing in Y = Y / ... Y = Y / (Y.sum(depth_dim).eval().reshape(dims2d).broadcast(bcast)); // 3. Using TensorRef for partial access TensorRef<Tensor<float, 3>> ref = ((t1 + t2) * 0.2f).exp(); float val = ref(0, 0, 0); // Evaluates on the fly- Assignment to a Tensor: Assigning an expression to
Choose a Tensor execution device
masterEigen Tensors support different execution backends via the
.device()method. If no device is specified, the default is a single-threaded CPU implementation optimized for Intel CPUs (SSE, AVX, FMA). To use a different device, you must declare the result Tensor explicitly and call.device()as the last call on the left of the assignment operator.Supported devices:
DefaultDevice: Single-threaded CPU (default).ThreadPoolDevice: Multi-threaded CPU execution.GpuDevice: GPU execution (requires explicit CUDA memory allocation).
// Using a ThreadPoolDevice for multi-threaded CPU execution Eigen::ThreadPoolDevice my_device(4); // 4 threads Eigen::Tensor<float, 2> c(30, 50); // The .device() call must be the last call on the left of the operator= c.device(my_device) = a.contract(b, dot_product_dims);Use the Translation class for geometric transformations
masterThe
Translation<Scalar, Dim>class represents a geometric translation. It is primarily designed to simplify the construction and updating ofTransformobjects (likeAffineTransformTypeorIsometryTransformType) rather than being used as a standalone storage for transformation matrices.Key features:
- Constructors: Initialize via individual coordinates (for 2D or 3D), a
VectorType, or an existingTranslationobject. - Accessors: Retrieve or modify translation components using
.x(),.y(), and.z()or by accessing the underlying.vector()or.translation(). - Composition: Use the
*operator to concatenate translations with other transformations (Scaling, Rotation, or general Linear transformations) or to apply a translation to a vector. - Identity: Use
Translation::Identity()to get a zero-translation object.
// Example: Creating and applying a 3D translation Eigen::Translation3d t(1.0, 2.0, 3.0); Eigen::Vector3d v(0.0, 0.0, 0.0); // Apply translation to a vector Eigen::Vector3d translated_v = t * v; // Concatenate with an identity translation Eigen::Translation3d t_identity = Eigen::Translation3d::Identity();- Constructors: Initialize via individual coordinates (for 2D or 3D), a
Use the AngleAxis class for 3D rotations
masterThe
AngleAxisclass represents a 3D rotation as an angle (in radians) around an arbitrary 3D axis. It is primarily used as an intermediate object to facilitate the creation of other rotation representations likeQuaternionor rotation matrices.Key Requirements
- Axis Normalization: When constructing an
AngleAxisobject, the axis vector must be normalized. If the axis is not a unit vector, the resulting rotation will be invalid. - Precision Types: For convenience, Eigen provides
AngleAxisf(float) andAngleAxisd(double).
Common Operations
- Conversion: You can convert an
AngleAxisto a 3x3 rotation matrix using.toRotationMatrix()or to aQuaternionvia multiplication or explicit conversion. - Concatenation: Use the
*operator to concatenate anAngleAxiswith anotherAngleAxisor aQuaternion. This returns aQuaternion. - Inversion: Use
.inverse()to get anAngleAxisrepresenting the opposite rotation. - Euler Angles: You can mimic Euler angles by combining
AngleAxiswith unit vectors (e.g.,Matrix3::UnitX()).
// Example: Creating a rotation of 0.5 radians around the Z-axis Eigen::AngleAxisd rotation(0.5, Eigen::Vector3d::UnitZ()); // Convert to a rotation matrix Eigen::Matrix3d mat = rotation.toRotationMatrix(); // Convert to a quaternion Eigen::Quaterniond q(rotation);- Axis Normalization: When constructing an