Fixing pointers up to Dklu_solve.
[JKLU.git] / src / main / java / edu / ufl / cise / klu / tdouble / Dklu_diagnostics.java
blobda6d522e9cb1d5c0509bd0d8ab53c72c9a3bd5d9
1 /**
2 * KLU: a sparse LU factorization algorithm.
3 * Copyright (C) 2004-2009, Timothy A. Davis.
4 * Copyright (C) 2011-2012, Richard W. Lincoln.
5 * http://www.cise.ufl.edu/research/sparse/klu
7 * -------------------------------------------------------------------------
9 * KLU is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * KLU is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this Module; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 package edu.ufl.cise.klu.tdouble;
27 import edu.ufl.cise.klu.common.KLU_common;
28 import edu.ufl.cise.klu.common.KLU_numeric;
29 import edu.ufl.cise.klu.common.KLU_symbolic;
31 import static edu.ufl.cise.klu.tdouble.Dklu_tsolve.klu_tsolve;
32 import static edu.ufl.cise.klu.tdouble.Dklu_solve.klu_solve;
34 /**
35 * Linear algebraic diagnostics.
37 public class Dklu_diagnostics extends Dklu_internal
40 /**
41 * Compute the reciprocal pivot growth factor. In MATLAB notation:
43 * rgrowth = min (max (abs ((R \ A (p,q)) - F))) ./ max (abs (U)))
45 * Takes O(|A|+|U|) time.
47 * @param Ap
48 * @param Ai
49 * @param Ax
50 * @param Symbolic
51 * @param Numeric
52 * @param Common
53 * @return TRUE if successful, FALSE otherwise
55 public static int klu_rgrowth(int[] Ap, int[] Ai, double[] Ax,
56 KLU_symbolic Symbolic, KLU_numeric Numeric, KLU_common Common)
58 double temp, max_ai, max_ui, min_block_rgrowth ;
59 double aik ;
60 int[] Q, Pinv ;
61 int[] Ulen, Uip ;
62 double[] LU ;
63 double[] Aentry, Ux, Ukk ;
64 double[] Rs ;
65 int i, newrow, oldrow, k1, k2, nk, j, oldcol, k, pend ;
66 int Uip_offset = 0, Ulen_offset = 0, Ukk_offset = 0 ;
67 int[] len = new int[1] ;
68 int[] Ui_offset = new int[1] ;
69 int[] Ux_offset = new int[1] ;
71 /* ---------------------------------------------------------------------- */
72 /* check inputs */
73 /* ---------------------------------------------------------------------- */
75 if (Common == null)
77 return (FALSE) ;
80 if (Symbolic == null || Ap == null || Ai == null || Ax == null)
82 Common.status = KLU_INVALID ;
83 return (FALSE) ;
86 if (Numeric == null)
88 /* treat this as a singular matrix */
89 Common.rgrowth = 0 ;
90 Common.status = KLU_SINGULAR ;
91 return (TRUE) ;
93 Common.status = KLU_OK ;
95 /* ---------------------------------------------------------------------- */
96 /* compute the reciprocal pivot growth */
97 /* ---------------------------------------------------------------------- */
99 Aentry = (double[]) Ax ;
100 Pinv = Numeric.Pinv ;
101 Rs = Numeric.Rs ;
102 Q = Symbolic.Q ;
103 Common.rgrowth = 1 ;
105 for (i = 0 ; i < Symbolic.nblocks ; i++)
107 k1 = Symbolic.R[i] ;
108 k2 = Symbolic.R[i+1] ;
109 nk = k2 - k1 ;
110 if (nk == 1)
112 continue ; /* skip singleton blocks */
114 LU = Numeric.LUbx[i] ;
115 Uip = Numeric.Uip ;
116 Uip_offset += k1 ;
117 Ulen = Numeric.Ulen ;
118 Ulen_offset += k1 ;
119 Ukk = Numeric.Udiag ;
120 Ukk_offset += k1 ;
121 min_block_rgrowth = 1 ;
122 for (j = 0 ; j < nk ; j++)
124 max_ai = 0 ;
125 max_ui = 0 ;
126 oldcol = Q[j + k1] ;
127 pend = Ap [oldcol + 1] ;
128 for (k = Ap [oldcol] ; k < pend ; k++)
130 oldrow = Ai [k] ;
131 newrow = Pinv [oldrow] ;
132 if (newrow < k1)
134 continue ; /* skip entry outside the block */
136 ASSERT (newrow < k2) ;
137 if (Rs != null)
139 //SCALE_DIV_ASSIGN (aik, Aentry [k], Rs [newrow]) ;
140 aik = Aentry [k] / Rs [newrow] ;
142 else
144 aik = Aentry [k] ;
146 temp = ABS ( aik ) ;
147 //ABS (temp, aik) ;
148 if (temp > max_ai)
150 max_ai = temp ;
154 Ux = GET_POINTER (LU, Uip, Uip_offset, Ulen, Ulen_offset,
155 Ui_offset, Ux_offset, j, len) ;
156 for (k = 0 ; k < len[0] ; k++)
158 temp = ABS (Ux [Ux_offset[0] + k]) ;
159 //ABS (temp, Ux [k]) ;
160 if (temp > max_ui)
162 max_ui = temp ;
165 /* consider the diagonal element */
166 temp = ABS (Ukk [Ukk_offset + j]) ;
167 //ABS (temp, Ukk [j]) ;
168 if (temp > max_ui)
170 max_ui = temp ;
173 /* if max_ui is 0, skip the column */
174 if (SCALAR_IS_ZERO (max_ui))
176 continue ;
178 temp = max_ai / max_ui ;
179 if (temp < min_block_rgrowth)
181 min_block_rgrowth = temp ;
185 if (min_block_rgrowth < Common.rgrowth)
187 Common.rgrowth = min_block_rgrowth ;
190 return (TRUE) ;
194 * Estimate the condition number. Uses Higham and Tisseur's algorithm
195 * (A block algorithm for matrix 1-norm estimation, with applications to
196 * 1-norm pseudospectra, SIAM J. Matrix Anal. Appl., 21(4):1185-1201, 2000.
198 * Takes about O(|A|+5*(|L|+|U|)) time
200 * @param Ap
201 * @param Ax
202 * @param Symbolic
203 * @param Numeric
204 * @param Common
205 * @return TRUE if successful, FALSE otherwise
207 public static int klu_condest(int[] Ap, double[] Ax, KLU_symbolic Symbolic,
208 KLU_numeric Numeric, KLU_common Common)
210 double xj, Xmax, csum, anorm, ainv_norm, est_old, est_new, abs_value ;
211 double[] Udiag, Aentry, X, S ;
212 int i, j, jmax, jnew, pend, n ;
213 int unchanged ;
215 /* ---------------------------------------------------------------------- */
216 /* check inputs */
217 /* ---------------------------------------------------------------------- */
219 if (Common == null)
221 return (FALSE) ;
223 if (Symbolic == null || Ap == null || Ax == null)
225 Common.status = KLU_INVALID ;
226 return (FALSE) ;
228 abs_value = 0 ;
229 if (Numeric == null)
231 /* treat this as a singular matrix */
232 Common.condest = 1 / abs_value ;
233 Common.status = KLU_SINGULAR ;
234 return (TRUE) ;
236 Common.status = KLU_OK ;
238 /* ---------------------------------------------------------------------- */
239 /* get inputs */
240 /* ---------------------------------------------------------------------- */
242 n = Symbolic.n ;
243 Udiag = Numeric.Udiag ;
245 /* ---------------------------------------------------------------------- */
246 /* check if diagonal of U has a zero on it */
247 /* ---------------------------------------------------------------------- */
249 for (i = 0 ; i < n ; i++)
251 //ABS (abs_value, Udiag [i]) ;
252 abs_value = ABS (Udiag [i]) ;
253 if (SCALAR_IS_ZERO (abs_value))
255 Common.condest = 1 / abs_value ;
256 Common.status = KLU_SINGULAR ;
257 return (TRUE) ;
261 /* ---------------------------------------------------------------------- */
262 /* compute 1-norm (maximum column sum) of the matrix */
263 /* ---------------------------------------------------------------------- */
265 anorm = 0.0 ;
266 Aentry = (double[]) Ax ;
267 for (i = 0 ; i < n ; i++)
269 pend = Ap [i + 1] ;
270 csum = 0.0 ;
271 for (j = Ap [i] ; j < pend ; j++)
273 //ABS (abs_value, Aentry [j]) ;
274 abs_value = ABS (Aentry [j]) ;
275 csum += abs_value ;
277 if (csum > anorm)
279 anorm = csum ;
283 /* ---------------------------------------------------------------------- */
284 /* compute estimate of 1-norm of inv (A) */
285 /* ---------------------------------------------------------------------- */
287 /* get workspace (size 2*n double's) */
288 X = Numeric.Xwork ; /* size n space used in KLU_solve, tsolve */
289 //X += n ; /* X is size n */
290 int X_offset = n ;
291 //S = X + n ; /* S is size n */
292 S = X ;
293 int S_offset = 2*n ;
295 for (i = 0 ; i < n ; i++)
297 CLEAR (S, S_offset + i) ;
298 CLEAR (X, X_offset + i) ;
299 //REAL (X [i]) = 1.0 / ((double) n) ;
300 X [X_offset + i] = 1.0 / ((double) n);
302 jmax = 0 ;
304 ainv_norm = 0.0 ;
305 for (i = 0 ; i < 5 ; i++)
307 if (i > 0)
309 /* X [jmax] is the largest entry in X */
310 for (j = 0 ; j < n ; j++)
312 CLEAR (X, X_offset + j) ;
314 //REAL (X [jmax]) = 1 ;
315 X [X_offset + jmax] = 1 ;
318 klu_solve (Symbolic, Numeric, n, 1, (double[]) X, X_offset, Common) ;
319 est_old = ainv_norm ;
320 ainv_norm = 0.0 ;
322 for (j = 0 ; j < n ; j++)
324 /* ainv_norm += ABS (X [j]) ;*/
325 //ABS (abs_value, X [j]) ;
326 abs_value = ABS (X [X_offset + j]) ;
327 ainv_norm += abs_value ;
330 unchanged = TRUE ;
332 for (j = 0 ; j < n ; j++)
334 double s = (X [X_offset + j] >= 0) ? 1 : -1 ;
335 if (s != S [S_offset + j]) // s != REAL (S [j])
337 S [S_offset + j] = s ;
338 unchanged = FALSE ;
342 if (i > 0 && (ainv_norm <= est_old || unchanged == 1))
344 break ;
347 for (j = 0 ; j < n ; j++)
349 X [j] = S [S_offset + j] ;
352 /* do a transpose solve */
353 klu_tsolve (Symbolic, Numeric, n, 1, X, X_offset, Common) ;
355 /* jnew = the position of the largest entry in X */
356 jnew = 0 ;
357 Xmax = 0 ;
358 for (j = 0 ; j < n ; j++)
360 //ABS (xj, X [j]) ;
361 xj = ABS (X [X_offset + j]) ;
362 if (xj > Xmax)
364 Xmax = xj ;
365 jnew = j ;
368 if (i > 0 && jnew == jmax)
370 /* the position of the largest entry did not change
371 * from the previous iteration */
372 break ;
374 jmax = jnew ;
377 /* ---------------------------------------------------------------------- */
378 /* compute another estimate of norm(inv(A),1), and take the largest one */
379 /* ---------------------------------------------------------------------- */
381 for (j = 0 ; j < n ; j++)
383 CLEAR (X, X_offset + j) ;
384 if (j % 2 != 0)
386 //REAL (X [j]) = 1 + ((double) j) / ((double) (n-1)) ;
387 X [X_offset + j] = 1 + ((double) j) / ((double) (n-1)) ;
389 else
391 //REAL (X [j]) = -1 - ((double) j) / ((double) (n-1)) ;
392 X [X_offset + j] = -1 - ((double) j) / ((double) (n-1)) ;
396 klu_solve (Symbolic, Numeric, n, 1, (double[]) X, X_offset, Common) ;
398 est_new = 0.0 ;
399 for (j = 0 ; j < n ; j++)
401 /* est_new += ABS (X [j]) ;*/
402 //ABS (abs_value, X [j]) ;
403 abs_value = ABS (X [X_offset + j]) ;
404 est_new += abs_value ;
406 est_new = 2 * est_new / (3 * n) ;
407 ainv_norm = MAX (est_new, ainv_norm) ;
409 /* ---------------------------------------------------------------------- */
410 /* compute estimate of condition number */
411 /* ---------------------------------------------------------------------- */
413 Common.condest = ainv_norm * anorm ;
414 return (TRUE) ;
418 * Compute the flop count for the LU factorization (in Common.flops)
420 * @param Symbolic
421 * @param Numeric
422 * @param Common
423 * @return TRUE if successful, FALSE otherwise
425 public static int klu_flops(KLU_symbolic Symbolic, KLU_numeric Numeric,
426 KLU_common Common)
428 double flops = 0 ;
429 int[] R, Uip, Llen, Ulen ;
430 /*int[]*/double[] Ui ;
431 double[][] LUbx ;
432 double[] LU ;
433 int k, ulen, p, nk, block, nblocks, k1 ;
434 int Llen_offset = 0, Uip_offset = 0, Ulen_offset = 0 ;
436 /* ---------------------------------------------------------------------- */
437 /* check inputs */
438 /* ---------------------------------------------------------------------- */
440 if (Common == null)
442 return (FALSE) ;
444 Common.flops = EMPTY ;
445 if (Numeric == null || Symbolic == null)
447 Common.status = KLU_INVALID ;
448 return (FALSE) ;
450 Common.status = KLU_OK ;
452 /* ---------------------------------------------------------------------- */
453 /* get the contents of the Symbolic object */
454 /* ---------------------------------------------------------------------- */
456 R = Symbolic.R ;
457 nblocks = Symbolic.nblocks ;
459 /* ---------------------------------------------------------------------- */
460 /* get the contents of the Numeric object */
461 /* ---------------------------------------------------------------------- */
463 LUbx = (double[][]) Numeric.LUbx ;
465 /* ---------------------------------------------------------------------- */
466 /* compute the flop count */
467 /* ---------------------------------------------------------------------- */
469 for (block = 0 ; block < nblocks ; block++)
471 k1 = R [block] ;
472 nk = R [block+1] - k1 ;
473 if (nk > 1)
475 Llen = Numeric.Llen ;
476 Llen_offset += k1 ;
477 Uip = Numeric.Uip ;
478 Uip_offset += k1 ;
479 Ulen = Numeric.Ulen ;
480 Ulen_offset += k1 ;
481 LU = LUbx [block] ;
482 int[] Ui_offset = new int[1] ;
483 for (k = 0 ; k < nk ; k++)
485 /* compute kth column of U, and update kth column of A */
486 Ui = GET_I_POINTER (LU, Uip, Uip_offset, Ui_offset, k) ;
487 ulen = Ulen [Ulen_offset + k] ;
488 for (p = 0 ; p < ulen ; p++)
490 flops += 2 * Llen [Llen_offset + (int) Ui [Ui_offset[0] + p]] ;
492 /* gather and divide by pivot to get kth column of L */
493 flops += Llen [Llen_offset + k] ;
497 Common.flops = flops ;
498 return (TRUE) ;
502 * Compute a really cheap estimate of the reciprocal of the condition number,
503 * condition number, min(abs(diag(U))) / max(abs(diag(U))). If U has a zero
504 * pivot, or a NaN pivot, rcond will be zero. Takes O(n) time.
506 * @param Symbolic
507 * @param Numeric
508 * @param Common result in Common.rcond
509 * @return TRUE if successful, FALSE otherwise
511 public static int klu_rcond(KLU_symbolic Symbolic, KLU_numeric Numeric,
512 KLU_common Common)
514 double ukk, umin = 0, umax = 0 ;
515 double[] Udiag ;
516 int j, n ;
518 /* ---------------------------------------------------------------------- */
519 /* check inputs */
520 /* ---------------------------------------------------------------------- */
522 if (Common == null)
524 return (FALSE) ;
526 if (Symbolic == null)
528 Common.status = KLU_INVALID ;
529 return (FALSE) ;
531 if (Numeric == null)
533 Common.rcond = 0 ;
534 Common.status = KLU_SINGULAR ;
535 return (TRUE) ;
537 Common.status = KLU_OK ;
539 /* ---------------------------------------------------------------------- */
540 /* compute rcond */
541 /* ---------------------------------------------------------------------- */
543 n = Symbolic.n ;
544 Udiag = Numeric.Udiag ;
545 for (j = 0 ; j < n ; j++)
547 /* get the magnitude of the pivot */
548 //ABS (ukk, Udiag [j]) ;
549 ukk = ABS (Udiag [j]) ;
550 if (SCALAR_IS_NAN (ukk) || SCALAR_IS_ZERO (ukk))
552 /* if NaN, or zero, the rcond is zero */
553 Common.rcond = 0 ;
554 Common.status = KLU_SINGULAR ;
555 return (TRUE) ;
557 if (j == 0)
559 /* first pivot entry */
560 umin = ukk ;
561 umax = ukk ;
563 else
565 /* subsequent pivots */
566 umin = MIN (umin, ukk) ;
567 umax = MAX (umax, ukk) ;
571 Common.rcond = umin / umax ;
572 if (SCALAR_IS_NAN (Common.rcond) || SCALAR_IS_ZERO (Common.rcond))
574 /* this can occur if umin or umax are Inf or NaN */
575 Common.rcond = 0 ;
576 Common.status = KLU_SINGULAR ;
578 return (TRUE) ;