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
;
35 * Linear algebraic diagnostics.
37 public class Dklu_diagnostics
extends Dklu_internal
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.
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
;
63 double[] Aentry
, Ux
, Ukk
;
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 /* ---------------------------------------------------------------------- */
73 /* ---------------------------------------------------------------------- */
80 if (Symbolic
== null || Ap
== null || Ai
== null || Ax
== null)
82 Common
.status
= KLU_INVALID
;
88 /* treat this as a singular matrix */
90 Common
.status
= KLU_SINGULAR
;
93 Common
.status
= KLU_OK
;
95 /* ---------------------------------------------------------------------- */
96 /* compute the reciprocal pivot growth */
97 /* ---------------------------------------------------------------------- */
99 Aentry
= (double[]) Ax
;
100 Pinv
= Numeric
.Pinv
;
105 for (i
= 0 ; i
< Symbolic
.nblocks
; i
++)
108 k2
= Symbolic
.R
[i
+1] ;
112 continue ; /* skip singleton blocks */
114 LU
= Numeric
.LUbx
[i
] ;
117 Ulen
= Numeric
.Ulen
;
119 Ukk
= Numeric
.Udiag
;
121 min_block_rgrowth
= 1 ;
122 for (j
= 0 ; j
< nk
; j
++)
127 pend
= Ap
[oldcol
+ 1] ;
128 for (k
= Ap
[oldcol
] ; k
< pend
; k
++)
131 newrow
= Pinv
[oldrow
] ;
134 continue ; /* skip entry outside the block */
136 ASSERT (newrow
< k2
) ;
139 //SCALE_DIV_ASSIGN (aik, Aentry [k], Rs [newrow]) ;
140 aik
= Aentry
[k
] / Rs
[newrow
] ;
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]) ;
165 /* consider the diagonal element */
166 temp
= ABS (Ukk
[Ukk_offset
+ j
]) ;
167 //ABS (temp, Ukk [j]) ;
173 /* if max_ui is 0, skip the column */
174 if (SCALAR_IS_ZERO (max_ui
))
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
;
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
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
;
215 /* ---------------------------------------------------------------------- */
217 /* ---------------------------------------------------------------------- */
223 if (Symbolic
== null || Ap
== null || Ax
== null)
225 Common
.status
= KLU_INVALID
;
231 /* treat this as a singular matrix */
232 Common
.condest
= 1 / abs_value
;
233 Common
.status
= KLU_SINGULAR
;
236 Common
.status
= KLU_OK
;
238 /* ---------------------------------------------------------------------- */
240 /* ---------------------------------------------------------------------- */
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
;
261 /* ---------------------------------------------------------------------- */
262 /* compute 1-norm (maximum column sum) of the matrix */
263 /* ---------------------------------------------------------------------- */
266 Aentry
= (double[]) Ax
;
267 for (i
= 0 ; i
< n
; i
++)
271 for (j
= Ap
[i
] ; j
< pend
; j
++)
273 //ABS (abs_value, Aentry [j]) ;
274 abs_value
= ABS (Aentry
[j
]) ;
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 */
291 //S = X + n ; /* S is size 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
);
305 for (i
= 0 ; i
< 5 ; i
++)
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
;
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
;
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
;
342 if (i
> 0 && (ainv_norm
<= est_old
|| unchanged
== 1))
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 */
358 for (j
= 0 ; j
< n
; j
++)
361 xj
= ABS (X
[X_offset
+ j
]) ;
368 if (i
> 0 && jnew
== jmax
)
370 /* the position of the largest entry did not change
371 * from the previous iteration */
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
) ;
386 //REAL (X [j]) = 1 + ((double) j) / ((double) (n-1)) ;
387 X
[X_offset
+ j
] = 1 + ((double) j
) / ((double) (n
-1)) ;
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
) ;
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
;
418 * Compute the flop count for the LU factorization (in Common.flops)
423 * @return TRUE if successful, FALSE otherwise
425 public static int klu_flops(KLU_symbolic Symbolic
, KLU_numeric Numeric
,
429 int[] R
, Uip
, Llen
, Ulen
;
430 /*int[]*/double[] Ui
;
433 int k
, ulen
, p
, nk
, block
, nblocks
, k1
;
434 int Llen_offset
= 0, Uip_offset
= 0, Ulen_offset
= 0 ;
436 /* ---------------------------------------------------------------------- */
438 /* ---------------------------------------------------------------------- */
444 Common
.flops
= EMPTY
;
445 if (Numeric
== null || Symbolic
== null)
447 Common
.status
= KLU_INVALID
;
450 Common
.status
= KLU_OK
;
452 /* ---------------------------------------------------------------------- */
453 /* get the contents of the Symbolic object */
454 /* ---------------------------------------------------------------------- */
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
++)
472 nk
= R
[block
+1] - k1
;
475 Llen
= Numeric
.Llen
;
479 Ulen
= Numeric
.Ulen
;
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
;
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.
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
,
514 double ukk
, umin
= 0, umax
= 0 ;
518 /* ---------------------------------------------------------------------- */
520 /* ---------------------------------------------------------------------- */
526 if (Symbolic
== null)
528 Common
.status
= KLU_INVALID
;
534 Common
.status
= KLU_SINGULAR
;
537 Common
.status
= KLU_OK
;
539 /* ---------------------------------------------------------------------- */
541 /* ---------------------------------------------------------------------- */
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 */
554 Common
.status
= KLU_SINGULAR
;
559 /* first pivot entry */
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 */
576 Common
.status
= KLU_SINGULAR
;