CTMD(Compile-Time Multi-Dimensional matrix library) is a header-only C++ library for multi-dimensional matrix operations and broadcasting. Built on C++23’s std::mdspan and C++26's std::mdarray and std::submdspan, it enables both compile-time and run-time matrix computations. CTMD also supports acceleration through Eigen and OpenMP.
- NumPy-like Syntax: Designed with a familiar NumPy-style API for intuitive usage.
- Compile-Time Computation: Enables compile-time operations when possible for maximum efficiency.
- Flexibility: Seamlessly supports constexpr and non-constexpr contexts, diverse data types, and both static and dynamic extents.
- High Performance: Optimized for fast execution, leveraging modern C++ and hardware acceleration.
- Modern C++ Support: Fully compatible with C++23 and ready to adopt future features like std::linalg in C++26.
- C++ Version Compatibility:
- CTMD requires C++23 for full functionality.
- std::mdspan (C++23), std::mdarray (C++26), std::submdspan (C++26) are sourced from the Reference mdspan implementation.
- Extent Conventions:
- Scalar (0D mdspan): Data stored as an arithmetic type (e.g., int, float, double).
- Vector (1D mdspan): Data stored as a 1D mdarray.
- Matrix (2D mdspan): Data stored as a 2D mdarray.
- Acceleration:
- Using Eigen: Define the macro "USE_EIGEN" during build.
- Using OpenMP: Add the -fopenmp flag during compilation and link with the OpenMP library (-lgomp).
CTMD is a header-only library, so you can start using it by simply including ctmd/ctmd.hpp in your project.
To integrate CTMD into a Bazel project, add it as a dependency in your WORKSPACE file. Ensure your compiler supports C++23. For specific setup requirements, refer to the .devcontainer/DockerFile file. Alternatively, you can use the provided development container to automatically configure your environment.
-
Matrix addition
Code:
#include "ctmd/ctmd.hpp" namespace md = ctmd; constexpr auto a = md::full<int, md::extents<size_t, 3, 1, 2>>(1); constexpr auto b = md::full<int, md::extents<size_t, 2, 1>>(2); constexpr auto c = md::add(a, b); constexpr auto c_expect = md::full<int, md::extents<size_t, 3, 2, 2>>(3); constexpr bool is_allclose = md::allclose(c, c_expect); std::cout << "a extents: " << md::to_string(a.extents()) << std::endl; std::cout << "a: " << md::to_string(a) << std::endl << std::endl; std::cout << "b extents: " << md::to_string(b.extents()) << std::endl; std::cout << "b: " << md::to_string(b) << std::endl << std::endl; std::cout << "c extents: " << md::to_string(c.extents()) << std::endl; std::cout << "c: " << md::to_string(c) << std::endl; static_assert(is_allclose);
Output:
a extents: (3, 1, 2) a: [[[1, 1]], [[1, 1]], [[1, 1]]] b extents: (2, 1) b: [[2], [2]] c extents: (3, 2, 2) c: [[[3, 3], [3, 3]], [[3, 3], [3, 3]], [[3, 3], [3, 3]]]
CTMD uses GoogleTest for unit tests, located in the tests/ directory. Run all tests using Bazel:
bazel test tests/...
Benchmarks (in benchmarks/) are written using GoogleBenchmark. To run a benchmark (e.g., matrix addition in double precision):
bazel run benchmarks/add:pd
This project is developed and maintained by Uon robotics, South Korea. As a robotics company, we are committed to building robust, efficient software — and we believe in the power of open-source collaboration.
CTMD is in active development, and contributions are welcome! Feel free to open issues or pull requests — whether for bug reports, feature ideas, or code improvements.
CTMD is licensed under the Apache 2.0 License. See the LICENSE file for full details.