Amesos2 - Direct Sparse Solver Interfaces Version of the Day
klu2_diagnostics.hpp
1/* ========================================================================== */
2/* === KLU_diagnostics ====================================================== */
3/* ========================================================================== */
4// @HEADER
5// *****************************************************************************
6// KLU2: A Direct Linear Solver package
7//
8// Copyright 2011 NTESS and the KLU2 contributors.
9// SPDX-License-Identifier: LGPL-2.1-or-later
10// *****************************************************************************
11// @HEADER
12
13/* Linear algebraic diagnostics:
14 * KLU_rgrowth: reciprocal pivot growth, takes O(|A|+|U|) time
15 * KLU_condest: condition number estimator, takes about O(|A|+5*(|L|+|U|)) time
16 * KLU_flops: compute # flops required to factorize A into L*U
17 * KLU_rcond: compute a really cheap estimate of the reciprocal of the
18 * condition number, min(abs(diag(U))) / max(abs(diag(U))).
19 * Takes O(n) time.
20 */
21
22#ifndef KLU2_DIAGNOSTICS_HPP
23#define KLU2_DIAGNOSTICS_HPP
24
25#include "klu2_internal.h"
26#include "klu2_tsolve.hpp"
27
28/* ========================================================================== */
29/* === KLU_rgrowth ========================================================== */
30/* ========================================================================== */
31
32/* Compute the reciprocal pivot growth factor. In MATLAB notation:
33 *
34 * rgrowth = min (max (abs ((R \ A (p,q)) - F))) ./ max (abs (U)))
35 */
36
37template <typename Entry, typename Int>
38Int KLU_rgrowth /* return TRUE if successful, FALSE otherwise */
39(
40 Int *Ap,
41 Int *Ai,
42 double *Ax,
43 KLU_symbolic<Entry, Int> *Symbolic,
44 KLU_numeric<Entry, Int> *Numeric,
45 KLU_common<Entry, Int> *Common
46)
47{
48 double temp, max_ai, max_ui, min_block_rgrowth ;
49 Entry aik ;
50 Int *Q, *Ui, *Uip, *Ulen, *Pinv ;
51 Unit *LU ;
52 Entry *Aentry, *Ux, *Ukk ;
53 double *Rs ;
54 Int i, newrow, oldrow, k1, k2, nk, j, oldcol, k, pend, len ;
55
56 /* ---------------------------------------------------------------------- */
57 /* check inputs */
58 /* ---------------------------------------------------------------------- */
59
60 if (Common == NULL)
61 {
62 return (FALSE) ;
63 }
64
65 if (Symbolic == NULL || Ap == NULL || Ai == NULL || Ax == NULL)
66 {
67 Common->status = KLU_INVALID ;
68 return (FALSE) ;
69 }
70
71 if (Numeric == NULL)
72 {
73 /* treat this as a singular matrix */
74 Common->rgrowth = 0 ;
75 Common->status = KLU_SINGULAR ;
76 return (TRUE) ;
77 }
78 Common->status = KLU_OK ;
79
80 /* ---------------------------------------------------------------------- */
81 /* compute the reciprocal pivot growth */
82 /* ---------------------------------------------------------------------- */
83
84 Aentry = (Entry *) Ax ;
85 Pinv = Numeric->Pinv ;
86 Rs = Numeric->Rs ;
87 Q = Symbolic->Q ;
88 Common->rgrowth = 1 ;
89
90 for (i = 0 ; i < Symbolic->nblocks ; i++)
91 {
92 k1 = Symbolic->R[i] ;
93 k2 = Symbolic->R[i+1] ;
94 nk = k2 - k1 ;
95 if (nk == 1)
96 {
97 continue ; /* skip singleton blocks */
98 }
99 LU = (Unit *) Numeric->LUbx[i] ;
100 Uip = Numeric->Uip + k1 ;
101 Ulen = Numeric->Ulen + k1 ;
102 Ukk = ((Entry *) Numeric->Udiag) + k1 ;
103 min_block_rgrowth = 1 ;
104 for (j = 0 ; j < nk ; j++)
105 {
106 max_ai = 0 ;
107 max_ui = 0 ;
108 oldcol = Q[j + k1] ;
109 pend = Ap [oldcol + 1] ;
110 for (k = Ap [oldcol] ; k < pend ; k++)
111 {
112 oldrow = Ai [k] ;
113 newrow = Pinv [oldrow] ;
114 if (newrow < k1)
115 {
116 continue ; /* skip entry outside the block */
117 }
118 ASSERT (newrow < k2) ;
119 if (Rs != NULL)
120 {
121 /* aik = Aentry [k] / Rs [oldrow] */
122 SCALE_DIV_ASSIGN (aik, Aentry [k], Rs [newrow]) ;
123 }
124 else
125 {
126 aik = Aentry [k] ;
127 }
128 /* temp = ABS (aik) */
129 KLU2_ABS (temp, aik) ;
130 if (temp > max_ai)
131 {
132 max_ai = temp ;
133 }
134 }
135
136 GET_POINTER (LU, Uip, Ulen, Ui, Ux, j, len) ;
137 for (k = 0 ; k < len ; k++)
138 {
139 /* temp = ABS (Ux [k]) */
140 KLU2_ABS (temp, Ux [k]) ;
141 if (temp > max_ui)
142 {
143 max_ui = temp ;
144 }
145 }
146 /* consider the diagonal element */
147 KLU2_ABS (temp, Ukk [j]) ;
148 if (temp > max_ui)
149 {
150 max_ui = temp ;
151 }
152
153 /* if max_ui is 0, skip the column */
154 if (SCALAR_IS_ZERO (max_ui))
155 {
156 continue ;
157 }
158 temp = max_ai / max_ui ;
159 if (temp < min_block_rgrowth)
160 {
161 min_block_rgrowth = temp ;
162 }
163 }
164
165 if (min_block_rgrowth < Common->rgrowth)
166 {
167 Common->rgrowth = min_block_rgrowth ;
168 }
169 }
170 return (TRUE) ;
171}
172
173
174/* ========================================================================== */
175/* === KLU_condest ========================================================== */
176/* ========================================================================== */
177
178/* Estimate the condition number. Uses Higham and Tisseur's algorithm
179 * (A block algorithm for matrix 1-norm estimation, with applications to
180 * 1-norm pseudospectra, SIAM J. Matrix Anal. Appl., 21(4):1185-1201, 2000.
181 */
182
183template <typename Entry, typename Int>
184Int KLU_condest /* return TRUE if successful, FALSE otherwise */
185(
186 Int Ap [ ],
187 double Ax [ ], /* TODO : Check !!! */
188 KLU_symbolic<Entry, Int> *Symbolic,
189 KLU_numeric<Entry, Int> *Numeric,
190 KLU_common<Entry, Int> *Common
191)
192{
193 double xj, Xmax, csum, anorm, ainv_norm, est_old, est_new, abs_value ;
194 Entry *Udiag, *Aentry, *X, *S ;
195 Int *R ;
196 Int nblocks, i, j, jmax, jnew, pend, n ;
197#ifndef COMPLEX
198 Int unchanged ;
199#endif
200
201 /* ---------------------------------------------------------------------- */
202 /* check inputs */
203 /* ---------------------------------------------------------------------- */
204
205 if (Common == NULL)
206 {
207 return (FALSE) ;
208 }
209 if (Symbolic == NULL || Ap == NULL || Ax == NULL)
210 {
211 Common->status = KLU_INVALID ;
212 return (FALSE) ;
213 }
214 abs_value = 0 ;
215 if (Numeric == NULL)
216 {
217 /* treat this as a singular matrix */
218 Common->condest = 1 / abs_value ;
219 Common->status = KLU_SINGULAR ;
220 return (TRUE) ;
221 }
222 Common->status = KLU_OK ;
223
224 /* ---------------------------------------------------------------------- */
225 /* get inputs */
226 /* ---------------------------------------------------------------------- */
227
228 n = Symbolic->n ;
229 nblocks = Symbolic->nblocks ;
230 R = Symbolic->R ;
231 Udiag = (Entry *) Numeric->Udiag ;
232
233 /* ---------------------------------------------------------------------- */
234 /* check if diagonal of U has a zero on it */
235 /* ---------------------------------------------------------------------- */
236
237 for (i = 0 ; i < n ; i++)
238 {
239 KLU2_ABS (abs_value, Udiag [i]) ;
240 if (SCALAR_IS_ZERO (abs_value))
241 {
242 Common->condest = 1 / abs_value ;
243 Common->status = KLU_SINGULAR ;
244 return (TRUE) ;
245 }
246 }
247
248 /* ---------------------------------------------------------------------- */
249 /* compute 1-norm (maximum column sum) of the matrix */
250 /* ---------------------------------------------------------------------- */
251
252 anorm = 0.0 ;
253 Aentry = (Entry *) Ax ;
254 for (i = 0 ; i < n ; i++)
255 {
256 pend = Ap [i + 1] ;
257 csum = 0.0 ;
258 for (j = Ap [i] ; j < pend ; j++)
259 {
260 KLU2_ABS (abs_value, Aentry [j]) ;
261 csum += abs_value ;
262 }
263 if (csum > anorm)
264 {
265 anorm = csum ;
266 }
267 }
268
269 /* ---------------------------------------------------------------------- */
270 /* compute estimate of 1-norm of inv (A) */
271 /* ---------------------------------------------------------------------- */
272
273 /* get workspace (size 2*n Entry's) */
274 X = (Entry *) Numeric->Xwork ; /* size n space used in KLU_solve, tsolve */
275 X += n ; /* X is size n */
276 S = X + n ; /* S is size n */
277
278 for (i = 0 ; i < n ; i++)
279 {
280 CLEAR (S [i]) ;
281 CLEAR (X [i]) ;
282 /* TODO : Check REAL(X[i]) -> X[i]*/
283 /*REAL (X [i]) = 1.0 / ((double) n) ;*/
284 X [i] = 1.0 / ((double) n) ;
285 }
286 jmax = 0 ;
287
288 ainv_norm = 0.0 ;
289 for (i = 0 ; i < 5 ; i++)
290 {
291 if (i > 0)
292 {
293 /* X [jmax] is the largest entry in X */
294 for (j = 0 ; j < n ; j++)
295 {
296 /* X [j] = 0 ;*/
297 CLEAR (X [j]) ;
298 }
299 /* TODO : Check REAL(X[i]) -> X[i]*/
300 /*REAL (X [jmax]) = 1 ;*/
301 X [jmax] = 1 ;
302 }
303
304 KLU_solve (Symbolic, Numeric, n, 1, (double *) X, Common) ;
305 est_old = ainv_norm ;
306 ainv_norm = 0.0 ;
307
308 for (j = 0 ; j < n ; j++)
309 {
310 /* ainv_norm += ABS (X [j]) ;*/
311 KLU2_ABS (abs_value, X [j]) ;
312 ainv_norm += abs_value ;
313 }
314
315#ifndef COMPLEX
316 unchanged = TRUE ;
317
318 for (j = 0 ; j < n ; j++)
319 {
320 double s = (X [j] >= 0) ? 1 : -1 ;
321 if (s != (Int) REAL (S [j]))
322 {
323 S [j] = s ;
324 unchanged = FALSE ;
325 }
326 }
327
328 if (i > 0 && (ainv_norm <= est_old || unchanged))
329 {
330 break ;
331 }
332#else
333 for (j = 0 ; j < n ; j++)
334 {
335 if (IS_NONZERO (X [j]))
336 {
337 KLU2_ABS (abs_value, X [j]) ;
338 SCALE_DIV_ASSIGN (S [j], X [j], abs_value) ;
339 }
340 else
341 {
342 CLEAR (S [j]) ;
343 /* TODO : Check REAL(X[i]) -> X[i]*/
344 /*REAL (S [j]) = 1 ; */
345 S [j] = 1 ;
346 }
347 }
348
349 if (i > 0 && ainv_norm <= est_old)
350 {
351 break ;
352 }
353#endif
354
355 for (j = 0 ; j < n ; j++)
356 {
357 X [j] = S [j] ;
358 }
359
360#ifndef COMPLEX
361 /* do a transpose solve */
362 KLU_tsolve (Symbolic, Numeric, n, 1, X, Common) ;
363#else
364 /* do a conjugate transpose solve */
365 KLU_tsolve (Symbolic, Numeric, n, 1, (double *) X, 1, Common) ;
366#endif
367
368 /* jnew = the position of the largest entry in X */
369 jnew = 0 ;
370 Xmax = 0 ;
371 for (j = 0 ; j < n ; j++)
372 {
373 /* xj = ABS (X [j]) ;*/
374 KLU2_ABS (xj, X [j]) ;
375 if (xj > Xmax)
376 {
377 Xmax = xj ;
378 jnew = j ;
379 }
380 }
381 if (i > 0 && jnew == jmax)
382 {
383 /* the position of the largest entry did not change
384 * from the previous iteration */
385 break ;
386 }
387 jmax = jnew ;
388 }
389
390 /* ---------------------------------------------------------------------- */
391 /* compute another estimate of norm(inv(A),1), and take the largest one */
392 /* ---------------------------------------------------------------------- */
393
394 for (j = 0 ; j < n ; j++)
395 {
396 CLEAR (X [j]) ;
397 if (j % 2)
398 {
399 /* TODO : Check REAL(X[i]) -> X[i]*/
400 /*REAL (X [j]) = 1 + ((double) j) / ((double) (n-1)) ;*/
401 X [j] = 1 + ((double) j) / ((double) (n-1)) ;
402 }
403 else
404 {
405 /* TODO : Check REAL(X[i]) -> X[i]*/
406 /*REAL (X [j]) = -1 - ((double) j) / ((double) (n-1)) ;*/
407 X [j] = -1 - ((double) j) / ((double) (n-1)) ;
408 }
409 }
410
411 KLU_solve (Symbolic, Numeric, n, 1, (double *) X, Common) ;
412
413 est_new = 0.0 ;
414 for (j = 0 ; j < n ; j++)
415 {
416 /* est_new += ABS (X [j]) ;*/
417 KLU2_ABS (abs_value, X [j]) ;
418 est_new += abs_value ;
419 }
420 est_new = 2 * est_new / (3 * n) ;
421 ainv_norm = MAX (est_new, ainv_norm) ;
422
423 /* ---------------------------------------------------------------------- */
424 /* compute estimate of condition number */
425 /* ---------------------------------------------------------------------- */
426
427 Common->condest = ainv_norm * anorm ;
428 return (TRUE) ;
429}
430
431
432/* ========================================================================== */
433/* === KLU_flops ============================================================ */
434/* ========================================================================== */
435
436/* Compute the flop count for the LU factorization (in Common->flops) */
437
438template <typename Entry, typename Int>
439Int KLU_flops /* return TRUE if successful, FALSE otherwise */
440(
441 KLU_symbolic<Entry, Int> *Symbolic,
442 KLU_numeric<Entry, Int> *Numeric,
443 KLU_common<Entry, Int> *Common
444)
445{
446 double flops = 0 ;
447 Int *R, *Ui, *Uip, *Llen, *Ulen ;
448 Unit **LUbx ;
449 Unit *LU ;
450 Int k, ulen, p, n, nk, block, nblocks, k1 ;
451
452 /* ---------------------------------------------------------------------- */
453 /* check inputs */
454 /* ---------------------------------------------------------------------- */
455
456 if (Common == NULL)
457 {
458 return (FALSE) ;
459 }
460 Common->flops = AMESOS2_KLU2_EMPTY ;
461 if (Numeric == NULL || Symbolic == NULL)
462 {
463 Common->status = KLU_INVALID ;
464 return (FALSE) ;
465 }
466 Common->status = KLU_OK ;
467
468 /* ---------------------------------------------------------------------- */
469 /* get the contents of the Symbolic object */
470 /* ---------------------------------------------------------------------- */
471
472 n = Symbolic->n ;
473 R = Symbolic->R ;
474 nblocks = Symbolic->nblocks ;
475
476 /* ---------------------------------------------------------------------- */
477 /* get the contents of the Numeric object */
478 /* ---------------------------------------------------------------------- */
479
480 LUbx = (Unit **) Numeric->LUbx ;
481
482 /* ---------------------------------------------------------------------- */
483 /* compute the flop count */
484 /* ---------------------------------------------------------------------- */
485
486 for (block = 0 ; block < nblocks ; block++)
487 {
488 k1 = R [block] ;
489 nk = R [block+1] - k1 ;
490 if (nk > 1)
491 {
492 Llen = Numeric->Llen + k1 ;
493 Uip = Numeric->Uip + k1 ;
494 Ulen = Numeric->Ulen + k1 ;
495 LU = LUbx [block] ;
496 for (k = 0 ; k < nk ; k++)
497 {
498 /* compute kth column of U, and update kth column of A */
499 GET_I_POINTER (LU, Uip, Ui, k) ;
500 ulen = Ulen [k] ;
501 for (p = 0 ; p < ulen ; p++)
502 {
503 flops += 2 * Llen [Ui [p]] ;
504 }
505 /* gather and divide by pivot to get kth column of L */
506 flops += Llen [k] ;
507 }
508 }
509 }
510 Common->flops = flops ;
511 return (TRUE) ;
512}
513
514
515/* ========================================================================== */
516/* === KLU_rcond ============================================================ */
517/* ========================================================================== */
518
519/* Compute a really cheap estimate of the reciprocal of the condition number,
520 * condition number, min(abs(diag(U))) / max(abs(diag(U))). If U has a zero
521 * pivot, or a NaN pivot, rcond will be zero. Takes O(n) time.
522 */
523
524template <typename Entry, typename Int>
525Int KLU_rcond /* return TRUE if successful, FALSE otherwise */
526(
527 KLU_symbolic<Entry, Int> *Symbolic, /* input, not modified */
528 KLU_numeric<Entry, Int> *Numeric, /* input, not modified */
529 KLU_common<Entry, Int> *Common /* result in Common->rcond */
530)
531{
532 double ukk, umin = 0, umax = 0 ;
533 Entry *Udiag ;
534 Int j, n ;
535
536 /* ---------------------------------------------------------------------- */
537 /* check inputs */
538 /* ---------------------------------------------------------------------- */
539
540 if (Common == NULL)
541 {
542 return (FALSE) ;
543 }
544 if (Symbolic == NULL)
545 {
546 Common->status = KLU_INVALID ;
547 return (FALSE) ;
548 }
549 if (Numeric == NULL)
550 {
551 Common->rcond = 0 ;
552 Common->status = KLU_SINGULAR ;
553 return (TRUE) ;
554 }
555 Common->status = KLU_OK ;
556
557 /* ---------------------------------------------------------------------- */
558 /* compute rcond */
559 /* ---------------------------------------------------------------------- */
560
561 n = Symbolic->n ;
562 Udiag = (Entry *) Numeric->Udiag ;
563 for (j = 0 ; j < n ; j++)
564 {
565 /* get the magnitude of the pivot */
566 KLU2_ABS (ukk, Udiag [j]) ;
567 if (SCALAR_IS_NAN (ukk) || SCALAR_IS_ZERO (ukk))
568 {
569 /* if NaN, or zero, the rcond is zero */
570 Common->rcond = 0 ;
571 Common->status = KLU_SINGULAR ;
572 return (TRUE) ;
573 }
574 if (j == 0)
575 {
576 /* first pivot entry */
577 umin = ukk ;
578 umax = ukk ;
579 }
580 else
581 {
582 /* subsequent pivots */
583 umin = MIN (umin, ukk) ;
584 umax = MAX (umax, ukk) ;
585 }
586 }
587
588 Common->rcond = umin / umax ;
589 if (SCALAR_IS_NAN (Common->rcond) || SCALAR_IS_ZERO (Common->rcond))
590 {
591 /* this can occur if umin or umax are Inf or NaN */
592 Common->rcond = 0 ;
593 Common->status = KLU_SINGULAR ;
594 }
595 return (TRUE) ;
596}
597
598#endif
int Ai[]
Row values.
Definition klu2_simple.cpp:54
int Ap[]
Column offsets.
Definition klu2_simple.cpp:52