CorrSolver 1.2.7; VERSION ${PROJECT_VERSION}
Loading...
Searching...
No Matches
linalg.hpp
Go to the documentation of this file.
1
5#pragma once
6
9
10#include <ellalgo/arr.hpp>
11#include <random>
12
13// ---------------------------------------------------------------------------
14// Matrix helpers
15// ---------------------------------------------------------------------------
16
27inline Arr transpose(const Arr& a) {
28 assert(a.is_2d());
29 Arr out(a.cols(), a.rows());
30 for (size_t i = 0; i < a.rows(); ++i)
31 for (size_t j = 0; j < a.cols(); ++j) out(j, i) = a(i, j);
32 return out;
33}
34
40inline Arr flatten(const Arr& a) {
41 Arr out(a.size());
42 for (size_t i = 0; i < a.size(); ++i) out(i) = a(i);
43 return out;
44}
45
51inline Arr diagonal(const Arr& a) {
52 assert(a.is_2d() && a.rows() == a.cols());
53 auto n = a.rows();
54 Arr out(n);
55 for (size_t i = 0; i < n; ++i) out(i) = a(i, i);
56 return out;
57}
58
67inline double trace(const Arr& a) { return sum(diagonal(a)); }
68
77inline double norm(const Arr& a) { return std::sqrt(sum(a * a)); }
78
79// ---------------------------------------------------------------------------
80// Matrix-matrix multiplication: A * B (A: m×k, B: k×n → result: m×n)
81// ---------------------------------------------------------------------------
82
107inline Arr matmul(const Arr& A, const Arr& B) {
108 assert(A.is_2d() && B.is_2d() && A.cols() == B.rows());
109 auto m = A.rows();
110 auto k = A.cols();
111 auto n = B.cols();
112 Arr out(m, n);
113 for (size_t i = 0; i < m; ++i)
114 for (size_t j = 0; j < n; ++j) {
115 double s = 0.0;
116 for (size_t t = 0; t < k; ++t) s += A(i, t) * B(t, j);
117 out(i, j) = s;
118 }
119 return out;
120}
121
122// ---------------------------------------------------------------------------
123// Cholesky decomposition: A = L * L^T (A symmetric positive definite)
124// Returns lower-triangular L.
125// ---------------------------------------------------------------------------
126
153inline Arr cholesky(const Arr& A) {
154 auto n = A.rows();
155 assert(A.is_2d() && A.cols() == n);
156 Arr L(n, n);
157 for (size_t j = 0; j < n; ++j) {
158 double s = 0.0;
159 for (size_t k = 0; k < j; ++k) s += L(j, k) * L(j, k);
160 L(j, j) = std::sqrt(A(j, j) - s);
161 for (size_t i = j + 1; i < n; ++i) {
162 s = 0.0;
163 for (size_t k = 0; k < j; ++k) s += L(i, k) * L(j, k);
164 L(i, j) = (A(i, j) - s) / L(j, j);
165 }
166 }
167 return L;
168}
169
170// ---------------------------------------------------------------------------
171// Matrix inverse via Cholesky (for SPD matrices).
172// ---------------------------------------------------------------------------
173
196inline Arr inv(const Arr& A) {
197 auto n = A.rows();
198 auto L = cholesky(A);
199 // Solve L * Y = I (forward substitution)
200 Arr Y(n, n);
201 for (size_t j = 0; j < n; ++j) {
202 for (size_t i = 0; i < n; ++i) {
203 double s = (i == j) ? 1.0 : 0.0;
204 for (size_t k = 0; k < i; ++k) s -= L(i, k) * Y(k, j);
205 Y(i, j) = s / L(i, i);
206 }
207 }
208 // Solve L^T * X = Y (back substitution)
209 Arr X(n, n);
210 for (size_t j = 0; j < n; ++j) {
211 for (size_t i = n; i-- > 0;) {
212 double s = Y(i, j);
213 for (size_t k = i + 1; k < n; ++k) s -= L(k, i) * X(k, j);
214 X(i, j) = s / L(i, i);
215 }
216 }
217 return X;
218}
219
220// ---------------------------------------------------------------------------
221// Random number generation
222// ---------------------------------------------------------------------------
223
228inline std::mt19937_64& global_rng() {
229 static std::mt19937_64 rng(std::random_device{}());
230 return rng;
231}
232
237inline void random_seed(unsigned seed) { global_rng().seed(seed); }
238
244inline Arr randn(size_t n) {
245 auto& rng = global_rng();
246 std::normal_distribution<double> dist(0.0, 1.0);
247 Arr out(n);
248 for (size_t i = 0; i < n; ++i) out(i) = dist(rng);
249 return out;
250}
251
252// ---------------------------------------------------------------------------
253// meshgrid: returns {XX, YY} where XX and YY are 2D grids
254// ---------------------------------------------------------------------------
255
262inline std::pair<Arr, Arr> meshgrid(const Arr& x, const Arr& y) {
263 auto nx = x.size();
264 auto ny = y.size();
265 Arr xx(ny, nx);
266 Arr yy(ny, nx);
267 for (size_t i = 0; i < ny; ++i) {
268 for (size_t j = 0; j < nx; ++j) {
269 xx(i, j) = x(j);
270 yy(i, j) = y(i);
271 }
272 }
273 return {xx, yy};
274}
275
276// ---------------------------------------------------------------------------
277// stack: combines multiple 1D arrays as rows (axis=0) into a 2D matrix
278// ---------------------------------------------------------------------------
279
286inline Arr stack(const Arr& a, const Arr& b, int /*unused*/ = 0) {
287 assert(!a.is_2d() && !b.is_2d() && a.size() == b.size());
288 Arr out(2, a.size());
289 for (size_t j = 0; j < a.size(); ++j) {
290 out(0, j) = a(j);
291 out(1, j) = b(j);
292 }
293 return out;
294}
void random_seed(unsigned seed)
Seed the global random number generator.
Definition linalg.hpp:237
double norm(const Arr &a)
Compute the Frobenius norm of an array.
Definition linalg.hpp:77
double trace(const Arr &a)
Compute the trace of a square matrix (sum of diagonal elements).
Definition linalg.hpp:67
Arr flatten(const Arr &a)
Flatten a matrix or vector into a 1D array.
Definition linalg.hpp:40
Arr diagonal(const Arr &a)
Extract the diagonal of a square matrix.
Definition linalg.hpp:51
Arr cholesky(const Arr &A)
Cholesky decomposition: A = L * L^T for SPD matrices.
Definition linalg.hpp:153
std::pair< Arr, Arr > meshgrid(const Arr &x, const Arr &y)
Create 2D meshgrid arrays from 1D coordinate vectors.
Definition linalg.hpp:262
Arr matmul(const Arr &A, const Arr &B)
Multiply two matrices: A * B.
Definition linalg.hpp:107
Arr inv(const Arr &A)
Compute the inverse of a symmetric positive definite matrix via Cholesky.
Definition linalg.hpp:196
Arr transpose(const Arr &a)
Transpose a 2D matrix.
Definition linalg.hpp:27
std::mt19937_64 & global_rng()
Get the global Mersenne Twister random number generator.
Definition linalg.hpp:228
Arr randn(size_t n)
Generate a vector of standard normal random numbers.
Definition linalg.hpp:244
Arr stack(const Arr &a, const Arr &b, int=0)
Stack two 1D arrays as rows into a 2D matrix.
Definition linalg.hpp:286