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 
37 template <typename Entry, typename Int>
38 Int 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 
183 template <typename Entry, typename Int>
184 Int 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 
438 template <typename Entry, typename Int>
439 Int 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 
524 template <typename Entry, typename Int>
525 Int 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 Ap[]
Column offsets.
Definition: klu2_simple.cpp:52
int Ai[]
Row values.
Definition: klu2_simple.cpp:54