mp-units

repository·master·Indexed 23 days ago

https://github.com/mpusz/mp-units

A Modern C++ (C++20+) library for domain-correct quantities and units providing compile-time dimensional analysis and quantity kind safety based on the ISO 80000 standard. It features zero runtime overhead, support for the International System of Quantities (ISQ), and is a candidate for C++29 standardization. The library supports C++20 modules, freestanding mode, and full std::format compatibility.

Tokens
229.1K
Snippets
417
Records
888
Agent score
81%

What's inside mp-units

  1. Overview of mp-units

    master

    mp-units

    mp-units is a Modern C++ (C++20 and later) library that provides compile-time safety for domain-specific quantities and units. It is built on the ISO 80000 International System of Quantities (ISQ) and is a candidate for C++29 standardization.

    Key Safety Features

    • Quantity Kind Safety: Distinguishes between quantities that share the same dimension but represent different physical concepts (e.g., frequency Hz vs. radioactive activity Bq).
    • ISO 80000 (ISQ) Support: Allows functions to require specific quantities (e.g., isq::height) rather than generic dimensions (e.g., isq::length).
    • Strongly-Typed Numerics: Can be used for non-physics domains like item counts, financial values, or identifiers to prevent accidental mixing of numeric types.

    Performance and Integration

    • Zero Runtime Overhead: All dimensional analysis is performed at compile time.
    • Low Adoption Cost: No external dependencies, macro-free API, C++20 modules-ready, and freestanding-capable.
    #include <mp-units/systems/isq.h>
    #include <mp-units/systems/si.h>
    
    using namespace mp_units;
    using namespace mp_units::si::unit_symbols;
    
    // Compile-time dimensional analysis — zero runtime overhead
    static_assert(1 * km / (1 * s) == 1000 * m / s);
    
    // Function signatures encode domain/physics, not just dimensions
    void calculate_trajectory(quantity<isq::kinetic_energy[J]> e);
    
    int main()
    {
      quantity<isq::potential_energy[J]> Ep = 42 * J;
      quantity<isq::kinetic_energy[J]>   Ek = 123 * J;
      calculate_trajectory(Ek);         // ✅ correct
      // calculate_trajectory(Ep);      // ❌ potential energy ≠ kinetic energy (both in J)
    
      // quantity<Gy> q = 42 * Sv;      // ❌ absorbed dose ≠ dose equivalent (both J/kg)
    }
  2. Explore mp-units Framework Basics

    master

    The Framework Basics section covers the core technical pillars of the library. Use these topics to understand how mp-units handles physical quantities and units at a low level:

    • API & Design: Interface Introduction (API overview) and Design Overview (architecture principles).
    • Quantity & Unit Hierarchies: Systems of Quantities and Systems of Units.
    • Quantity Creation & Representation: Simple and Typed Quantities, Representation Types (numeric types), and Dimensionless Quantities (ratios/counts).
    • Mathematical Operations: Value Conversions, Quantity Arithmetics, and The Affine Space (points, quantities, and origins).
    • Advanced Type Features: Character of a Quantity (scalar/vector/tensor), Type Introspection, Concepts (C++20 concepts), and Generic Interfaces.
    • Safety & Utilities: safe_int<T> (overflow-safe arithmetic), Faster-than-lightspeed Constants, and Text Output (formatting).
  3. Advanced Usage Guides in mp-units

    master

    The mp-units library provides several advanced techniques for sophisticated scenarios that go beyond standard quantity calculations. These guides cover specialized domains such as symbolic computation, vector decomposition, and physics-specific workflows.

    Available Advanced Topics:

    • Pure Dimensional Analysis: Perform symbolic computation and compile-time validation using dimensions without specific units. This is useful for building automatic differentiation systems or custom arithmetic types.
    • Type-Safe Indices and Offsets: Model container indices and offsets as quantities with point origins. This covers handling 0-based vs 1-based indexing, SI vs IEC element prefixes, and stride arithmetic.
    • Decompose a Vector Quantity into Components: Split a vector quantity into named, strongly-typed 1D-vector component quantities using the quantity hierarchy, get<Idx>/get<QS>, and structured bindings.
    • Represent an Axial Vector as an Antisymmetric Tensor: Bridge domain-specific representations (like skew-symmetric tensors) to standard quantities (like isq::angular_velocity) using an explicit hat/vee dual.
    • Ensure Ultimate Safety: Implement guaranteed bounds enforcement by combining constrained representations, constraint_violation_handler, and check_in_range.
    • Working With Nondimensionalized Physics: Integrate mp-units with natural units and dimensionless quantities using scale-in/scale-out workflows while retaining strong typing.
  4. The mp-units learning curriculum

    master

    The learning resources are organized into three main stages:

    1. Tutorials (Progressive Learning)

    • Quick Start (~30 min): Creating quantities, simple math, and building a calculator.
    • Working with Units (~50 min): Unit conversions (safe/unsafe) and extracting numeric values.
    • Type Safety (~65 min): Compile-time protection, automatic dimensional analysis, quantity specifications, and generic interfaces (QuantityOf).
    • Affine Space (~55 min): Distinguishing points from quantities, point origins, and temperature handling.

    2. Foundation Workshops (Practical Patterns)

    Focus on integrating mp-units into existing codebases:

    • Refactoring to strong types.
    • Using QuantityOf for generic, type-safe interfaces.
    • Extracting numeric values for legacy interfaces.
    • Handling temperatures and affine spaces.
    • Interop with std::chrono.

    3. Extension & Advanced Workshops (Domain Specialization)

    • Extensions: Creating custom dimensionless units (e.g., cartons, pallets), typed quantities of the same kind (e.g., height vs width), custom quantity specifications, and custom base dimensions (e.g., financial shares/currency).
    • Advanced: Strongly-typed counts (for graphics/buffers), implementing physical constants with automatic cancellation, and incremental migration.
  5. Integrate mp-units with existing codebases

    master

    The mp-units integration guides provide instructions for incorporating the library into various development scenarios. Use these guides to address the following needs:

    • Legacy APIs: Interfacing with code that expects raw numeric types instead of quantities.
    • Custom Representations: Using your own numeric types (such as fixed-point or arbitrary precision) as the underlying representation for quantities.
    • Third-party Libraries: Integrating with linear algebra libraries like Eigen, GLM, or Blaze using shipped plugins.
    • Interoperability: Converting between mp-units quantities and external types like std::chrono or other units libraries.
    • Portability: Ensuring maximum compatibility across different compilers and environments.
  6. Compare safety benefits of mp-units vs raw doubles in HEP

    master

    When working in High Energy Physics (HEP), using raw double types for physical quantities leads to several risks that mp-units mitigates at compile time. The following table summarizes the safety improvements provided by the mp-units HEP system:

    ProblemStatus with raw doubleStatus with mp-units
    Wrong dimensions at call site❌ Runtime, if ever✅ Compile error
    Arguments swapped❌ Runtime, if ever✅ Compile error
    Framework unit mismatch (10×/1000×)❌ Runtime, if ever✅ Compile error
    Same-dimension quantity confusion❌ Runtime, if ever✅ Compile error
    CODATA version inconsistencies❌ Manual tracking✅ Namespace-selected
    Performance overhead✅ Zero (same assembly)
    Migration of 2.5M-line codebases✅ Incremental, 7 phases
  7. Summary of mp-units compatibility strategies

    master

    mp-units allows you to choose between modern, terse syntax for the latest compilers and portable, verbose macros for wider C++ standard support. This enables incremental adoption: you can start with portable code and refactor to modern syntax as your environment evolves.

    Key compatibility tools include:

    • QUANTITY_SPEC(): Provides compatibility across C++20 and C++23.
    • MP_UNITS_STD_FMT: Enables support for either std::format or the {fmt} library.
    • Contract checking macros: Provides support for gsl-lite or ms-gsl.
    • Module guards: Supports both C++ modules and traditional header files.
  8. Explore mp-units systems and hierarchies

    master

    The mp-units library provides a wide range of pre-defined measurement systems. You can navigate the reference documentation through several specialized indexes to find specific components:

    • Dimensions: Base dimensions used to define quantities.
    • Quantities: Specific physical quantities (e.g., length, mass).
    • Prefixes: Multipliers like kilo-, milli-, etc.
    • Units: The actual units of measurement (e.g., meter, second).
    • Constants: Physical or mathematical constants.
    • Point Origins: Definitions for point origins.
    • Quantity Hierarchies: Information on ISQ (International System of Quantities) quantity type hierarchies.
  9. What is Quantity Kind Safety and how does it work?

    master

    Quantity kind safety is a high-level safety feature in mp-units that distinguishes between quantities that share the same physical dimension but represent different physical concepts (different "kinds").

    While traditional unit libraries might allow you to add or compare any two quantities with the same dimension (e.g., adding two different types of length), mp-units treats different kinds as incompatible types. This prevents common errors where conceptually distinct values are mixed up, such as:

    • Absorbed dose (Gy) vs. Dose equivalent (Sv) (both $L^2T^{-2}$)
    • Frequency (Hz) vs. Activity (Bq) (both $T^{-1}$)
    • Fluid head vs. Water head (both $L$)
    • Various dimensionless counts (e.g., item_count vs. widget_count)

    In mp-units, attempting to add, compare, or assign quantities of different kinds results in a compile-time error.

    To interact with these quantities, you must either:

    1. Use an explicit conversion function (e.g., involving a physical constant like specific_gravity).
    2. Explicitly upcast to a more generic dimension/kind (e.g., using isq::height for both fluid and water head).
    // Example of distinct kinds preventing errors
    quantity absorbed_dose = 1.5 * Gy;
    quantity dose_equivalent = 2.0 * Sv;
    
    // auto result = absorbed_dose + dose_equivalent;           // ❌ Compile-time error!
    // auto equal = (absorbed_dose == dose_equivalent);         // ❌ Compile-time error!
  10. What is a quantity point and when to use it?

    master

    A quantity point specifies an absolute quantity with respect to an origin (e.g., a specific timestamp, an altitude, or a temperature point).

    When to use it: Use quantity_point in places where adding two values is mathematically meaningless, such as:

    • Temperatures (e.g., $20^\circ\text{C}$)
    • Timestamps
    • Altitudes
    • Odometer readouts

    Quantity points model The Affine Space. They offer more restricted operations than quantity to provide additional type safety. You can convert a point to a different unit representation using the .in() method.

    import mp_units;
    #include <print>
    
    int main()
    {
      using namespace mp_units;
      using namespace mp_units::si::unit_symbols;
      using namespace mp_units::usc::unit_symbols;
    
      // Create a temperature point at 20 degrees Celsius
      quantity_point temp = point<deg_C>(20.);
    
      // Convert and print
      std::println("Temperature: {} ({})", temp, temp.in(deg_F));
    }
  11. What is Pure Dimensional Analysis in mp-units

    master

    Pure dimensional analysis allows you to track and validate dimensions and quantity types without needing actual numerical values. This is achieved by embedding Dimension or QuantitySpec types into your own custom arithmetic types. By overloading operators to propagate these embedded types, the library performs full dimensional analysis and type checking at compile-time with zero runtime overhead.

    This is useful for:

    • Symbolic computation systems.
    • Validating equation systems before numerical evaluation.
    • Implementing custom arithmetic types like automatic differentiation or interval arithmetic.
    • Enforcing dimensional relationships in APIs without committing to specific units.