Using a Linear Algebra Library as the Representation¶
Overview¶
This example shows how a linear algebra library can be used directly as the
representation type of a vector
quantity. The exact same mp-units code is compiled against four different vector
types: three mainstream third-party libraries
(Eigen, GLM, and
Blaze) and the library's own built-in
cartesian_vector; only the
small shim that names the vector type and constructs it differs.
The key idea is that a 3D vector — Eigen::Vector3d, glm::dvec3,
blaze::StaticVector<double, 3>, or cartesian_vector<double> — becomes the
representation, so the quantity carries both a unit and a direction:
Enabling the Integration¶
For each third-party library, mp-units ships an opt-in plugin that wires the library's vector type into the representation customization points automatically, with no adapter code of your own. It is available both as a header and a named module:
#include <mp-units/integrations/eigen.h> // or <mp-units/integrations/glm.h>, or .../blaze.h>
// in module mode instead: import mp_units.integrations.eigen;
Each header is guarded with __has_include, so it is a harmless no-op when the corresponding
library is not available. The built-in cartesian_vector needs no plugin at all — it ships
with the library and is a representation type out of the box. This example is compiled against
all four backends, in both header and module modes.
Key Concepts¶
Unit conversion of a whole vector¶
Converting the unit scales every component at once:
Vector quantity × scalar quantity¶
Multiplying a velocity vector by a duration produces a displacement vector, with the units combined automatically:
This is where expression-template libraries (Eigen, Blaze) need care: their operator*
returns a lazy proxy that holds references to its operands. mp-units materializes such
a proxy into the concrete vector type before storing it, so no dangling references are possible.
Magnitude as a scalar quantity¶
The library's magnitude() customization point recognizes the norm() (or length()) that
linear algebra libraries provide. A vector quantity supports magnitude() directly, returning
the Euclidean magnitude as a scalar quantity in the same unit:
Decomposing into named components¶
Declaring the whole as a named quantity, instead of the generic isq::velocity above, lets you
split it into named component quantities, one per axis. Give each axis its own kind and list the
axes in coordinate order:
inline constexpr struct flight_velocity : quantity_spec<isq::velocity> {} flight_velocity;
inline constexpr struct forward_velocity : quantity_spec<isq::velocity, is_kind> {} forward_velocity;
inline constexpr struct lateral_velocity : quantity_spec<isq::velocity, is_kind> {} lateral_velocity;
inline constexpr struct vertical_velocity : quantity_spec<isq::velocity, is_kind> {} vertical_velocity;
template<>
struct mp_units::vector_components<flight_velocity> :
mp_units::vector_axes<forward_velocity, lateral_velocity, vertical_velocity> {};
The velocity, now a flight_velocity, decomposes into 1D-vector quantities, through structured
bindings or by axis spec:
const quantity velocity = flight_velocity(la::make_vec3(30, 40, 0) * km / h);
const auto [forward, lateral, vertical] = velocity; // forward 30, lateral 40, vertical 0 (km/h)
quantity climb = get<vertical_velocity>(velocity); // or pull one axis out by its spec
This works against every backend in this example, because each vector type is element-accessible
through operator[]. See
Decompose a Vector Quantity into Components
for the hierarchy rules, the representation requirements, and why access is get<Idx> rather than
operator[].
What About Other Libraries?¶
The same recipe applies to any library whose vector type is weakly regular (copyable and
bool-returning equality-comparable) and provides a Euclidean norm. Note that
Armadillo is not supported: its operator== returns an
element-wise mask rather than a bool, so its types are not std::equality_comparable and
cannot satisfy the representation requirements.
See Also¶
- Representation Types - the customization points used here
- Using Custom Representation Types - how to integrate your own type
- Decompose a Vector Quantity into Components - splitting a vector quantity into named, strongly-typed component quantities
- Character of a Quantity - scalars vs vectors vs tensors