akreon-linalg
Fixed-size linear algebra and numerical methods in C++26.
Loading...
Searching...
No Matches
linalg_util.hpp
Go to the documentation of this file.
1/*
2 * Copyright © 2025-2026 Akreon LLC
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6#pragma once
7
14
15namespace linalg {
16
24template <std::size_t Start, std::size_t End, VectorContainer Vec>
26constexpr auto get_elements(const Vec& x) {
27 using T = vector_element_t<Vec>;
28 Vector<T, End - Start> result;
29 for (std::size_t i = Start, idx = 0; i < End; ++i, ++idx) result(idx) = x(i);
30 return result;
31}
32
38template <Field T, std::size_t N>
41 for (std::size_t i = 0; i < N; ++i) I(i, i) = T(1);
42 return I;
43}
44
50template <Field T, std::size_t Rows, std::size_t Cols>
53 for (std::size_t i = 0; i < Rows; ++i)
54 for (std::size_t j = 0; j < Cols; ++j) Z(i, j) = T(0);
55 return Z;
56}
57
65template <VectorContainer Vec>
66constexpr auto as_col_vector(const Vec& X) {
67 using T = vector_element_t<Vec>;
68 constexpr auto N = vector_dim_v<Vec>;
70 for (std::size_t i = 0; i < N; ++i) A(i, 0) = X(i);
71 return A;
72}
73
81template <VectorContainer Vec>
82constexpr auto as_row_vector(const Vec& X) {
83 using T = vector_element_t<Vec>;
84 constexpr auto N = vector_dim_v<Vec>;
86 for (std::size_t i = 0; i < N; ++i) A(0, i) = X(i);
87 return A;
88}
89
97template <MatrixContainer Mat>
98constexpr auto as_complex_matrix(const Mat& A) {
99 using T = matrix_scalar_t<Mat>;
100 constexpr auto Rows = mat_rows_v<Mat>;
101 constexpr auto Cols = mat_cols_v<Mat>;
103 if constexpr (Real<T>) {
104 for (std::size_t i = 0; i < Rows; ++i)
105 for (std::size_t j = 0; j < Cols; ++j)
106 result(i, j) = std::complex<T>(A(i, j));
107 } else {
108 result = A;
109 }
110 return result;
111}
112
120template <Field T, std::size_t N>
121constexpr auto as_vector(const ColVector<T, N>& A) {
123 for (std::size_t i = 0; i < N; ++i) res(i) = A(i, 0);
124 return res;
125}
126
134template <Field T, std::size_t N>
135constexpr auto as_vector(const RowVector<T, N>& A) {
137 for (std::size_t i = 0; i < N; ++i) res(i) = A(0, i);
138 return res;
139}
140
149template <MatrixContainer Mat>
150constexpr auto get_col(const Mat& A, std::size_t idx) {
151 using T = matrix_scalar_t<Mat>;
152 constexpr auto Rows = mat_rows_v<Mat>;
153 AK_ASSERT(idx < mat_cols_v<Mat> && "get_col index out of bounds");
155 for (std::size_t i = 0; i < Rows; ++i) X(i) = A(i, idx);
156 return X;
157}
158
167template <MatrixContainer Mat>
168constexpr auto get_row(const Mat& A, std::size_t idx) {
169 AK_ASSERT(idx < mat_rows_v<Mat> && "get_row index out of bounds");
170 return A.row(idx);
171}
172
180template <MatrixContainer Mat>
181constexpr auto get_diag(const Mat& A) {
182 using T = matrix_scalar_t<Mat>;
183 constexpr auto Rows = mat_rows_v<Mat>;
184 constexpr auto Cols = mat_cols_v<Mat>;
185 constexpr std::size_t mn = std::min(Rows, Cols);
187 for (std::size_t i = 0; i < mn; ++i) diag(i) = A(i, i);
188 return diag;
189}
190
198template <Field T, std::size_t N>
199constexpr auto make_diag(const Vector<T, N>& X) {
201 for (std::size_t i = 0; i < N; ++i) diag(i, i) = X(i);
202 return diag;
203}
204
212template <std::size_t Start, std::size_t End, MatrixContainer Mat>
214constexpr auto get_n_rows(const Mat& A) {
215 using T = matrix_scalar_t<Mat>;
216 constexpr auto Cols = mat_cols_v<Mat>;
217 Matrix<T, End - Start, Cols> result;
218 for (std::size_t i = Start, idx = 0; i < End; ++i, ++idx)
219 for (std::size_t col = 0; col < Cols; ++col) result(idx, col) = A(i, col);
220 return result;
221}
222
230template <std::size_t Start, std::size_t End, MatrixContainer Mat>
232constexpr auto get_n_cols(const Mat& A) {
233 using T = matrix_scalar_t<Mat>;
234 constexpr auto Rows = mat_rows_v<Mat>;
235 Matrix<T, Rows, End - Start> result;
236 for (std::size_t col = Start, idx = 0; col < End; ++col, ++idx)
237 for (std::size_t row = 0; row < Rows; ++row) result(row, idx) = A(row, col);
238 return result;
239}
240
251template <std::size_t StartRow, std::size_t EndRow, std::size_t StartCol,
252 std::size_t EndCol, MatrixContainer Mat>
255constexpr auto get_block(const Mat& A) {
256 using T = matrix_scalar_t<Mat>;
258 for (std::size_t i = StartRow, a = 0; i < EndRow; ++i, ++a)
259 for (std::size_t j = StartCol, b = 0; j < EndCol; ++j, ++b)
260 result(a, b) = A(i, j);
261 return result;
262}
263
275template <std::size_t StartRow, std::size_t EndRow, std::size_t StartCol,
276 std::size_t EndCol, MatrixContainer Mat>
279constexpr auto set_block(Mat A,
281 EndCol - StartCol>& B) {
282 for (std::size_t i = StartRow, a = 0; i < EndRow; ++i, ++a)
283 for (std::size_t j = StartCol, b = 0; j < EndCol; ++j, ++b)
284 A(i, j) = B(a, b);
285 return A;
286}
287
295template <MatrixContainer Mat>
296constexpr auto get_upper_right_triangular_matrix(const Mat& A) {
297 constexpr auto Rows = mat_rows_v<Mat>;
298 constexpr auto Cols = mat_cols_v<Mat>;
299 Mat R;
300 for (std::size_t i = 0; i < Rows; ++i)
301 for (std::size_t j = i; j < Cols; ++j) R(i, j) = A(i, j);
302 return R;
303}
304
312template <MatrixContainer Mat>
313constexpr auto get_lower_left_triangular_matrix(const Mat& A) {
314 constexpr auto Rows = mat_rows_v<Mat>;
315 constexpr auto Cols = mat_cols_v<Mat>;
316 Mat L;
317 for (std::size_t i = 0; i < Cols; ++i)
318 for (std::size_t j = i; j < Rows; ++j) L(j, i) = A(j, i);
319 return L;
320}
321
330template <VectorContainer Vec>
331constexpr auto euclidean_distance(const Vec& X, const Vec& Y) {
332 return L2<Vec>()(X - Y);
333}
334
343template <VectorContainer Vec>
344constexpr auto manhattan_distance(const Vec& X, const Vec& Y) {
345 return L1<Vec>()(X - Y);
346}
347
357template <FieldVector Vec>
358constexpr bool all_equal(const Vec& X, const Vec& Y,
360 return euclidean_distance(X, Y) <= tol;
361}
362
372template <Field T, std::size_t Rows, std::size_t Cols>
373constexpr bool all_equal(const Matrix<T, Rows, Cols>& A,
375 real_type_t<T> tol = 1e-10) {
376 bool rv = true;
377 for (std::size_t i = 0; i < Rows; ++i)
378 rv &= all_equal(A.row(i), B.row(i), tol);
379 return rv;
380}
381
391template <MatrixContainer MatA, MatrixContainer MatB>
392 requires(std::same_as<matrix_scalar_t<MatA>, matrix_scalar_t<MatB>> &&
395constexpr bool rows_equal_cols(const MatA& A, const MatB& B) {
396 constexpr auto Rows = mat_rows_v<MatA>;
397 bool rv = true;
398 for (std::size_t i = 0; i < Rows; ++i)
399 rv &= euclidean_distance(A.row(i), get_col(B, i)) <= 1e-10;
400 return rv;
401}
402
410template <std::size_t N, FieldVector Vec>
411 requires(vector_dim_v<Vec> == N * (N + 1) / 2)
413 using T = vector_element_t<Vec>;
414 Matrix<T, N, N> S{};
415 for (std::size_t i = 0; i < N; ++i) {
416 for (std::size_t j = 0; j <= i; ++j) {
417 const auto idx = i * (i + 1) / 2 + j;
418 S(i, j) = L(idx);
419 if (i != j) S(i, j) /= linalg::sqrt2_v<T>;
420 }
421 }
422 const auto S_T = transpose(S);
424 for (std::size_t i = 0; i < N; ++i) {
425 for (std::size_t j = 0; j < N; ++j) {
426 if (i >= j) res(i, j) = S(i, j);
427 else res(i, j) = S_T(i, j);
428 }
429 }
430 return res;
431}
432
445template <SquareMatrix Mat>
446constexpr auto get_lower_triangle_with_diag(const Mat& A) {
447 using T = matrix_scalar_t<Mat>;
448 static constexpr std::size_t N = mat_rows_v<Mat>;
449 static constexpr std::size_t K = N * (N + 1) / 2;
451 for (std::size_t i = 0, k = 0; i < N; ++i)
452 for (std::size_t j = 0; j <= i; ++j, ++k) vec(k) = A(i, j);
453 return vec;
454}
455
466template <SquareMatrix Mat>
467constexpr auto get_svec(const Mat& A) {
468 using T = matrix_scalar_t<Mat>;
469 static constexpr std::size_t N = mat_rows_v<Mat>;
470 static constexpr std::size_t K = N * (N + 1) / 2;
472 for (std::size_t i = 0, k = 0; i < N; ++i) {
473 for (std::size_t j = 0; j <= i; ++j, ++k) {
474 vec(k) = A(i, j);
475 if (i != j) vec(k) *= sqrt2_v<T>;
476 }
477 }
478 return vec;
479}
480
486template <SquareMatrix Mat>
487constexpr auto make_svec(const Mat& A) {
488 return get_svec(A);
489}
490
500template <SquareMatrix Mat>
501constexpr auto symmetric_part(const Mat& A) {
502 using T = matrix_scalar_t<Mat>;
503 return T(0.5) * (A + transpose(A));
504}
505
518template <SquareMatrix Mat>
519constexpr auto get_lower_triangle(const Mat& A) {
520 using T = matrix_scalar_t<Mat>;
521 static constexpr std::size_t N = mat_rows_v<Mat>;
522 static constexpr std::size_t K = N * (N + 1) / 2 - N;
524 for (std::size_t i = 0, k = 0; i < N; ++i)
525 for (std::size_t j = 0; j < i; ++j, ++k) vec(k) = A(i, j);
526 return vec;
527}
528
539template <SquareMatrix Mat, VectorContainer Vec>
540 requires(std::same_as<matrix_scalar_t<Mat>, vector_element_t<Vec>>)
541constexpr auto make_unit_lower_triangle(const Vec& x) {
542 using T = matrix_scalar_t<Mat>;
543 static constexpr std::size_t N = mat_rows_v<Mat>;
544 static_assert(N * (N + 1) / 2 - N == vector_dim_v<Vec>,
545 "Invalid vector size to make lower triangle of square matrix");
546 Mat L{};
547 for (std::size_t i = 0, k = 0; i < N; ++i) {
548 std::size_t j = 0;
549 for (; j < i; ++j, ++k) L(i, j) = x(k);
550 if (i == j) L(i, j) = T(1);
551 }
552
553 return L;
554}
555
566template <SquareMatrix Mat, VectorContainer Vec>
567 requires(std::same_as<matrix_scalar_t<Mat>, vector_element_t<Vec>>)
568constexpr auto make_lower_triangle(const Vec& x) {
569 constexpr std::size_t N = mat_rows_v<Mat>;
570 static_assert(N * (N + 1) / 2 == vector_dim_v<Vec>,
571 "Invalid vector size to make lower triangle of square matrix");
572
573 Mat L{};
574 for (std::size_t i = 0, k = 0; i < N; ++i)
575 for (std::size_t j = 0; j < i + 1; ++j, ++k) L(i, j) = x(k);
576
577 return L;
578}
579
580} // namespace linalg
#define AK_ASSERT(x)
Definition assert.hpp:13
Field classified by scalar_traits as real.
constexpr auto get_svec(const Mat &A)
get svec encoding of a symmetric matrix
constexpr auto get_diag(const Mat &A)
get the diagonal of a matrix A
constexpr auto symmetric_part(const Mat &A)
symmetric part of a square matrix
constexpr auto make_unit_lower_triangle(const Vec &x)
Construct a unit lower-triangular matrix from strict-lower entries.
typename vector_traits_t< Vec >::element_type vector_element_t
Registered vector coordinate type.
typename scalar_traits_t< T >::real_type real_type_t
Associated real component type registered for T.
constexpr auto get_lower_triangle(const Mat &A)
get lower triangle
constexpr auto get_row(const Mat &A, std::size_t idx)
get the row of matrix A based on given index
constexpr auto as_row_vector(const Vec &X)
express the vector X as a row vector (1 x N)
constexpr auto as_complex_matrix(const Mat &A)
express matrix as complex one
constexpr auto as_vector(const ColVector< T, N > &A)
express col vector as vector
constexpr auto make_diag(const Vector< T, N > &X)
make a diagonal matrix from a vector
constexpr Matrix< T, N, N > make_identity()
create an identity matrix of size N type T
constexpr auto make_smat(const Vec &L)
make symmetric matrix
constexpr auto get_lower_left_triangular_matrix(const Mat &A)
get lower left triangular matrix from A
constexpr auto transpose(const Vec &x)
tranpose of a vector
constexpr auto get_lower_triangle_with_diag(const Mat &A)
get lower triangle with diag
constexpr auto get_n_rows(const Mat &A)
Copy the half-open matrix row range [Start, End).
constexpr bool rows_equal_cols(const MatA &A, const MatB &B)
checks if the row space of one matrix is equivalent to the column space of another matrix
constexpr auto make_svec(const Mat &A)
Compatibility spelling for get_svec(A).
constexpr Matrix< T, Rows, Cols > make_zeros()
create a matrix filled with zeros of size Rows x Cols of type T
constexpr auto get_block(const Mat &A)
Copy a compile-time rectangular matrix block.
constexpr std::size_t mat_rows_v
Registered compile-time row count after cv/ref normalization.
constexpr auto get_elements(const Vec &x)
Copy the half-open vector slice [Start, End).
constexpr auto manhattan_distance(const Vec &X, const Vec &Y)
Compute the manhattan distance between two vectors (L1 norm of delta)
constexpr auto make_lower_triangle(const Vec &x)
Construct a lower-triangular matrix including its diagonal.
constexpr auto get_col(const Mat &A, std::size_t idx)
get the column of matrix A based on given index
constexpr bool all_equal(const Vec &X, const Vec &Y, real_type_t< vector_element_t< Vec > > tol=1e-10)
checks if two vectors are equivalent to a given tolerance (different than == operator on vector which...
constexpr auto set_block(Mat A, const Matrix< matrix_scalar_t< Mat >, EndRow - StartRow, EndCol - StartCol > &B)
Return a matrix copy with one compile-time block replaced.
constexpr auto euclidean_distance(const Vec &X, const Vec &Y)
Compute the euclidean distance between two vectors (L2 norm of delta)
constexpr auto get_n_cols(const Mat &A)
Copy the half-open matrix column range [Start, End).
typename mat_traits< remove_cvref_t< Mat > >::value_type matrix_scalar_t
Registered matrix scalar type after cv/ref normalization.
constexpr auto as_col_vector(const Vec &X)
express the vector X as a column vector (N x 1)
constexpr auto get_upper_right_triangular_matrix(const Mat &A)
get upper right triangular matrix from A
Owning, fixed-size, row-major matrix container over a scalar field.
Definition matrix.hpp:44
Owning, fixed-size vector container.
Definition vector.hpp:36