numerics
Loading...
Searching...
No Matches
expv.cpp
Go to the documentation of this file.
1/// @file expv.cpp
2/// @brief Implementation of Krylov-Padé matrix exponential-vector product
4#include "core/matrix.hpp"
6#include "core/vector.hpp"
7#include <cmath>
8#include <algorithm>
9#include <vector>
10
11namespace num {
12
13/// @brief Dense matrix exponential via scaling+squaring + Padé [6/6]
14///
15/// Padé [6/6] numerator/denominator coefficients:
16/// c[0]=1, c[1]=1/2, c[2]=5/44, c[3]=1/66,
17/// c[4]=1/792, c[5]=1/15840, c[6]=1/665280
18static Matrix dense_expm(const Matrix& A) {
19 const idx m = A.rows();
20
21 // Padé [6/6] coefficients
22 static constexpr double c[7] = {
23 1.0,
24 0.5,
25 5.0 / 44.0,
26 1.0 / 66.0,
27 1.0 / 792.0,
28 1.0 / 15840.0,
29 1.0 / 665280.0
30 };
31
32 // 1. Compute inf-norm (max absolute row sum)
33 double norm_inf = 0.0;
34 for (idx i = 0; i < m; i++) {
35 double row_sum = 0.0;
36 for (idx j = 0; j < m; j++) row_sum += std::abs(A(i, j));
37 norm_inf = std::max(norm_inf, row_sum);
38 }
39
40 // 2. Scaling: s = max(0, ceil(log2(norm_inf / 0.5)))
41 int s = 0;
42 if (norm_inf > 0.5) {
43 s = (int)std::max(0.0, std::ceil(std::log2(norm_inf / 0.5)));
44 }
45
46 // 3. As = A / 2^s
47 double scale = std::ldexp(1.0, -s); // 1/2^s
48 Matrix As(m, m, 0.0);
49 for (idx i = 0; i < m; i++)
50 for (idx j = 0; j < m; j++)
51 As(i, j) = A(i, j) * scale;
52
53 // 4. Build powers: B = As^2, B2 = As^4, B3 = As^6
54 Matrix B(m, m, 0.0);
55 matmul(As, As, B); // B = As^2
56
57 Matrix B2(m, m, 0.0);
58 matmul(B, B, B2); // B2 = As^4
59
60 Matrix B3(m, m, 0.0);
61 matmul(B2, B, B3); // B3 = As^6
62
63 // 5. V_mat = c[6]*B3 + c[4]*B2 + c[2]*B + c[0]*I (even terms)
64 Matrix V_mat(m, m, 0.0);
65 for (idx i = 0; i < m; i++) {
66 for (idx j = 0; j < m; j++) {
67 V_mat(i, j) = c[6] * B3(i, j) + c[4] * B2(i, j) + c[2] * B(i, j);
68 }
69 V_mat(i, i) += c[0];
70 }
71
72 // 6. W = c[5]*B2 + c[3]*B + c[1]*I (inner odd terms, without As factor)
73 Matrix W(m, m, 0.0);
74 for (idx i = 0; i < m; i++) {
75 for (idx j = 0; j < m; j++) {
76 W(i, j) = c[5] * B2(i, j) + c[3] * B(i, j);
77 }
78 W(i, i) += c[1];
79 }
80
81 // 7. U = As * W (full odd numerator terms)
82 Matrix U(m, m, 0.0);
83 matmul(As, W, U);
84
85 // 8. VpU = V_mat + U, VmU = V_mat - U
86 Matrix VpU(m, m, 0.0);
87 Matrix VmU(m, m, 0.0);
88 for (idx i = 0; i < m; i++) {
89 for (idx j = 0; j < m; j++) {
90 VpU(i, j) = V_mat(i, j) + U(i, j);
91 VmU(i, j) = V_mat(i, j) - U(i, j);
92 }
93 }
94
95 // 9. Solve VmU * E = VpU (Padé approximant: E = (V-U)^{-1}*(V+U))
96 LUResult fac = lu(VmU);
97 Matrix E(m, m, 0.0);
98 lu_solve(fac, VpU, E);
99
100 // 10. Squaring: E = E^(2^s)
101 for (int i = 0; i < s; i++) {
102 Matrix E2(m, m, 0.0);
103 matmul(E, E, E2);
104 E = std::move(E2);
105 }
106
107 return E;
108}
109
110Vector expv(real t, const MatVecFn& matvec, idx n, const Vector& v,
111 int m_max, real tol)
112{
113 // Handle zero vector
114 real beta = norm(v);
115 if (beta < 1e-300) {
116 return Vector(n, 0.0);
117 }
118
119 // Krylov basis vectors: V[0..m_max]
120 std::vector<Vector> V;
121 V.reserve(m_max + 1);
122
123 // V[0] = v / beta
124 Vector v0(n);
125 for (idx i = 0; i < n; i++) v0[i] = v[i] / beta;
126 V.push_back(std::move(v0));
127
128 // Upper Hessenberg matrix H: (m_max+1) x m_max
129 Matrix H(m_max + 1, m_max, 0.0);
130
131 int m_actual = m_max;
132
133 // Arnoldi process
134 for (int j = 0; j < m_max; j++) {
135 // w = A * V[j]
136 Vector w(n, 0.0);
137 matvec(V[j], w);
138
139 // Modified Gram-Schmidt orthogonalization
140 for (int i = 0; i <= j; i++) {
141 real h = dot(V[i], w);
142 H(i, j) = h;
143 axpy(-h, V[i], w); // w -= h * V[i]
144 }
145
146 real h_next = norm(w);
147 H(j + 1, j) = h_next;
148
149 // Check for lucky breakdown
150 if (h_next < tol) {
151 m_actual = j + 1;
152 break;
153 }
154
155 // Normalize and store next Krylov vector
156 Vector vj1(n);
157 for (idx i = 0; i < n; i++) vj1[i] = w[i] / h_next;
158 V.push_back(std::move(vj1));
159 }
160
161 // Extract H_m = t * H[0..m_actual-1, 0..m_actual-1]
162 Matrix Hm(m_actual, m_actual, 0.0);
163 for (int i = 0; i < m_actual; i++)
164 for (int j = 0; j < m_actual; j++)
165 Hm(i, j) = t * H(i, j);
166
167 // Compute dense expm of Hm
168 Matrix E = dense_expm(Hm);
169
170 // result = sum_j (beta * E[j,0]) * V[j]
171 Vector result(n, 0.0);
172 for (int j = 0; j < m_actual; j++) {
173 real coeff = beta * E(j, 0);
174 axpy(coeff, V[j], result);
175 }
176
177 return result;
178}
179
180Vector expv(real t, const SparseMatrix& A, const Vector& v,
181 int m_max, real tol)
182{
183 MatVecFn fn = [&A](const Vector& x, Vector& y) {
184 sparse_matvec(A, x, y);
185 };
186 return expv(t, fn, A.n_rows(), v, m_max, tol);
187}
188
189} // namespace num
Dense row-major matrix with optional GPU storage.
Definition matrix.hpp:12
constexpr idx rows() const noexcept
Definition matrix.hpp:24
Sparse matrix in Compressed Sparse Row (CSR) format.
Definition sparse.hpp:15
Krylov subspace matrix exponential-vector product: compute exp(t*A)*v.
LU factorization with partial pivoting.
Matrix operations.
double real
Definition types.hpp:10
LUResult lu(const Matrix &A)
LU factorization of a square matrix A with partial pivoting.
Definition lu.cpp:21
real beta(real a, real b)
B(a, b) – beta function.
Definition math.hpp:242
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
std::size_t idx
Definition types.hpp:11
void matvec(const Matrix &A, const Vector &x, Vector &y, Backend b=default_backend)
y = A * x
Definition matrix.cpp:94
void scale(Vector &v, real alpha, Backend b=default_backend)
v *= alpha
Definition vector.cpp:27
void sparse_matvec(const SparseMatrix &A, const Vector &x, Vector &y)
y = A * x
Definition sparse.cpp:110
real dot(const Vector &x, const Vector &y, Backend b=default_backend)
dot product
Definition vector.cpp:57
constexpr real e
Definition math.hpp:41
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:122
real norm(const Vector &x, Backend b=default_backend)
Euclidean norm.
Definition vector.cpp:69
void axpy(real alpha, const Vector &x, Vector &y, Backend b=default_backend)
y += alpha * x
Definition vector.cpp:46
void matmul(const Matrix &A, const Matrix &B, Matrix &C, Backend b=default_backend)
C = A * B.
Definition matrix.cpp:83
Vector expv(real t, const MatVecFn &matvec, idx n, const Vector &v, int m_max=30, real tol=1e-8)
Compute exp(t*A)*v via Krylov-Padé approximation (matrix-free)
Definition expv.cpp:110
void lu_solve(const LUResult &f, const Vector &b, Vector &x)
Solve A*x = b using a precomputed LU factorization.
Definition lu.cpp:67
std::function< void(const Vector &, Vector &)> MatVecFn
Callable type for matrix-free matvec: computes y = A*x.
Definition cg.hpp:13
Vector operations.