# `omath::Mat` > Header: your project’s `mat.hpp` (requires `vector3.hpp`) > Namespace: `omath` > Requires: **C++23** (uses multi-parameter `operator[]`) > SIMD (optional): define **`OMATH_USE_AVX2`** to enable AVX2-accelerated multiplication for `float`/`double`. --- ## Overview `omath::Mat` is a compile-time, fixed-size matrix with: * **Row/column counts** as template parameters (no heap allocations). * **Row-major** or **column-major** storage (compile-time via `MatStoreType`). * **Arithmetic** and **linear algebra**: matrix × matrix, scalar ops, transpose, determinant, inverse (optional), etc. * **Transform helpers**: translation, axis rotations, look-at, perspective & orthographic projections. * **I/O helpers**: `to_string`/`to_wstring`/`to_u8string` and `std::formatter` specializations. --- ## Template parameters | Parameter | Description | Default | | ----------- | ------------------------------------------------------------------------ | ----------- | | `Rows` | Number of rows (size_t, compile-time) | — | | `Columns` | Number of columns (size_t, compile-time) | — | | `Type` | Element type (arithmetic) | `float` | | `StoreType` | Storage order: `MatStoreType::ROW_MAJOR` or `MatStoreType::COLUMN_MAJOR` | `ROW_MAJOR` | ```cpp enum class MatStoreType : uint8_t { ROW_MAJOR = 0, COLUMN_MAJOR }; ``` --- ## Quick start ```cpp #include "mat.hpp" using omath::Mat; // 4x4 float, row-major Mat<4,4> I = { {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}, }; // Multiply 4x4 transforms Mat<4,4> A = { {1,2,3,0},{0,1,4,0},{5,6,0,0},{0,0,0,1} }; Mat<4,4> B = { {2,0,0,0},{0,2,0,0},{0,0,2,0},{0,0,0,1} }; Mat<4,4> C = A * B; // matrix × matrix // Scalar ops auto D = C * 0.5f; // scale all entries // Indexing (C++23 multi-parameter operator[]) float a03 = A[0,3]; // same as A.at(0,3) A[1,2] = 42.0f; // Transpose, determinant, inverse auto AT = A.transposed(); float det = A.determinant(); // only for square matrices auto inv = A.inverted(); // std::optional; std::nullopt if non-invertible ``` > **Note** > Multiplication requires the **same** `StoreType` and `Type` on both operands, and dimensions must match at compile time. --- ## Construction ```cpp Mat(); // zero-initialized Mat(std::initializer_list> rows); explicit Mat(const Type* raw_data); // copies Rows*Columns elements Mat(const Mat&); Mat(Mat&&); ``` * **Zeroing/setting** ```cpp m.clear(); // set all entries to 0 m.set(3.14f); // set all entries to a value ``` * **Shape & metadata** ```cpp Mat<>::row_count(); // constexpr size_t Mat<>::columns_count(); // constexpr size_t Mat<>::size(); // constexpr MatSize {rows, columns} Mat<>::get_store_ordering(); // constexpr MatStoreType using ContainedType = Type; // alias ``` --- ## Element access ```cpp T& at(size_t r, size_t c); T const& at(size_t r, size_t c) const; T& operator[](size_t r, size_t c); // C++23 T const& operator[](size_t r, size_t c) const; // C++23 ``` > **Bounds checking** > In debug builds you may enable/disable range checks via your compile-time macros (see the source guard around `at()`). --- ## Arithmetic * **Matrix × matrix** ```cpp // (Rows x Columns) * (Columns x OtherColumns) -> (Rows x OtherColumns) template Mat operator*(const Mat&) const; ``` * Complexity: `O(Rows * Columns * OtherColumns)`. * AVX2-accelerated when `OMATH_USE_AVX2` is defined and `Type` is `float` or `double`. * **Scalars** ```cpp Mat operator*(const Type& s) const; Mat& operator*=(const Type& s); Mat operator/(const Type& s) const; Mat& operator/=(const Type& s); ``` * **Transpose** ```cpp Mat transposed() const noexcept; ``` * **Determinant (square only)** ```cpp Type determinant() const; // 1x1, 2x2 fast path; larger uses Laplace expansion ``` * **Inverse (square only)** ```cpp std::optional inverted() const; // nullopt if det == 0 ``` * **Minors & cofactors (square only)** ```cpp Mat strip(size_t r, size_t c) const; Type minor(size_t r, size_t c) const; Type alg_complement(size_t r, size_t c) const; // cofactor ``` * **Utilities** ```cpp Type sum() const noexcept; auto& raw_array(); // std::array& auto const& raw_array() const; ``` * **Comparison / formatting** ```cpp bool operator==(const Mat&) const; bool operator!=(const Mat&) const; std::string to_string() const noexcept; std::wstring to_wstring() const noexcept; std::u8string to_u8string() const noexcept; ``` // std::formatter specialization provided for char, wchar_t, char8_t ```` --- ## Storage order notes - **Row-major**: `index = row * Columns + column` - **Column-major**: `index = row + column * Rows` Choose one **consistently** across your math types and shader conventions. Mixed orders are supported by the type system but not for cross-multiplying (store types must match). --- ## Transform helpers ### From vectors ```cpp template Mat<1,4,T,St> mat_row_from_vector(const Vector3& v); template Mat<4,1,T,St> mat_column_from_vector(const Vector3& v); ```` ### Translation ```cpp template Mat<4,4,T,St> mat_translation(const Vector3& d) noexcept; ``` ### Axis rotations ```cpp // Angle type must provide angle.cos() and angle.sin() template Mat<4,4,T,St> mat_rotation_axis_x(const Angle& a) noexcept; template Mat<4,4,T,St> mat_rotation_axis_y(const Angle& a) noexcept; template Mat<4,4,T,St> mat_rotation_axis_z(const Angle& a) noexcept; ``` ### Camera/view ```cpp template Mat<4,4,T,St> mat_camera_view(const Vector3& forward, const Vector3& right, const Vector3& up, const Vector3& camera_origin) noexcept; ``` ### Perspective projections ```cpp template Mat<4,4,T,St> mat_perspective_left_handed (float fov_deg, float aspect, float near, float far) noexcept; template Mat<4,4,T,St> mat_perspective_right_handed(float fov_deg, float aspect, float near, float far) noexcept; ``` ### Orthographic projections ```cpp template Mat<4,4,T,St> mat_ortho_left_handed (T left, T right, T bottom, T top, T near, T far) noexcept; template Mat<4,4,T,St> mat_ortho_right_handed(T left, T right, T bottom, T top, T near, T far) noexcept; ``` ### Look-at matrices ```cpp template Mat<4,4,T,St> mat_look_at_left_handed (const Vector3& eye, const Vector3& center, const Vector3& up); template Mat<4,4,T,St> mat_look_at_right_handed(const Vector3& eye, const Vector3& center, const Vector3& up); ``` --- ## Screen-space helper ```cpp template static constexpr Mat<4,4> to_screen_mat(const Type& screen_w, const Type& screen_h) noexcept; // Maps NDC to screen space (origin top-left, y down) ``` --- ## Examples ### 1) Building a left-handed camera and perspective ```cpp using V3 = omath::Vector3; using M4 = omath::Mat<4,4,float, omath::MatStoreType::COLUMN_MAJOR>; V3 eye{0, 1, -5}, center{0, 0, 0}, up{0, 1, 0}; M4 view = omath::mat_look_at_left_handed(eye, center, up); float fov = 60.f, aspect = 16.f/9.f, n = 0.1f, f = 100.f; M4 proj = omath::mat_perspective_left_handed(fov, aspect, n, f); // final VP M4 vp = proj * view; ``` ### 2) Inverting a transform safely ```cpp omath::Mat<4,4> T = omath::mat_translation(omath::Vector3{2,3,4}); if (auto inv = T.inverted()) { // use *inv } else { // handle non-invertible } ``` ### 3) Formatting for logs ```cpp omath::Mat<2,2> A = { {1,2},{3,4} }; std::string s = A.to_string(); // "[[ 1.000, 2.000]\n [ 3.000, 4.000]]" std::string f = std::format("A = {}", A); // uses std::formatter ``` --- ## Performance * **Cache-friendly kernels** per storage order when AVX2 is not enabled. * **AVX2 path** (`OMATH_USE_AVX2`) for `float`/`double` implements FMAs with 256-bit vectors for both row-major and column-major multiplication. * Complexity for `A(R×K) * B(K×C)`: **O(RKC)** regardless of storage order. --- ## Constraints & concepts ```cpp template concept MatTemplateEqual = (M1::rows == M2::rows) && (M1::columns == M2::columns) && std::is_same_v && (M1::store_type == M2::store_type); ``` > Use this concept to constrain generic functions that operate on like-shaped matrices. --- ## Exceptions * `std::invalid_argument` — initializer list dimensions mismatch. * `std::out_of_range` — out-of-bounds in `at()` when bounds checking is active (see source guard). * `inverted()` does **not** throw; returns `std::nullopt` if `determinant() == 0`. --- ## Build switches * **`OMATH_USE_AVX2`** — enable AVX2 vectorized multiplication paths (`` required). * **Debug checks** — the `at()` method contains a conditional range check; refer to the preprocessor guard in the code to enable/disable in your configuration. --- ## Known requirements & interoperability * **C++23** is required for multi-parameter `operator[]`. If you target pre-C++23, use `at(r,c)` instead. * All binary operations require matching `Type` and `StoreType`. Convert explicitly if needed. --- ## See also * `omath::Vector3` * Projection helpers: `mat_perspective_*`, `mat_ortho_*` * View helpers: `mat_look_at_*`, `mat_camera_view` * Construction helpers: `mat_row_from_vector`, `mat_column_from_vector`, `mat_translation`, `mat_rotation_axis_*` --- ## Appendix: API summary (signatures) ```cpp // Core Mat(); Mat(const Mat&); Mat(Mat&&); Mat(std::initializer_list>); explicit Mat(const Type* raw); Mat& operator=(const Mat&); Mat& operator=(Mat&&); static constexpr size_t row_count(); static constexpr size_t columns_count(); static consteval MatSize size(); static constexpr MatStoreType get_store_ordering(); T& at(size_t r, size_t c); T const& at(size_t r, size_t c) const; T& operator[](size_t r, size_t c); T const& operator[](size_t r, size_t c) const; void clear(); void set(const Type& v); Type sum() const noexcept; template Mat operator*(const Mat&) const; Mat& operator*=(const Type&); Mat operator*(const Type&) const; Mat& operator/=(const Type&); Mat operator/(const Type&) const; Mat transposed() const noexcept; Type determinant() const; // square only std::optional inverted() const; // square only Mat strip(size_t r, size_t c) const; Type minor(size_t r, size_t c) const; Type alg_complement(size_t r, size_t c) const; auto& raw_array(); auto const& raw_array() const; std::string to_string() const noexcept; std::wstring to_wstring() const noexcept; std::u8string to_u8string() const noexcept; bool operator==(const Mat&) const; bool operator!=(const Mat&) const; // Helpers (see sections above) ``` --- *Last updated: 31 Oct 2025*