GammaLib 2.0.0
Loading...
Searching...
No Matches
GSparseNumeric.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSparseNumeric.cpp - Sparse matrix numeric analysis class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2006-2022 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GSparseNumeric.cpp
23 * @brief Sparse matrix numeric analysis class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GTools.hpp"
33#include "GMatrixSparse.hpp"
34#include "GSparseNumeric.hpp"
35#include "GSparseSymbolic.hpp"
36
37/* __ Method name definitions ____________________________________________ */
38#define G_CHOLESKY "GSparseNumeric::cholesky_numeric_analysis("\
39 "GMatrixSparse&, GSparseSymbolic&)"
40
41/* __ Macros _____________________________________________________________ */
42#define CS_FLIP(i) (-(i)-2)
43#define CS_MARK(w,j) { w [j] = CS_FLIP (w [j]) ; }
44#define CS_MARKED(w,j) (w [j] < 0)
45
46
47/*==========================================================================
48 = =
49 = Constructors/destructors =
50 = =
51 ==========================================================================*/
52
53/***************************************************************************
54 * GSparseNumeric constructor *
55 ***************************************************************************/
57{
58 // Initialise private members for clean destruction
59 m_L = NULL;
60 m_U = NULL;
61 m_pinv = NULL;
62 m_B = NULL;
63 m_n_pinv = 0;
64 m_n_B = 0;
65
66 // Return
67 return;
68}
69
70
71/***************************************************************************
72 * GSparseNumeric destructor *
73 ***************************************************************************/
75{
76 // De-allocate only if memory has indeed been allocated
77 if (m_L != NULL) delete m_L;
78 if (m_U != NULL) delete m_U;
79 if (m_pinv != NULL) delete [] m_pinv;
80 if (m_B != NULL) delete [] m_B;
81
82 // Return
83 return;
84}
85
86
87/*==========================================================================
88 = =
89 = GSparseNumeric operators =
90 = =
91 ==========================================================================*/
92
93/***************************************************************************
94 * GSparseNumeric assignment operator *
95 ***************************************************************************/
97{
98 // Execute only if object is not identical
99 if (this != &n) {
100
101 // De-allocate only if memory has indeed been allocated
102 if (m_L != NULL) delete m_L;
103 if (m_U != NULL) delete m_U;
104 if (m_pinv != NULL) delete [] m_pinv;
105 if (m_B != NULL) delete [] m_B;
106
107 // Initialise private members for clean destruction
108 m_L = NULL;
109 m_U = NULL;
110 m_pinv = NULL;
111 m_B = NULL;
112 m_n_pinv = 0;
113 m_n_B = 0;
114
115 // Copy m_L if it exists
116 if (n.m_L != NULL) {
117 m_L = new GMatrixSparse(*n.m_L);
118 }
119
120 // Copy m_U if it exists
121 if (n.m_U != NULL) {
122 m_U = new GMatrixSparse(*n.m_U);
123 }
124
125 // Copy m_pinv array if it exists
126 if (n.m_pinv != NULL && n.m_n_pinv > 0) {
127 m_pinv = new int[n.m_n_pinv];
128 for (int i = 0; i < n.m_n_pinv; ++i) {
129 m_pinv[i] = n.m_pinv[i];
130 }
131 m_n_pinv = n.m_n_pinv;
132 }
133
134 // Copy m_B array if it exists
135 if (n.m_B != NULL && n.m_n_B > 0) {
136 m_B = new double[n.m_n_B];
137 for (int i = 0; i < n.m_n_B; ++i) {
138 m_B[i] = n.m_B[i];
139 }
140 m_n_B = n.m_n_B;
141 }
142
143 } // endif: object was not identical
144
145 // Return
146 return *this;
147}
148
149
150/*==========================================================================
151 = =
152 = GSparseNumeric member functions =
153 = =
154 ==========================================================================*/
155
156/***************************************************************************
157 * @brief Numerical Cholesky analysis
158 *
159 * @param[in] A Spare matrix.
160 * @param[in] S Symbolic analysis of sparse matrix.
161 ***************************************************************************/
163 const GSparseSymbolic& S)
164{
165 // De-allocate memory that has indeed been previously allocated
166 if (m_L != NULL) delete m_L;
167 if (m_U != NULL) delete m_U;
168 if (m_pinv != NULL) delete [] m_pinv;
169 if (m_B != NULL) delete [] m_B;
170
171 // Initialise members
172 m_L = NULL;
173 m_U = NULL;
174 m_pinv = NULL;
175 m_B = NULL;
176 m_n_pinv = 0;
177 m_n_B = 0;
178
179 // Return if arrays in the symbolic analysis have not been allocated
180 if (!S.m_cp || !S.m_parent) {
181 return;
182 }
183
184 // Declare
185 double lki;
186 int i, p, k;
187
188 // Assign input matrix attributes
189 int n = A.m_cols;
190
191 // Allocate int workspace
192 int wrk_size = 2*n;
193 int* wrk_int = new int[wrk_size];
194
195 // Allocate double workspace
196 wrk_size = n;
197 double* wrk_double = new double[wrk_size];
198
199 // Assign pointers
200 int* cp = S.m_cp;
201 int* pinv = S.m_pinv;
202 int* parent = S.m_parent;
203
204 // Assign C = A(p,p) where A and C are symmetric and the upper part stored
205 GMatrixSparse C = (pinv) ? cs_symperm(A, pinv) : (A);
206
207 // Assign workspace pointer
208 int* c = wrk_int;
209 int* s = wrk_int + n;
210 double* x = wrk_double;
211
212 // Assign C matrix pointers
213 int* Cp = C.m_colstart;
214 int* Ci = C.m_rowinx;
215 double* Cx = C.m_data;
216
217 // Allocate L matrix
218 m_L = new GMatrixSparse(n, n, cp[n]);
219
220 // Assign L matrix pointers
221 int* Lp = m_L->m_colstart;
222 int* Li = m_L->m_rowinx;
223 double* Lx = m_L->m_data;
224
225 // Initialise column pointers of L and c
226 for (k = 0; k < n; ++k) {
227 Lp[k] = c[k] = cp[k];
228 }
229
230 // Compute L(:,k) for L*L' = C
231 for (k = 0; k < n; k++) {
232
233 // Nonzero pattern of L(k,:).
234 // Returns -1 if parent = NULL, s = NULL or c = NULL
235 int top = cs_ereach(&C, k, parent, s, c); // find pattern of L(k,:)
236 x[k] = 0; // x (0:k) is now zero
237
238 // x = full(triu(C(:,k)))
239 for (p = Cp[k]; p < Cp[k+1]; p++) {
240 if (Ci[p] <= k) {
241 x[Ci[p]] = Cx[p];
242 }
243 }
244
245 // d = C(k,k)
246 double d = x[k];
247
248 // Clear x for k+1st iteration
249 x[k] = 0;
250
251 // Triangular solve: Solve L(0:k-1,0:k-1) * x = C(:,k)
252 for ( ; top < n; top++) {
253 i = s[top]; // s [top..n-1] is pattern of L(k,:)
254 lki = x[i]/Lx[Lp[i]]; // L(k,i) = x (i) / L(i,i)
255 x[i] = 0; // clear x for k+1st iteration
256 for (p = Lp[i]+1; p < c[i]; p++) {
257 x[Li[p]] -= Lx[p] * lki;
258 }
259 d -= lki * lki; // d = d - L(k,i)*L(k,i)
260 p = c[i]++;
261 Li[p] = k; // store L(k,i) in column i
262 Lx[p] = lki;
263 }
264
265 // Compute L(k,k)
266 if (d <= 0) {
267 std::string msg = "Matrix is not positive definite, the sum "+
268 gammalib::str(d)+" occured in row and column "+
269 gammalib::str(k)+".";
271 }
272
273 // Store L(k,k) = sqrt (d) in column k
274 p = c[k]++;
275 Li[p] = k;
276 Lx[p] = sqrt(d);
277
278 }
279
280 // Finalize L
281 Lp[n] = cp[n];
282
283 // Free workspace
284 delete [] wrk_int;
285 delete [] wrk_double;
286
287 // Return void
288 return;
289}
290
291
292/*==========================================================================
293 = =
294 = GSparseNumeric private functions =
295 = =
296 ==========================================================================*/
297
298/***************************************************************************
299 * @brief cs_ereach
300 *
301 * @param[in] A Sparse matrix.
302 * @param[in] k Node.
303 * @param[in] parent Argument.
304 * @param[in] s Argument.
305 * @param[in] w Argument.
306 * @return Index, where s[top..n-1] contains pattern of L(k,:); -1 if
307 * arrays have not been allocated
308 *
309 * Find nonzero pattern of Cholesky L(k,1:k-1) using etree and triu(A(:,k))
310 ***************************************************************************/
312 int k,
313 const int* parent,
314 int* s,
315 int* w)
316{
317 // Return -1 if arrays have not been allocated
318 if (!parent || !s || !w) {
319 return (-1);
320 }
321
322 // Assign A matrix attributes and pointers
323 int n = A->m_cols;
324 int top = n;
325 int* Ap = A->m_colstart;
326 int* Ai = A->m_rowinx;
327
328 // Mark node k as visited
329 CS_MARK(w, k);
330
331 // Loop over elements of node
332 for (int p = Ap[k]; p < Ap[k+1]; ++p) {
333 int i = Ai[p]; // A(i,k) is nonzero
334 if (i > k) {
335 continue; // only use upper triangular part of A
336 }
337
338 // Traverse up etree
339 int len;
340 for (len = 0; !CS_MARKED(w,i); i = parent[i]) {
341 s[len++] = i; // L(k,i) is nonzero
342 CS_MARK(w, i); // mark i as visited
343 }
344
345 // Push path onto stack
346 while (len > 0) {
347 s[--top] = s[--len];
348 }
349
350 } // endfor: looped over elements of node
351
352 // Unmark all nodes
353 for (int p = top; p < n; ++p) {
354 CS_MARK(w, s[p]);
355 }
356
357 // Unmark node k
358 CS_MARK(w, k);
359
360 // Return index top, where s[top..n-1] contains pattern of L(k,:)
361 return top;
362}
363
364
365/*==========================================================================
366 = =
367 = GSparseNumeric static member functions =
368 = =
369 ==========================================================================*/
370
371/*==========================================================================
372 = =
373 = GSparseNumeric friends =
374 = =
375 ==========================================================================*/
376
377/***************************************************************************
378 * Output operator *
379 ***************************************************************************/
380std::ostream& operator<< (std::ostream& os, const GSparseNumeric& n)
381{
382 // Put header is stream
383 os << "=== GSparseNumeric ===";
384
385 // Show L or V matrix
386 if (n.m_L != NULL) {
387 os << std::endl << " === L or V ";
388 os << *n.m_L << std::endl;
389 }
390
391 // Show U or R matrix
392 if (n.m_U != NULL) {
393 os << std::endl << " === U or R matrix ";
394 os << *n.m_U << std::endl;
395 }
396
397 // Show inverse permutation if it exists
398 if (n.m_pinv != NULL) {
399 os << std::endl << " Inverse permutation (of ";
400 os << n.m_n_pinv << " elements)" << std::endl;
401 for (int i = 0; i < n.m_n_pinv; ++i) {
402 os << " " << n.m_pinv[i];
403 }
404 }
405
406 // Show beta array if it exists
407 if (n.m_B != NULL) {
408 os << std::endl << " Beta[0.." << n.m_n_B << "]" << std::endl;
409 for (int i = 0; i < n.m_n_B; ++i) {
410 os << " " << n.m_B[i];
411 }
412 }
413
414 // Return output stream
415 return os;
416}
Exception handler interface definition.
GMatrixSparse cs_symperm(const GMatrixSparse &matrix, const int *pinv)
cs_symperm
Sparse matrix class definition.
#define G_CHOLESKY
std::ostream & operator<<(std::ostream &os, const GSparseNumeric &n)
#define CS_MARK(w, j)
#define CS_MARKED(w, j)
Sparse matrix numeric analysis class definition.
Sparse matrix symbolic analysis class definition.
Gammalib tools definition.
GVector sqrt(const GVector &vector)
Computes square root of vector elements.
Definition GVector.cpp:1358
int m_cols
Number of columns.
double * m_data
Matrix data.
int * m_colstart
Column start indices (m_cols+1)
Sparse matrix class interface definition.
int * m_rowinx
Row-indices of all elements.
Sparse matrix numeric analysis class.
GMatrixSparse * m_U
virtual ~GSparseNumeric(void)
GSparseNumeric & operator=(const GSparseNumeric &n)
GMatrixSparse * m_L
friend class GMatrixSparse
void cholesky_numeric_analysis(const GMatrixSparse &m, const GSparseSymbolic &s)
int cs_ereach(const GMatrixSparse *A, int k, const int *parent, int *s, int *w)
Sparse matrix symbolic analysis class.
int * m_pinv
Inverse row permutation for QR, fill reduce permutation for Cholesky.
int * m_cp
column pointers for Cholesky, row counts for QR
int * m_parent
elimination tree for Cholesky and QR
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489