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