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_memory
.klu_malloc_dbl
;
32 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_scale
.klu_scale
;
33 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_dump
.klu_valid
;
34 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_dump
.klu_valid_LU
;
37 * Factor the matrix, after ordering and analyzing it with KLU_analyze, and
38 * factoring it once with KLU_factor. This routine cannot do any numerical
39 * pivoting. The pattern of the input matrix (Ap, Ai) must be identical to
40 * the pattern given to KLU_factor.
42 public class Dklu_refactor
extends Dklu_internal
{
46 * @param Ap size n+1, column pointers
47 * @param Ai size nz, row indices
52 * @return true if successful, false otherwise
54 public static int klu_refactor(int[] Ap
, int[] Ai
, double[] Ax
,
55 KLU_symbolic Symbolic
, KLU_numeric Numeric
, KLU_common Common
)
58 double[] Offx
, Lx
, Ux
, X
, Az
, Udiag
;
60 int[] Q
, R
, Pnum
, Offp
, Offi
, Pinv
, Lip
, Uip
, Llen
, Ulen
;
61 /*int[]*/double[] Ui
, Li
;
64 int k1
, k2
, nk
, k
, block
, oldcol
, pend
, oldrow
, n
, p
, newrow
, scale
,
65 nblocks
, poff
, i
, j
, up
, maxblock
, nzoff
;
66 int[] ulen
= new int[1] ;
67 int[] Ui_offset
= new int[1] ;
68 int[] Ux_offset
= new int[1] ;
69 int[] llen
= new int[1] ;
70 int[] Li_offset
= new int[1] ;
71 int[] Lx_offset
= new int[1] ;
73 /* ---------------------------------------------------------------------- */
75 /* ---------------------------------------------------------------------- */
81 Common
.status
= KLU_OK
;
85 /* invalid Numeric object */
86 Common
.status
= KLU_INVALID
;
90 Common
.numerical_rank
= EMPTY
;
91 Common
.singular_col
= EMPTY
;
95 /* ---------------------------------------------------------------------- */
96 /* get the contents of the Symbolic object */
97 /* ---------------------------------------------------------------------- */
102 nblocks
= Symbolic
.nblocks
;
103 maxblock
= Symbolic
.maxblock
;
105 /* ---------------------------------------------------------------------- */
106 /* get the contents of the Numeric object */
107 /* ---------------------------------------------------------------------- */
109 Pnum
= Numeric
.Pnum
;
110 Offp
= Numeric
.Offp
;
111 Offi
= Numeric
.Offi
;
112 Offx
= Numeric
.Offx
;
114 LUbx
= Numeric
.LUbx
;
116 scale
= Common
.scale
;
119 /* factorization was not scaled, but refactorization is scaled */
120 if (Numeric
.Rs
== null)
122 Numeric
.Rs
= klu_malloc_dbl (n
, Common
) ;
123 if (Common
.status
< KLU_OK
)
125 Common
.status
= KLU_OUT_OF_MEMORY
;
132 /* no scaling for refactorization; ensure Numeric.Rs is freed. This
133 * does nothing if Numeric.Rs is already null. */
134 //Numeric.Rs = KLU_free (Numeric.Rs, n, sizeof (double), Common) ;
139 Pinv
= Numeric
.Pinv
;
141 Common
.nrealloc
= 0 ;
142 Udiag
= Numeric
.Udiag
;
143 nzoff
= Symbolic
.nzoff
;
145 /* ---------------------------------------------------------------------- */
146 /* check the input matrix compute the row scale factors, Rs */
147 /* ---------------------------------------------------------------------- */
149 /* do no scale, or check the input matrix, if scale < 0 */
152 /* check for out-of-range indices, but do not check for duplicates */
153 if (klu_scale (scale
, n
, Ap
, Ai
, Ax
, Rs
, null, Common
) == 0)
159 /* ---------------------------------------------------------------------- */
160 /* clear workspace X */
161 /* ---------------------------------------------------------------------- */
163 for (k
= 0 ; k
< maxblock
; k
++)
171 /* ---------------------------------------------------------------------- */
172 /* factor each block */
173 /* ---------------------------------------------------------------------- */
178 /* ------------------------------------------------------------------ */
180 /* ------------------------------------------------------------------ */
182 for (block
= 0 ; block
< nblocks
; block
++)
185 /* -------------------------------------------------------------- */
186 /* the block is from rows/columns k1 to k2-1 */
187 /* -------------------------------------------------------------- */
196 /* ---------------------------------------------------------- */
198 /* ---------------------------------------------------------- */
201 pend
= Ap
[oldcol
+1] ;
202 s
= 0 ; //CLEAR (s) ;
203 for (p
= Ap
[oldcol
] ; p
< pend
; p
++)
205 newrow
= Pinv
[Ai
[p
]] - k1
;
206 if (newrow
< 0 && poff
< nzoff
)
208 /* entry in off-diagonal block */
209 Offx
[poff
] = Az
[p
] ;
224 /* ---------------------------------------------------------- */
225 /* construct and factor the kth block */
226 /* ---------------------------------------------------------- */
229 int Lip_offset
= k1
;
230 Llen
= Numeric
.Llen
;
231 int Llen_offset
= k1
;
233 int Uip_offset
= k1
;
234 Ulen
= Numeric
.Ulen
;
235 int Ulen_offset
= k1
;
238 for (k
= 0 ; k
< nk
; k
++)
241 /* ------------------------------------------------------ */
242 /* scatter kth column of the block into workspace X */
243 /* ------------------------------------------------------ */
246 pend
= Ap
[oldcol
+1] ;
247 for (p
= Ap
[oldcol
] ; p
< pend
; p
++)
249 newrow
= Pinv
[Ai
[p
]] - k1
;
250 if (newrow
< 0 && poff
< nzoff
)
252 /* entry in off-diagonal block */
253 Offx
[poff
] = Az
[p
] ;
258 /* (newrow,k) is an entry in the block */
259 X
[newrow
] = Az
[p
] ;
263 /* ------------------------------------------------------ */
264 /* compute kth column of U, and update kth column of A */
265 /* ------------------------------------------------------ */
267 Ui
= Ux
= GET_POINTER (LU
, Uip
, Uip_offset
, Ulen
, Ulen_offset
,
268 Ui_offset
, Ux_offset
, k
, ulen
) ;
269 for (up
= 0 ; up
< ulen
[0] ; up
++)
271 j
= (int) Ui
[Ui_offset
[0] + up
] ;
275 Ux
[Ux_offset
[0] + up
] = ujk
;
276 Li
= Lx
= GET_POINTER (LU
, Lip
, Lip_offset
, Llen
, Llen_offset
,
277 Li_offset
, Lx_offset
, j
, llen
) ;
278 for (p
= 0 ; p
< llen
[0] ; p
++)
280 //MULT_SUB (X [Li [p]], Lx [p], ujk) ;
281 X
[(int) Li
[Li_offset
[0] + p
]] -= Lx
[Lx_offset
[0] + p
] * ujk
;
284 /* get the diagonal entry of U */
291 /* matrix is numerically singular */
292 Common
.status
= KLU_SINGULAR
;
293 if (Common
.numerical_rank
== EMPTY
)
295 Common
.numerical_rank
= k
+k1
;
296 Common
.singular_col
= Q
[k
+k1
] ;
298 if (Common
.halt_if_singular
!= 0)
300 /* do not continue the factorization */
305 /* gather and divide by pivot to get kth column of L */
306 Li
= Lx
= GET_POINTER (LU
, Lip
, Lip_offset
, Llen
, Llen_offset
,
307 Li_offset
, Lx_offset
, k
, llen
) ;
308 for (p
= 0 ; p
< llen
[0] ; p
++)
310 i
= (int) Li
[Li_offset
[0] + p
] ;
311 //DIV (Lx [p], X [i], ukk) ;
312 Lx
[Lx_offset
[0] + p
] = X
[i
] / ukk
;
324 /* ------------------------------------------------------------------ */
326 /* ------------------------------------------------------------------ */
328 for (block
= 0 ; block
< nblocks
; block
++)
331 /* -------------------------------------------------------------- */
332 /* the block is from rows/columns k1 to k2-1 */
333 /* -------------------------------------------------------------- */
342 /* ---------------------------------------------------------- */
344 /* ---------------------------------------------------------- */
347 pend
= Ap
[oldcol
+1] ;
348 s
= 0 ; //CLEAR (s) ;
349 for (p
= Ap
[oldcol
] ; p
< pend
; p
++)
352 newrow
= Pinv
[oldrow
] - k1
;
353 if (newrow
< 0 && poff
< nzoff
)
355 /* entry in off-diagonal block */
356 Offx
[poff
] = Az
[p
] / Rs
[oldrow
] ;
357 //SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]) ;
363 s
= Az
[p
] / Rs
[oldrow
] ;
364 //SCALE_DIV_ASSIGN (s, Az [p], Rs [oldrow]) ;
373 /* ---------------------------------------------------------- */
374 /* construct and factor the kth block */
375 /* ---------------------------------------------------------- */
378 int Lip_offset
= k1
;
379 Llen
= Numeric
.Llen
;
380 int Llen_offset
= k1
;
382 int Uip_offset
= k1
;
383 Ulen
= Numeric
.Ulen
;
384 int Ulen_offset
= k1
;
387 for (k
= 0 ; k
< nk
; k
++)
390 /* ------------------------------------------------------ */
391 /* scatter kth column of the block into workspace X */
392 /* ------------------------------------------------------ */
395 pend
= Ap
[oldcol
+1] ;
396 for (p
= Ap
[oldcol
] ; p
< pend
; p
++)
399 newrow
= Pinv
[oldrow
] - k1
;
400 if (newrow
< 0 && poff
< nzoff
)
402 /* entry in off-diagonal part */
403 //SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]);
404 Offx
[poff
] = Az
[p
] / Rs
[oldrow
] ;
409 /* (newrow,k) is an entry in the block */
410 //SCALE_DIV_ASSIGN (X [newrow], Az [p], Rs [oldrow]) ;
411 X
[newrow
] = Az
[p
] / Rs
[oldrow
] ;
415 /* ------------------------------------------------------ */
416 /* compute kth column of U, and update kth column of A */
417 /* ------------------------------------------------------ */
419 Ui
= Ux
= GET_POINTER (LU
, Uip
, Uip_offset
, Ulen
, Ulen_offset
,
420 Ui_offset
, Ux_offset
, k
, ulen
) ;
421 for (up
= 0 ; up
< ulen
[0] ; up
++)
423 j
= (int) Ui
[Ui_offset
[0] + up
] ;
427 Ux
[Ux_offset
[0] + up
] = ujk
;
428 Li
= Lx
= GET_POINTER (LU
, Lip
, Lip_offset
, Llen
, Llen_offset
,
429 Li_offset
, Lx_offset
, j
, llen
) ;
430 for (p
= 0 ; p
< llen
[0] ; p
++)
432 //MULT_SUB (X [Li [p]], Lx [p], ujk) ;
433 X
[(int) Li
[Li_offset
[0] + p
]] -= Lx
[Lx_offset
[0] + p
] * ujk
;
436 /* get the diagonal entry of U */
443 /* matrix is numerically singular */
444 Common
.status
= KLU_SINGULAR
;
445 if (Common
.numerical_rank
== EMPTY
)
447 Common
.numerical_rank
= k
+k1
;
448 Common
.singular_col
= Q
[k
+k1
] ;
450 if (Common
.halt_if_singular
!= 0)
452 /* do not continue the factorization */
457 /* gather and divide by pivot to get kth column of L */
458 Li
= Lx
= GET_POINTER (LU
, Lip
, Lip_offset
, Llen
, Llen_offset
,
459 Li_offset
, Lx_offset
, k
, llen
) ;
460 for (p
= 0 ; p
< llen
[0] ; p
++)
462 i
= (int) Li
[Li_offset
[0] + p
] ;
463 //DIV (Lx [p], X [i], ukk) ;
464 Lx
[Lx_offset
[0] + p
] = X
[i
] / ukk
;
472 /* ---------------------------------------------------------------------- */
473 /* permute scale factors Rs according to pivotal row order */
474 /* ---------------------------------------------------------------------- */
478 for (k
= 0 ; k
< n
; k
++)
480 X
[k
] = Rs
[Pnum
[k
]] ;
481 //REAL (X [k]) = Rs [Pnum [k]] ;
483 for (k
= 0 ; k
< n
; k
++)
486 //Rs [k] = REAL (X [k]) ;
492 ASSERT (Offp
[n
] == poff
) ;
493 ASSERT (Symbolic
.nzoff
== poff
) ;
494 PRINTF (("\n------------------- Off diagonal entries, new:\n")) ;
495 if (!NDEBUG
) ASSERT (klu_valid (n
, Offp
, Offi
, Offx
)) ;
496 if (Common
.status
== KLU_OK
)
498 PRINTF ("\n ########### KLU_BTF_REFACTOR done, nblocks %d\n",
500 for (block
= 0 ; block
< nblocks
; block
++)
506 "\n================KLU_refactor output: k1 %d k2 %d nk %d\n",
510 PRINTF ("singleton ") ;
511 PRINT_ENTRY (Udiag
[k1
]) ;
516 int Lip_offset
= k1
;
517 Llen
= Numeric
.Llen
;
518 int Llen_offset
= k1
;
519 LU
= (double[]) Numeric
.LUbx
[block
] ;
520 PRINTF ("\n---- L block %d\n", block
) ;
521 if (!NDEBUG
) ASSERT (klu_valid_LU (nk
, TRUE
, Lip
, Lip_offset
, Llen
, Llen_offset
, LU
)) ;
523 int Uip_offset
= k1
;
524 Ulen
= Numeric
.Ulen
;
525 int Ulen_offset
= k1
;
526 PRINTF ("\n---- U block %d\n", block
) ;
527 if (!NDEBUG
) ASSERT (klu_valid_LU (nk
, FALSE
, Uip
, Uip_offset
, Ulen
, Ulen_offset
, LU
)) ;