[maven-release-plugin] prepare for next development iteration
[JKLU.git] / src / main / java / edu / ufl / cise / klu / tdouble / Dklu_refactor.java
blobcc34ae9e04824f59d9a70090761074de246512b1
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_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;
36 /**
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 {
44 /**
46 * @param Ap size n+1, column pointers
47 * @param Ai size nz, row indices
48 * @param Ax
49 * @param Symbolic
50 * @param Numeric
51 * @param Common
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)
57 double ukk, ujk, s ;
58 double[] Offx, Lx, Ux, X, Az, Udiag ;
59 double[] Rs ;
60 int[] Q, R, Pnum, Offp, Offi, Pinv, Lip, Uip, Llen, Ulen ;
61 /*int[]*/double[] Ui, Li ;
62 double[][] LUbx ;
63 double[] LU ;
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 /* ---------------------------------------------------------------------- */
74 /* check inputs */
75 /* ---------------------------------------------------------------------- */
77 if (Common == null)
79 return (FALSE) ;
81 Common.status = KLU_OK ;
83 if (Numeric == null)
85 /* invalid Numeric object */
86 Common.status = KLU_INVALID ;
87 return (FALSE) ;
90 Common.numerical_rank = EMPTY ;
91 Common.singular_col = EMPTY ;
93 Az = (double[]) Ax ;
95 /* ---------------------------------------------------------------------- */
96 /* get the contents of the Symbolic object */
97 /* ---------------------------------------------------------------------- */
99 n = Symbolic.n ;
100 Q = Symbolic.Q ;
101 R = Symbolic.R ;
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 ;
117 if (scale > 0)
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 ;
126 return (FALSE) ;
130 else
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) ;
135 Numeric.Rs = null ;
137 Rs = Numeric.Rs ;
139 Pinv = Numeric.Pinv ;
140 X = Numeric.Xwork ;
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 */
150 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)
155 return (FALSE) ;
159 /* ---------------------------------------------------------------------- */
160 /* clear workspace X */
161 /* ---------------------------------------------------------------------- */
163 for (k = 0 ; k < maxblock ; k++)
165 /* X [k] = 0 ; */
166 CLEAR (X, k) ;
169 poff = 0 ;
171 /* ---------------------------------------------------------------------- */
172 /* factor each block */
173 /* ---------------------------------------------------------------------- */
175 if (scale <= 0)
178 /* ------------------------------------------------------------------ */
179 /* no scaling */
180 /* ------------------------------------------------------------------ */
182 for (block = 0 ; block < nblocks ; block++)
185 /* -------------------------------------------------------------- */
186 /* the block is from rows/columns k1 to k2-1 */
187 /* -------------------------------------------------------------- */
189 k1 = R [block] ;
190 k2 = R [block+1] ;
191 nk = k2 - k1 ;
193 if (nk == 1)
196 /* ---------------------------------------------------------- */
197 /* singleton case */
198 /* ---------------------------------------------------------- */
200 oldcol = Q [k1] ;
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] ;
210 poff++ ;
212 else
214 /* singleton */
215 s = Az [p] ;
218 Udiag [k1] = s ;
221 else
224 /* ---------------------------------------------------------- */
225 /* construct and factor the kth block */
226 /* ---------------------------------------------------------- */
228 Lip = Numeric.Lip ;
229 int Lip_offset = k1 ;
230 Llen = Numeric.Llen ;
231 int Llen_offset = k1 ;
232 Uip = Numeric.Uip ;
233 int Uip_offset = k1 ;
234 Ulen = Numeric.Ulen ;
235 int Ulen_offset = k1 ;
236 LU = LUbx [block] ;
238 for (k = 0 ; k < nk ; k++)
241 /* ------------------------------------------------------ */
242 /* scatter kth column of the block into workspace X */
243 /* ------------------------------------------------------ */
245 oldcol = Q [k+k1] ;
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] ;
254 poff++ ;
256 else
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] ;
272 ujk = X [j] ;
273 /* X [j] = 0 ; */
274 CLEAR (X, j) ;
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 */
285 ukk = X [k] ;
286 /* X [k] = 0 ; */
287 CLEAR (X, k) ;
288 /* singular case */
289 if (IS_ZERO (ukk))
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 */
301 return (FALSE) ;
304 Udiag [k+k1] = ukk ;
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 ;
313 CLEAR (X, i) ;
321 else
324 /* ------------------------------------------------------------------ */
325 /* scaling */
326 /* ------------------------------------------------------------------ */
328 for (block = 0 ; block < nblocks ; block++)
331 /* -------------------------------------------------------------- */
332 /* the block is from rows/columns k1 to k2-1 */
333 /* -------------------------------------------------------------- */
335 k1 = R [block] ;
336 k2 = R [block+1] ;
337 nk = k2 - k1 ;
339 if (nk == 1)
342 /* ---------------------------------------------------------- */
343 /* singleton case */
344 /* ---------------------------------------------------------- */
346 oldcol = Q [k1] ;
347 pend = Ap [oldcol+1] ;
348 s = 0 ; //CLEAR (s) ;
349 for (p = Ap [oldcol] ; p < pend ; p++)
351 oldrow = Ai [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]) ;
358 poff++ ;
360 else
362 /* singleton */
363 s = Az [p] / Rs [oldrow] ;
364 //SCALE_DIV_ASSIGN (s, Az [p], Rs [oldrow]) ;
367 Udiag [k1] = s ;
370 else
373 /* ---------------------------------------------------------- */
374 /* construct and factor the kth block */
375 /* ---------------------------------------------------------- */
377 Lip = Numeric.Lip ;
378 int Lip_offset = k1 ;
379 Llen = Numeric.Llen ;
380 int Llen_offset = k1 ;
381 Uip = Numeric.Uip ;
382 int Uip_offset = k1 ;
383 Ulen = Numeric.Ulen ;
384 int Ulen_offset = k1 ;
385 LU = LUbx [block] ;
387 for (k = 0 ; k < nk ; k++)
390 /* ------------------------------------------------------ */
391 /* scatter kth column of the block into workspace X */
392 /* ------------------------------------------------------ */
394 oldcol = Q [k+k1] ;
395 pend = Ap [oldcol+1] ;
396 for (p = Ap [oldcol] ; p < pend ; p++)
398 oldrow = Ai [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] ;
405 poff++ ;
407 else
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] ;
424 ujk = X [j] ;
425 /* X [j] = 0 ; */
426 CLEAR (X, j) ;
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 */
437 ukk = X [k] ;
438 /* X [k] = 0 ; */
439 CLEAR (X, k) ;
440 /* singular case */
441 if (IS_ZERO (ukk))
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 */
453 return (FALSE) ;
456 Udiag [k+k1] = ukk ;
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 ;
465 CLEAR (X, i) ;
472 /* ---------------------------------------------------------------------- */
473 /* permute scale factors Rs according to pivotal row order */
474 /* ---------------------------------------------------------------------- */
476 if (scale > 0)
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++)
485 Rs [k] = X [k] ;
486 //Rs [k] = REAL (X [k]) ;
490 if (!NDEBUG)
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",
499 nblocks);
500 for (block = 0 ; block < nblocks ; block++)
502 k1 = R [block] ;
503 k2 = R [block+1] ;
504 nk = k2 - k1 ;
505 PRINTF (
506 "\n================KLU_refactor output: k1 %d k2 %d nk %d\n",
507 k1, k2, nk) ;
508 if (nk == 1)
510 PRINTF ("singleton ") ;
511 PRINT_ENTRY (Udiag [k1]) ;
513 else
515 Lip = Numeric.Lip ;
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)) ;
522 Uip = Numeric.Uip ;
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)) ;
533 return (TRUE) ;