OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
GSLLinalg.h
Go to the documentation of this file.
1//
2// GSL Linear Algebra compatibility to replace gsl_linalg
3//
4// Copyright (c) 2023, Paul Scherrer Institute, Villigen PSI, Switzerland
5// All rights reserved
6//
7// This file is part of OPAL.
8//
9// OPAL is free software: you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation, either version 3 of the License, or
12// (at your option) any later version.
13//
14// You should have received a copy of the GNU General License
15// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
16//
17
18#ifndef OPAL_GSL_LINALG_HH
19#define OPAL_GSL_LINALG_HH
20
21#include <algorithm>
22#include <cmath>
23#include <vector>
25#include "Utilities/GSLMatrix.h"
26
31 size_t size;
32 size_t* data;
33
34 gsl_permutation() : size(0), data(nullptr) {}
35};
36
42 p->size = n;
43 p->data = new size_t[n];
44 for (size_t i = 0; i < n; ++i) {
45 p->data[i] = i;
46 }
47 return p;
48}
49
53 if (p) {
54 delete[] p->data;
55 delete p;
56 }
57}
58
66inline int gsl_linalg_LU_decomp(gsl_matrix* A, gsl_permutation* p, int* signum) {
67 if (A->size1 != A->size2) {
68 return -1; // Error: not square
69 }
70
71 size_t n = A->size1;
72 *signum = 1;
73
74 // Initialize permutation
75 for (size_t i = 0; i < n; ++i) {
76 p->data[i] = i;
77 }
78
79 // Perform LU decomposition with partial pivoting
80 for (size_t k = 0; k < n - 1; ++k) {
81 // Find pivot
82 size_t max_row = k;
83 double max_val = std::abs(*gsl_matrix_ptr(A, k, k));
84 for (size_t i = k + 1; i < n; ++i) {
85 double val = std::abs(*gsl_matrix_ptr(A, i, k));
86 if (val > max_val) {
87 max_val = val;
88 max_row = i;
89 }
90 }
91
92 // Swap rows if needed
93 if (max_row != k) {
94 *signum = -*signum;
95 std::swap(p->data[k], p->data[max_row]);
96 for (size_t j = 0; j < n; ++j) {
97 std::swap(*gsl_matrix_ptr(A, k, j), *gsl_matrix_ptr(A, max_row, j));
98 }
99 }
100
101 // Check for singularity
102 if (std::abs(*gsl_matrix_ptr(A, k, k)) < 1e-15) {
103 return -1; // Singular matrix
104 }
105
106 // Eliminate
107 for (size_t i = k + 1; i < n; ++i) {
108 double factor = *gsl_matrix_ptr(A, i, k) / *gsl_matrix_ptr(A, k, k);
109 *gsl_matrix_ptr(A, i, k) = factor;
110 for (size_t j = k + 1; j < n; ++j) {
111 *gsl_matrix_ptr(A, i, j) -= factor * *gsl_matrix_ptr(A, k, j);
112 }
113 }
114 }
115
116 return 0; // Success
117}
118
124inline double gsl_linalg_LU_det(const gsl_matrix* LU, int signum) {
125 size_t n = LU->size1;
126 double det = static_cast<double>(signum);
127 for (size_t i = 0; i < n; ++i) {
128 det *= *gsl_matrix_ptr(LU, i, i);
129 }
130 return det;
131}
132
140 const gsl_matrix* LU, const gsl_permutation* p, gsl_matrix* inverse) {
141 size_t n = LU->size1;
142 if (inverse->size1 != n || inverse->size2 != n) {
143 return -1;
144 }
145
146 // Initialize inverse as permuted identity: P*I
147 for (size_t j = 0; j < n; ++j) {
148 for (size_t i = 0; i < n; ++i) {
149 *gsl_matrix_ptr(inverse, i, j) = (p->data[i] == j) ? 1.0 : 0.0;
150 }
151 }
152
153 // Forward substitution: L*y = P*I (solve for y)
154 // L is unit lower triangular stored in LU below diagonal
155 for (size_t j = 0; j < n; ++j) {
156 for (size_t i = 0; i < n; ++i) {
157 double sum = 0.0;
158 for (size_t k = 0; k < i; ++k) {
159 sum += *gsl_matrix_ptr(LU, i, k) * *gsl_matrix_ptr(inverse, k, j);
160 }
161 *gsl_matrix_ptr(inverse, i, j) -= sum;
162 }
163 }
164
165 // Back substitution: U*x = y (solve for x, which is the inverse)
166 // U is upper triangular stored in LU on and above diagonal
167 for (int i = static_cast<int>(n) - 1; i >= 0; --i) {
168 for (size_t j = 0; j < n; ++j) {
169 double sum = 0.0;
170 for (size_t k = i + 1; k < n; ++k) {
171 sum += *gsl_matrix_ptr(LU, i, k) * *gsl_matrix_ptr(inverse, k, j);
172 }
173 *gsl_matrix_ptr(inverse, i, j) =
174 (*gsl_matrix_ptr(inverse, i, j) - sum) / *gsl_matrix_ptr(LU, i, i);
175 }
176 }
177
178 return 0;
179}
180
188 if (A->size1 != A->size2) {
189 return -1;
190 }
191
192 size_t n = A->size1;
193 *signum = 1;
194
195 // Initialize permutation
196 for (size_t i = 0; i < n; ++i) {
197 p->data[i] = i;
198 }
199
200 // Perform LU decomposition with partial pivoting
201 for (size_t k = 0; k < n - 1; ++k) {
202 // Find pivot
203 size_t max_row = k;
204 double max_val = gsl_complex_abs(*gsl_matrix_complex_ptr(A, k, k));
205 for (size_t i = k + 1; i < n; ++i) {
206 double val = gsl_complex_abs(*gsl_matrix_complex_ptr(A, i, k));
207 if (val > max_val) {
208 max_val = val;
209 max_row = i;
210 }
211 }
212
213 // Swap rows if needed
214 if (max_row != k) {
215 *signum = -*signum;
216 std::swap(p->data[k], p->data[max_row]);
217 for (size_t j = 0; j < n; ++j) {
218 std::swap(*gsl_matrix_complex_ptr(A, k, j), *gsl_matrix_complex_ptr(A, max_row, j));
219 }
220 }
221
222 // Check for singularity
223 if (gsl_complex_abs(*gsl_matrix_complex_ptr(A, k, k)) < 1e-15) {
224 return -1;
225 }
226
227 // Eliminate
228 for (size_t i = k + 1; i < n; ++i) {
231 *gsl_matrix_complex_ptr(A, i, k) = factor;
232 for (size_t j = k + 1; j < n; ++j) {
234 *gsl_matrix_complex_ptr(A, i, j),
235 gsl_complex_mul(factor, *gsl_matrix_complex_ptr(A, k, j)));
236 }
237 }
238 }
239
240 return 0;
241}
242
249 size_t n = LU->size1;
250 gsl_complex det = gsl_complex(static_cast<double>(signum), 0.0);
251 for (size_t i = 0; i < n; ++i) {
252 det = gsl_complex_mul(det, *gsl_matrix_complex_ptr(LU, i, i));
253 }
254 return det;
255}
256
264 const gsl_matrix_complex* LU, const gsl_permutation* p, gsl_matrix_complex* inverse) {
265 size_t n = LU->size1;
266 if (inverse->size1 != n || inverse->size2 != n) {
267 return -1;
268 }
269
270 // Initialize inverse as permuted identity: P*I
271 for (size_t j = 0; j < n; ++j) {
272 for (size_t i = 0; i < n; ++i) {
273 *gsl_matrix_complex_ptr(inverse, i, j) =
274 (p->data[i] == j) ? gsl_complex(1.0, 0.0) : gsl_complex(0.0, 0.0);
275 }
276 }
277
278 // Forward substitution: L*y = P*I (solve for y)
279 // L is unit lower triangular stored in LU below diagonal
280 for (size_t j = 0; j < n; ++j) {
281 for (size_t i = 0; i < n; ++i) {
282 gsl_complex sum = gsl_complex(0.0, 0.0);
283 for (size_t k = 0; k < i; ++k) {
284 sum = gsl_complex_add(
285 sum, gsl_complex_mul(
286 *gsl_matrix_complex_ptr(LU, i, k),
287 *gsl_matrix_complex_ptr(inverse, k, j)));
288 }
289 *gsl_matrix_complex_ptr(inverse, i, j) =
290 gsl_complex_sub(*gsl_matrix_complex_ptr(inverse, i, j), sum);
291 }
292 }
293
294 // Back substitution: U*x = y (solve for x, which is the inverse)
295 // U is upper triangular stored in LU on and above diagonal
296 for (int i = static_cast<int>(n) - 1; i >= 0; --i) {
297 for (size_t j = 0; j < n; ++j) {
298 gsl_complex sum = gsl_complex(0.0, 0.0);
299 for (size_t k = i + 1; k < n; ++k) {
300 sum = gsl_complex_add(
301 sum, gsl_complex_mul(
302 *gsl_matrix_complex_ptr(LU, i, k),
303 *gsl_matrix_complex_ptr(inverse, k, j)));
304 }
305 *gsl_matrix_complex_ptr(inverse, i, j) = gsl_complex_div(
306 gsl_complex_sub(*gsl_matrix_complex_ptr(inverse, i, j), sum),
307 *gsl_matrix_complex_ptr(LU, i, i));
308 }
309 }
310
311 return 0;
312}
313
320 return gsl_linalg_complex_LU_decomp(A, p, signum);
321}
322
328 return gsl_linalg_complex_LU_det(LU, signum);
329}
330
337 const gsl_matrix_complex* LU, const gsl_permutation* p, gsl_matrix_complex* inverse) {
338 return gsl_linalg_complex_LU_invert(LU, p, inverse);
339}
340
341#endif // OPAL_GSL_LINALG_HH
gsl_complex gsl_complex_div(gsl_complex a, gsl_complex b)
Quotient .
Definition GSLComplex.h:106
gsl_complex gsl_complex_mul(gsl_complex a, gsl_complex b)
Product .
Definition GSLComplex.h:97
double gsl_complex_abs(gsl_complex z)
Magnitude .
Definition GSLComplex.h:67
gsl_complex gsl_complex_add(gsl_complex a, gsl_complex b)
Sum .
Definition GSLComplex.h:79
gsl_complex gsl_complex_sub(gsl_complex a, gsl_complex b)
Difference .
Definition GSLComplex.h:88
int gsl_linalg_LU_decomp_complex(gsl_matrix_complex *A, gsl_permutation *p, int *signum)
Alias for gsl_linalg_complex_LU_decomp.
Definition GSLLinalg.h:319
int gsl_linalg_LU_invert_complex(const gsl_matrix_complex *LU, const gsl_permutation *p, gsl_matrix_complex *inverse)
Alias for gsl_linalg_complex_LU_invert.
Definition GSLLinalg.h:336
gsl_complex gsl_linalg_complex_LU_det(const gsl_matrix_complex *LU, int signum)
Determinant from LU decomposition (complex).
Definition GSLLinalg.h:248
void gsl_permutation_free(gsl_permutation *p)
Free a permutation allocated by gsl_permutation_alloc.
Definition GSLLinalg.h:52
int gsl_linalg_LU_invert(const gsl_matrix *LU, const gsl_permutation *p, gsl_matrix *inverse)
Invert a matrix from its LU decomposition (real).
Definition GSLLinalg.h:139
gsl_permutation * gsl_permutation_alloc(size_t n)
Allocate an identity permutation of size .
Definition GSLLinalg.h:40
gsl_complex gsl_linalg_LU_det_complex(const gsl_matrix_complex *LU, int signum)
Alias for gsl_linalg_complex_LU_det.
Definition GSLLinalg.h:327
int gsl_linalg_complex_LU_decomp(gsl_matrix_complex *A, gsl_permutation *p, int *signum)
In-place LU decomposition with partial pivoting (complex).
Definition GSLLinalg.h:187
int gsl_linalg_complex_LU_invert(const gsl_matrix_complex *LU, const gsl_permutation *p, gsl_matrix_complex *inverse)
Invert a matrix from its LU decomposition (complex).
Definition GSLLinalg.h:263
double gsl_linalg_LU_det(const gsl_matrix *LU, int signum)
Determinant from LU decomposition (real).
Definition GSLLinalg.h:124
int gsl_linalg_LU_decomp(gsl_matrix *A, gsl_permutation *p, int *signum)
In-place LU decomposition with partial pivoting (real).
Definition GSLLinalg.h:66
double * gsl_matrix_ptr(gsl_matrix *m, size_t i, size_t j)
Return pointer to element in a real matrix.
Definition GSLMatrix.h:199
gsl_complex * gsl_matrix_complex_ptr(gsl_matrix_complex *m, size_t i, size_t j)
Return pointer to element in a complex matrix.
Definition GSLMatrix.h:217
Complex number stored as .
Definition GSLComplex.h:27
Dense complex matrix in row-major storage.
Definition GSLMatrix.h:45
Dense real matrix in row-major storage.
Definition GSLMatrix.h:29
size_t size1
Definition GSLMatrix.h:30
size_t size2
Definition GSLMatrix.h:31
Permutation vector for LU decomposition.
Definition GSLLinalg.h:30
size_t * data
Definition GSLLinalg.h:32