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_scale
.klu_scale
;
32 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_memory
.klu_malloc_int
;
33 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_memory
.klu_malloc_dbl
;
34 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_memory
.klu_add_size_t
;
35 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_dump
.klu_valid_LU
;
36 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu_dump
.klu_valid
;
37 import static edu
.ufl
.cise
.klu
.tdouble
.Dklu
.klu_kernel_factor
;
40 * Factor the matrix, after ordering and analyzing it with KLU_analyze
41 * or KLU_analyze_given.
43 public class Dklu_factor
extends Dklu_internal
48 * @param Ap size n+1, column pointers
49 * @param Ai size nz, row indices
55 public static void factor2(final int[] Ap
, final int[] Ai
, final double[] Ax
,
56 final KLU_symbolic Symbolic
, KLU_numeric Numeric
, KLU_common Common
)
60 int[] P
, Q
, R
, Pnum
, Offp
, Offi
, Pblock
, Pinv
, Iwork
,
61 Lip
, Uip
, Llen
, Ulen
;
62 double[] Offx
, X
, Udiag
;
65 int k1
, k2
, nk
, k
, block
, oldcol
, pend
, oldrow
, n
, lnz
, unz
, p
, newrow
,
66 nblocks
, poff
, nzoff
, scale
, max_lnz_block
,
68 int[] lnz_block
= new int [1] ;
69 int[] unz_block
= new int [1] ;
71 /* ---------------------------------------------------------------------- */
73 /* ---------------------------------------------------------------------- */
75 /* get the contents of the Symbolic object */
81 nblocks
= Symbolic
.nblocks
;
82 nzoff
= Symbolic
.nzoff
;
94 Udiag
= Numeric
.Udiag
;
98 X
= Numeric
.Xwork
; /* X is of size n */
99 // X = new double [n] ;
100 Iwork
= Numeric
.Iwork
; /* 5*maxblock for KLU_factor */
101 // Iwork = new int [5 * Symbolic.maxblock] ;
102 //Pblock = Iwork + 5*((int) Symbolic.maxblock) ; /* 1*maxblock for Pblock */
103 Pblock
= new int [Symbolic
.maxblock
] ;
104 Common
.nrealloc
= 0 ;
105 scale
= Common
.scale
;
109 /* compute the inverse of P from symbolic analysis. Will be updated to
110 * become the inverse of the numerical factorization when the factorization
111 * is done, for use in KLU_refactor */
114 for (k
= 0 ; k
< n
; k
++)
119 for (k
= 0 ; k
< n
; k
++)
121 ASSERT (P
[k
] >= 0 && P
[k
] < n
) ;
126 for (k
= 0 ; k
< n
; k
++) ASSERT (Pinv
[k
] != EMPTY
) ;
131 Common
.noffdiag
= 0 ;
134 /* ---------------------------------------------------------------------- */
135 /* optionally check input matrix and compute scale factors */
136 /* ---------------------------------------------------------------------- */
140 /* use Pnum as workspace. NOTE: scale factors are not yet permuted
141 * according to the final pivot row ordering, so Rs [oldrow] is the
142 * scale factor for A (oldrow,:), for the user's matrix A. Pnum is
143 * used as workspace in KLU_scale. When the factorization is done,
144 * the scale factors are permuted according to the final pivot row
145 * permutation, so that Rs [k] is the scale factor for the kth row of
146 * A(p,q) where p and q are the final row and column permutations. */
147 klu_scale (scale
, n
, Ap
, Ai
, Ax
, Rs
, Pnum
, Common
) ;
148 if (Common
.status
< KLU_OK
)
150 /* matrix is invalid */
159 for (k
= 0 ; k
< n
; k
++) PRINTF ("Rs [%d] %g\n", k
, Rs
[k
]) ;
163 /* ---------------------------------------------------------------------- */
164 /* factor each block using klu */
165 /* ---------------------------------------------------------------------- */
167 for (block
= 0 ; block
< nblocks
; block
++)
170 /* ------------------------------------------------------------------ */
171 /* the block is from rows/columns k1 to k2-1 */
172 /* ------------------------------------------------------------------ */
177 PRINTF ("FACTOR BLOCK %d, k1 %d k2-1 %d nk %d\n", block
, k1
,k2
-1,nk
) ;
182 /* -------------------------------------------------------------- */
184 /* -------------------------------------------------------------- */
188 pend
= Ap
[oldcol
+1] ;
195 for (p
= Ap
[oldcol
] ; p
< pend
; p
++)
198 newrow
= Pinv
[oldrow
] ;
201 Offi
[poff
] = oldrow
;
202 Offx
[poff
] = Ax
[p
] ;
207 ASSERT (newrow
== k1
) ;
208 PRINTF ("singleton block %d", block
) ;
209 PRINT_ENTRY (Ax
[p
]) ;
216 /* row scaling. NOTE: scale factors are not yet permuted
217 * according to the pivot row permutation, so Rs [oldrow] is
218 * used below. When the factorization is done, the scale
219 * factors are permuted, so that Rs [newrow] will be used in
220 * klu_solve, klu_tsolve, and klu_rgrowth */
221 for (p
= Ap
[oldcol
] ; p
< pend
; p
++)
224 newrow
= Pinv
[oldrow
] ;
227 Offi
[poff
] = oldrow
;
228 //SCALE_DIV_ASSIGN (Offx [poff], Ax [p], Rs [oldrow]) ;
229 Offx
[poff
] = Ax
[p
] / Rs
[oldrow
] ;
234 ASSERT (newrow
== k1
) ;
235 PRINTF ("singleton block %d ", block
) ;
236 PRINT_ENTRY (Ax
[p
]) ;
237 //SCALE_DIV_ASSIGN (s, Ax [p], Rs [oldrow]) ;
238 s
= Ax
[p
] / Rs
[oldrow
] ;
247 /* singular singleton */
248 Common
.status
= KLU_SINGULAR
;
249 Common
.numerical_rank
= k1
;
250 Common
.singular_col
= oldcol
;
251 if (Common
.halt_if_singular
== 1)
266 /* -------------------------------------------------------------- */
267 /* construct and factorize the kth block */
268 /* -------------------------------------------------------------- */
272 /* COLAMD was used - no estimate of fill-in */
273 /* use 10 times the nnz in A, plus n */
274 lsize
= -(Common
.initmem
) ;
278 lsize
= Common
.initmem_amd
* Lnz
[block
] + nk
;
281 /* allocates 1 arrays: LUbx [block] */
282 Numeric
.LUsize
[block
] = klu_kernel_factor (
284 lsize
, LUbx
, block
, Udiag
, k1
, Llen
, k1
,
285 Ulen
, k1
, Lip
, k1
, Uip
, k1
, Pblock
, lnz_block
, unz_block
,
286 X
, Iwork
, k1
, Pinv
, Rs
, Offp
, Offi
, Offx
, Common
) ;
288 if (Common
.status
< KLU_OK
||
289 (Common
.status
== KLU_SINGULAR
&&
290 Common
.halt_if_singular
== 1))
292 /* out of memory, invalid inputs, or singular */
296 PRINTF ("\n----------------------- L %d:\n", block
) ;
297 ASSERT (klu_valid_LU (nk
, TRUE
, Lip
, k1
, Llen
, k1
, LUbx
[block
])) ;
298 PRINTF ("\n----------------------- U %d:\n", block
) ;
299 ASSERT (klu_valid_LU (nk
, FALSE
, Uip
, k1
, Ulen
, k1
, LUbx
[block
])) ;
301 /* -------------------------------------------------------------- */
303 /* -------------------------------------------------------------- */
305 // lnz += lnz_block ;
306 // unz += unz_block ;
307 // max_lnz_block = MAX (max_lnz_block, lnz_block) ;
308 // max_unz_block = MAX (max_unz_block, unz_block) ;
310 // if (Lnz [block] == EMPTY)
312 // /* revise estimate for subsequent factorization */
313 // Lnz [block] = MAX (lnz_block, unz_block) ;
316 /* -------------------------------------------------------------- */
317 /* combine the klu row ordering with the symbolic pre-ordering */
318 /* -------------------------------------------------------------- */
320 PRINTF ("Pnum, 1-based:\n") ;
321 for (k
= 0 ; k
< nk
; k
++)
323 ASSERT (k
+ k1
< n
) ;
324 ASSERT (Pblock
[k
] + k1
< n
) ;
325 Pnum
[k
+ k1
] = P
[Pblock
[k
] + k1
] ;
326 PRINTF ("Pnum (%d + %d + 1 = %d) = %d + 1 = %d\n",
327 k
, k1
, k
+k1
+1, Pnum
[k
+k1
], Pnum
[k
+k1
]+1) ;
330 /* the local pivot row permutation Pblock is no longer needed */
333 ASSERT (nzoff
== Offp
[n
]) ;
334 PRINTF ("\n------------------- Off diagonal entries:\n") ;
335 ASSERT (klu_valid (n
, Offp
, Offi
, Offx
)) ;
339 Numeric
.max_lnz_block
= max_lnz_block
;
340 Numeric
.max_unz_block
= max_unz_block
;
342 /* compute the inverse of Pnum */
345 for (k
= 0 ; k
< n
; k
++)
350 for (k
= 0 ; k
< n
; k
++)
352 ASSERT (Pnum
[k
] >= 0 && Pnum
[k
] < n
) ;
353 Pinv
[Pnum
[k
]] = k
;
357 for (k
= 0 ; k
< n
; k
++) ASSERT (Pinv
[k
] != EMPTY
) ;
360 /* permute scale factors Rs according to pivotal row order */
363 for (k
= 0 ; k
< n
; k
++)
365 X
[k
] = Rs
[Pnum
[k
]] ;
366 //REAL (X [k]) = Rs [Pnum [k]] ;
368 for (k
= 0 ; k
< n
; k
++)
370 Rs
[k
] = X
[k
] ; //REAL (X [k]) ;
374 PRINTF ("\n------------------- Off diagonal entries, old:\n") ;
375 ASSERT (klu_valid (n
, Offp
, Offi
, Offx
)) ;
377 /* apply the pivot row permutations to the off-diagonal entries */
378 for (p
= 0 ; p
< nzoff
; p
++)
380 ASSERT (Offi
[p
] >= 0 && Offi
[p
] < n
) ;
381 Offi
[p
] = Pinv
[Offi
[p
]] ;
384 PRINTF ("\n------------------- Off diagonal entries, new:\n") ;
385 ASSERT (klu_valid (n
, Offp
, Offi
, Offx
)) ;
389 PRINTF ("\n ############# KLU_BTF_FACTOR done, nblocks %d\n",
392 Udiag
= Numeric
.Udiag
;
393 for (block
= 0 ; block
< nblocks
&& Common
.status
== KLU_OK
; block
++)
398 PRINTF ("\n======================KLU_factor output: k1 %d k2 %d nk %d\n",k1
,k2
,nk
) ;
401 PRINTF ("singleton ") ;
402 /* ENTRY_PRINT (singleton [block]) ; */
408 // int[] Lip, Uip, Llen, Ulen ;
410 // Lip = Numeric.Lip + k1 ;
411 // Llen = Numeric.Llen + k1 ;
412 // LU = (double[]) Numeric.LUbx [block] ;
413 // PRINTF ("\n---- L block %d\n", block);
414 // ASSERT (klu_valid_LU (nk, TRUE, Lip, Llen, LU)) ;
415 // Uip = Numeric.Uip + k1 ;
416 // Ulen = Numeric.Ulen + k1 ;
417 // PRINTF ("\n---- U block %d\n", block) ;
418 // ASSERT (klu_valid_LU (nk, FALSE, Uip, Ulen, LU)) ;
426 * @param Ap size n+1, column pointers
427 * @param Ai size nz, row indices
431 * @return null if error, or a valid KLU_numeric object if successful
433 public static KLU_numeric
klu_factor(int[] Ap
, int[] Ai
, double[] Ax
,
434 KLU_symbolic Symbolic
, KLU_common Common
)
436 int n
, nzoff
, nblocks
, maxblock
, k
;
437 int[] ok
= new int [] {TRUE
} ;
439 KLU_numeric Numeric
;
440 int n1
, nzoff1
, s
, b6
, n3
;
446 Common
.status
= KLU_OK
;
447 Common
.numerical_rank
= EMPTY
;
448 Common
.singular_col
= EMPTY
;
450 /* ---------------------------------------------------------------------- */
451 /* get the contents of the Symbolic object */
452 /* ---------------------------------------------------------------------- */
454 /* check for a valid Symbolic object */
455 if (Symbolic
== null)
457 Common
.status
= KLU_INVALID
;
462 nzoff
= Symbolic
.nzoff
;
463 nblocks
= Symbolic
.nblocks
;
464 maxblock
= Symbolic
.maxblock
;
466 PRINTF ("KLU_factor: n %d nzoff %d nblocks %d maxblock %d\n",
467 n
, nzoff
, nblocks
, maxblock
) ;
469 /* ---------------------------------------------------------------------- */
470 /* get control parameters and make sure they are in the proper range */
471 /* ---------------------------------------------------------------------- */
473 Common
.initmem_amd
= MAX (1.0, Common
.initmem_amd
) ;
474 Common
.initmem
= MAX (1.0, Common
.initmem
) ;
475 Common
.tol
= MIN (Common
.tol
, 1.0) ;
476 Common
.tol
= MAX (0.0, Common
.tol
) ;
477 Common
.memgrow
= MAX (1.0, Common
.memgrow
) ;
479 /* ---------------------------------------------------------------------- */
480 /* allocate the Numeric object */
481 /* ---------------------------------------------------------------------- */
483 /* this will not cause int overflow (already checked by KLU_symbolic) */
487 //Numeric = Dklu_memory.klu_malloc (sizeof (KLU_numeric), 1, Common) ;
490 Numeric
= new KLU_numeric();
492 catch (OutOfMemoryError e
)
494 Common
.status
= KLU_OUT_OF_MEMORY
;
498 Numeric
.nblocks
= nblocks
;
499 Numeric
.nzoff
= nzoff
;
500 Numeric
.Pnum
= klu_malloc_int (n
, Common
) ;
501 Numeric
.Offp
= klu_malloc_int (n1
, Common
) ;
502 Numeric
.Offi
= klu_malloc_int (nzoff1
, Common
) ;
503 Numeric
.Offx
= klu_malloc_dbl (nzoff1
, Common
) ;
505 Numeric
.Lip
= klu_malloc_int (n
, Common
) ;
506 Numeric
.Uip
= klu_malloc_int (n
, Common
) ;
507 Numeric
.Llen
= klu_malloc_int (n
, Common
) ;
508 Numeric
.Ulen
= klu_malloc_int (n
, Common
) ;
510 Numeric
.LUsize
= klu_malloc_int (nblocks
, Common
) ;
512 //Numeric.LUbx = klu_malloc (nblocks, sizeof (double[]), Common) ;
513 Numeric
.LUbx
= new double [nblocks
][] ;
514 if (Numeric
.LUbx
!= null)
516 for (k
= 0 ; k
< nblocks
; k
++)
518 Numeric
.LUbx
[k
] = null ;
522 Numeric
.Udiag
= klu_malloc_dbl (n
, Common
) ;
524 if (Common
.scale
> 0)
526 Numeric
.Rs
= klu_malloc_dbl (n
, Common
) ;
534 Numeric
.Pinv
= klu_malloc_int (n
, Common
) ;
536 /* allocate permanent workspace for factorization and solve. Note that the
537 * solver will use an Xwork of size 4n, whereas the factorization codes use
538 * an Xwork of size n and integer space (Iwork) of size 6n. KLU_condest
539 * uses an Xwork of size 2n. Total size is:
541 * n*sizeof(double) + max (6*maxblock*sizeof(Int), 3*n*sizeof(double))
543 //s = klu_mult_size_t (n, sizeof (double), ok) ;
545 //n3 = klu_mult_size_t (n, 3 * sizeof (double), ok) ;
547 //b6 = klu_mult_size_t (maxblock, 6 * sizeof (Int), ok) ;
549 Numeric
.worksize
= klu_add_size_t (s
, MAX (n3
, b6
), ok
) ;
552 if (ok
[0] == 0) throw new OutOfMemoryError() ;
554 //Numeric.Work = klu_malloc (Numeric.worksize, 1, Common) ;
555 Numeric
.Work
= new double [Numeric
.worksize
] ;
556 Numeric
.Xwork
= Numeric
.Work
;
557 //Numeric.Iwork = (Int[]) ((double[]) Numeric.Xwork + n) ;
558 Numeric
.Iwork
= new int [b6
] ;
560 catch (OutOfMemoryError e
)
562 /* out of memory or problem too large */
563 Common
.status
= ok
[0] == 1 ? KLU_OUT_OF_MEMORY
: KLU_TOO_LARGE
;
564 //klu_free_numeric (Numeric, Common) ;
569 /* ---------------------------------------------------------------------- */
570 /* factorize the blocks */
571 /* ---------------------------------------------------------------------- */
573 factor2 (Ap
, Ai
, Ax
, Symbolic
, Numeric
, Common
) ;
575 /* ---------------------------------------------------------------------- */
576 /* return or free the Numeric object */
577 /* ---------------------------------------------------------------------- */
579 if (Common
.status
< KLU_OK
)
581 /* out of memory or inputs invalid */
582 // klu_free_numeric (Numeric, Common) ;
585 else if (Common
.status
== KLU_SINGULAR
)
587 if (Common
.halt_if_singular
== 1)
589 /* Matrix is singular, and the Numeric object is only partially
590 * defined because we halted early. This is the default case for
591 * a singular matrix. */
593 // klu_free_numeric (Numeric, Common) ;
597 else if (Common
.status
== KLU_OK
)
599 /* successful non-singular factorization */
600 Common
.numerical_rank
= n
;
601 Common
.singular_col
= n
;