|
Dedekind 0.0.0
A structuralist C++23 Module Library
|
2×2 matrices — as linear maps between 2-tuples (the worked first-class instance; n>2 lives behind the structure-preserving combinators of #368). More...
#include <concepts>#include <cstddef>#include <functional>#include <type_traits>#include <utility>import dedekind.linear_algebra:vec2;import dedekind.sets;import dedekind.order;import dedekind.category;import dedekind.numbers;import dedekind.algebra;
Namespaces | |
| namespace | dedekind::category |
| namespace | dedekind::linear_algebra::detail |
Concepts | |
| concept | dedekind::category::detail_mat2x2::HasRingEntries |
The entries form a ring under the + and × the matrices are computed with: then M₂(T) is a ring (Lang, Algebra, §XIII.1), each law below inherited from it, and not otherwise. | |
Typedefs | |
| template<typename T = int> | |
| using | dedekind::linear_algebra::Identity2x2 = Invertible2x2<T, T{1}, T{0}, T{0}, T{1}> |
| The 2×2 identity matrix over T: [[1, 0], [0, 1]]. | |
| template<typename T = int> | |
| using | dedekind::linear_algebra::Zero2x2 = Matrix2x2<T, T{0}, T{0}, T{0}, T{0}> |
| The 2×2 zero matrix — the additive identity in the ring of matrices. | |
| using | dedekind::linear_algebra::_newb_compositional_pin::Q = dedekind::numbers::Rational<dedekind::numbers::default_integer> |
| using | dedekind::linear_algebra::_newb_compositional_pin::Vec2_Q = dedekind::linear_algebra::Vec2V<Q> |
| using | dedekind::linear_algebra::_newb_compositional_pin::Mat2_Q = dedekind::linear_algebra::Matrix2x2V<Q> |
Functions | |
| template<typename T, T a, T b, T c, T d, T a2, T b2, T c2, T d2> | |
| constexpr auto | dedekind::linear_algebra::operator* (Invertible2x2< T, a, b, c, d >, Matrix2x2< T, a2, b2, c2, d2 >) |
| Mixed composition: Invertible2x2 · Matrix2x2 → Matrix2x2. | |
| template<typename T> requires std::semiregular<T> && dedekind::algebra::HasRingOperators<T> | |
| constexpr Matrix2x2V< T > | dedekind::linear_algebra::inverse (const Matrix2x2V< T > &a, std::plus< Matrix2x2V< T > >) |
The additive inverse, \(-A\) entry by entry: the hook category::inverse_v reads, found by argument-dependent lookup. | |
| template<typename T> | |
| constexpr Vec2V< T > | dedekind::linear_algebra::operator* (const Matrix2x2V< T > &A, const Vec2V< T > &v) |
| Matrix-column-vector product: (2×2) · (2×1) → (2×1). | |
| template<typename T> | |
| constexpr Covec2V< T > | dedekind::linear_algebra::operator* (const Covec2V< T > &v, const Matrix2x2V< T > &A) |
| Row-vector-matrix product: (1×2) · (2×2) → (1×2). | |
| template<typename T> | |
| constexpr Matrix2x2V< T > | dedekind::linear_algebra::operator| (const Vec2V< T > &a, const Vec2V< T > &b) |
| Horizontal concatenation of two column vectors into a 2×2 matrix. | |
| template<typename T> | |
| constexpr Matrix2x2V< T > | dedekind::linear_algebra::operator/ (const Covec2V< T > &a, const Covec2V< T > &b) |
| Vertical concatenation of two row vectors into a 2×2 matrix. | |
Variables | |
| template<typename T> | |
| constexpr Matrix2x2V< T > | dedekind::linear_algebra::identity_matrix2x2_v {T{1}, T{0}, T{0}, T{1}} |
| Value-level identity: [[1, 0], [0, 1]]. | |
| template<typename T> | |
| constexpr Matrix2x2V< T > | dedekind::linear_algebra::zero_matrix2x2_v {T{0}, T{0}, T{0}, T{0}} |
| Value-level zero: [[0, 0], [0, 0]]. | |
| template<detail_mat2x2::HasRingEntries T> | |
| constexpr bool | dedekind::category::is_distributive_v< dedekind::linear_algebra::Matrix2x2V< T >, std::multiplies< dedekind::linear_algebra::Matrix2x2V< T > >, std::plus< dedekind::linear_algebra::Matrix2x2V< T > > > |
| template<typename T> | |
| constexpr bool | dedekind::linear_algebra::is_endomorphism_ring_v< Matrix2x2V< T >, Vec2V< T > > = true |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::nc_a {Rat{0L}, Rat{1L}, Rat{0L}, Rat{0L}} |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::nc_b {Rat{0L}, Rat{0L}, Rat{1L}, Rat{0L}} |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::decomp_probe |
| constexpr Vec2V< Rat > | dedekind::linear_algebra::detail::tr_vec {Rat{7L}, Rat{-3L}} |
| constexpr Covec2V< Rat > | dedekind::linear_algebra::detail::tr_covec {Rat{2L}, Rat{5L}} |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::orth_I = identity_matrix2x2_v<Rat> |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::orth_R90 {Rat{0L}, Rat{-1L}, Rat{1L}, Rat{0L}} |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::orth_Rx {Rat{1L}, Rat{0L}, Rat{0L}, Rat{-1L}} |
| constexpr Matrix2x2V< Rat > | dedekind::linear_algebra::detail::orth_R180 = orth_R90 * orth_R90 |
| constexpr Vec2V< Rat > | dedekind::linear_algebra::detail::col_e1 {Rat{1L}, Rat{0L}} |
| constexpr Vec2V< Rat > | dedekind::linear_algebra::detail::col_e2 {Rat{0L}, Rat{1L}} |
| template<typename T, typename Idx> | |
| constexpr bool | dedekind::category::is_eval_arrow_v< dedekind::linear_algebra::Matrix2x2V< T >, Idx > = true |
| template<typename T, std::integral U, U I> | |
| constexpr bool | dedekind::category::is_eval_arrow_v< dedekind::linear_algebra::Matrix2x2V< T >, std::integral_constant< U, I > > = true |
| constexpr Matrix2x2V< unsigned int > | dedekind::linear_algebra::detail_op::opm {1u, 2u, 3u, 4u} |
2×2 matrices — as linear maps between 2-tuples (the worked first-class instance; n>2 lives behind the structure-preserving combinators of #368).
@partition :mat2x2
Following Stammbach's "Lineare Algebra", matrices are interpreted as linear maps on the 2-vector carriers from :vec2. This partition carries two parallel families:
Tier 0 of issue #366 — the block-Schur invertibility recursion program. This partition establishes the base case that higher tiers compose: Invertible2x2<T, a, b, c, d> is an NTTP-parameterised 2×2 matrix with the full-rank witness a*d - b*c ≠ 0 enforced by static_assert at instantiation, and with inverse_type given by the closed-form Cramer expression (1/det) · [[d, -b], [-c, a]].
The carrier T is expected to be a structural (C++20 NTTP-compatible) type with ring-like arithmetic; the paper-facing existential proof uses Rational<long> (ℚ as a proxy for ℝ per the #364 / #366 narrowing), since exact rational arithmetic sidesteps the rounding / structurality questions that double would raise today.
Vec2<T, x, y> is a structural 2-vector carrying its coordinates as NTTPs. Invertible2x2 carries a left action on Vec2 via operator*(Vec2), which is the compile-time analogue of the linear action GL_2(T) × T² → T² that underlies dedekind.algebra:modules / :action conceptually. Because entries live in the type, each matrix-vector product is a type-level rewrite, observable via static_assert.
using Q = dedekind::numbers::Rational<long>;
// M = [[1, 2], [3, 4]], det = -2
constexpr Invertible2x2<Q, Q{1L}, Q{2L}, Q{3L}, Q{4L}> M{};
static_assert(M * M.inverse() == Identity2x2<Q>{});
Wikipedia: Invertible matrix, Cramer's rule, General linear group, Group action
|
export |
The 2×2 identity matrix over T: [[1, 0], [0, 1]].
Parameter-free reveal tag; mirrors the Ø{} / Singleton<V>{} convention from dedekind.order:halfspace. Callers write static_assert(M * M.inverse() == Identity2x2<T>{}) without having to spell the entries. T defaults to int for simple integer-matrix tests; paper-facing ℚ proofs pass T = Rational<Z> explicitly.
|
constexprexport |
The additive inverse, \(-A\) entry by entry: the hook category::inverse_v reads, found by argument-dependent lookup.
| a | the matrix. |
|
constexprexport |
Matrix-column-vector product: (2×2) · (2×1) → (2×1).
Higher matrix shapes do not fit the unary IsShapedFunctor mould as cleanly as the (1×1, 2×1, 1×2, 2×2) family above:
DirectSum<A, B> and BlockUpperTriangular<A, B, D> are naturally bifunctors / trifunctors Mat × Mat → Mat: block-diagonal / block-UT composition is functorial in each argument separately but not unary. Witnessing them via the unary IsShapedFunctor concept would require either a partial application trick (functor for fixed B / fixed D) or an IsBifunctor extension to the category partition;Matrix2x2V <·> (e.g. IsOrthogonalMatrixCarrier in :contracts), not as separate carrier types. Until #368 introduces dedicated carriers Orthogonal2x2<T>, Rotation2x2<T>, etc., there is no type for a functor to map into;Both directions are real upgrades but require either bifunctor concept work or new concrete carrier types from #368. Tracked separately rather than folded in here.
Matrix2x2V × Vec2V → Vec2V (left action on column vectors, 2×2 · 2×1) and Covec2V × Matrix2x2V → Covec2V (right action on row vectors, 1×2 · 2×2). The inner dimension 2 = column_count(M) = row_count(v) lines up; the outer shape of the result is determined by the outer dimensions. Mismatched shapes would be structurally ill-typed — no overload exists for Matrix2x2V × Covec2V or Vec2V × Matrix2x2V.
|
constexprexport |
Mixed composition: Invertible2x2 · Matrix2x2 → Matrix2x2.
Product of an invertible matrix with a possibly-singular one is in general singular, so the result is typed as Matrix2x2. Defined as a free function since it can't live as an Invertible2x2 member — that member already specialises to Invertible2x2 return type.
|
constexprexport |
Vertical concatenation of two row vectors into a 2×2 matrix.
(a.x, a.y) / (b.x, b.y) = [[a.x, a.y],
[b.x, b.y]]
Inverse of Matrix2x2V::row: (M.row(0) / M.row(1)) == M.
|
constexprexport |
Horizontal concatenation of two column vectors into a 2×2 matrix.
Concatenation is the inverse of decomposition: the column view of a matrix M.column(0) and M.column(1) reassembles to M under |; similarly the row view reassembles under /. This makes the slogan "a matrix is both a horizontal concatenation of its columns and a vertical concatenation of its rows" operationally meaningful — the decomposition and the concatenation are mutual inverses at the value level, witnessed by static_assert below.
Operator_choice
Scalar_→_tuple concatenation is already handled by aggregate initialisation: Vec2V<T>{a, b} and Covec2V<T>{a, b} literally concatenate two scalars into the respective 2×1 / 1×2 tuple.
(a.x, a.y)ᵀ | (b.x, b.y)ᵀ = [[a.x, b.x],
[a.y, b.y]]
Inverse of Matrix2x2V::column: (M.column(0) | M.column(1)) == M.