Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_klu_refactor.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === KLU_refactor ========================================================= */
3 /* ========================================================================== */
4 
5 /* Factor the matrix, after ordering and analyzing it with KLU_analyze, and
6  * factoring it once with KLU_factor. This routine cannot do any numerical
7  * pivoting. The pattern of the input matrix (Ap, Ai) must be identical to
8  * the pattern given to KLU_factor.
9  */
10 
11 #include "amesos_klu_internal.h"
12 
13 
14 /* ========================================================================== */
15 /* === KLU_refactor ========================================================= */
16 /* ========================================================================== */
17 
18 Int KLU_refactor /* returns TRUE if successful, FALSE otherwise */
19 (
20  /* inputs, not modified */
21  Int Ap [ ], /* size n+1, column pointers */
22  Int Ai [ ], /* size nz, row indices */
23  double Ax [ ],
24  KLU_symbolic *Symbolic,
25 
26  /* input/output */
27  KLU_numeric *Numeric,
28  KLU_common *Common
29 )
30 {
31  Entry ukk, ujk, s ;
32  Entry *Offx, *Lx, *Ux, *X, *Az, *Udiag ;
33  double *Rs ;
34  Int *P, *Q, *R, *Pnum, *Offp, *Offi, *Ui, *Li, *Pinv, *Lip, *Uip, *Llen,
35  *Ulen ;
36  Unit **LUbx ;
37  Unit *LU ;
38  Int k1, k2, nk, k, block, oldcol, pend, oldrow, n, p, newrow, scale,
39  nblocks, poff, i, j, up, ulen, llen, maxblock, nzoff ;
40 
41  /* ---------------------------------------------------------------------- */
42  /* check inputs */
43  /* ---------------------------------------------------------------------- */
44 
45  if (Common == NULL)
46  {
47  return (FALSE) ;
48  }
49  Common->status = KLU_OK ;
50 
51  if (Numeric == NULL)
52  {
53  /* invalid Numeric object */
54  Common->status = KLU_INVALID ;
55  return (FALSE) ;
56  }
57 
58  Common->numerical_rank = EMPTY ;
59  Common->singular_col = EMPTY ;
60 
61  Az = (Entry *) Ax ;
62 
63  /* ---------------------------------------------------------------------- */
64  /* get the contents of the Symbolic object */
65  /* ---------------------------------------------------------------------- */
66 
67  n = Symbolic->n ;
68  P = Symbolic->P ;
69  Q = Symbolic->Q ;
70  R = Symbolic->R ;
71  nblocks = Symbolic->nblocks ;
72  maxblock = Symbolic->maxblock ;
73 
74  /* ---------------------------------------------------------------------- */
75  /* get the contents of the Numeric object */
76  /* ---------------------------------------------------------------------- */
77 
78  Pnum = Numeric->Pnum ;
79  Offp = Numeric->Offp ;
80  Offi = Numeric->Offi ;
81  Offx = (Entry *) Numeric->Offx ;
82 
83  LUbx = (Unit **) Numeric->LUbx ;
84 
85  scale = Common->scale ;
86  if (scale > 0)
87  {
88  /* factorization was not scaled, but refactorization is scaled */
89  if (Numeric->Rs == NULL)
90  {
91  Numeric->Rs = KLU_malloc (n, sizeof (double), Common) ;
92  if (Common->status < KLU_OK)
93  {
94  Common->status = KLU_OUT_OF_MEMORY ;
95  return (FALSE) ;
96  }
97  }
98  }
99  else
100  {
101  /* no scaling for refactorization; ensure Numeric->Rs is freed. This
102  * does nothing if Numeric->Rs is already NULL. */
103  Numeric->Rs = KLU_free (Numeric->Rs, n, sizeof (double), Common) ;
104  }
105  Rs = Numeric->Rs ;
106 
107  Pinv = Numeric->Pinv ;
108  X = (Entry *) Numeric->Xwork ;
109  Common->nrealloc = 0 ;
110  Udiag = Numeric->Udiag ;
111  nzoff = Symbolic->nzoff ;
112 
113  /* ---------------------------------------------------------------------- */
114  /* check the input matrix compute the row scale factors, Rs */
115  /* ---------------------------------------------------------------------- */
116 
117  /* do no scale, or check the input matrix, if scale < 0 */
118  if (scale >= 0)
119  {
120  /* check for out-of-range indices, but do not check for duplicates */
121  if (!KLU_scale (scale, n, Ap, Ai, Ax, Rs, NULL, Common))
122  {
123  return (FALSE) ;
124  }
125  }
126 
127  /* ---------------------------------------------------------------------- */
128  /* clear workspace X */
129  /* ---------------------------------------------------------------------- */
130 
131  for (k = 0 ; k < maxblock ; k++)
132  {
133  /* X [k] = 0 */
134  CLEAR (X [k]) ;
135  }
136 
137  poff = 0 ;
138 
139  /* ---------------------------------------------------------------------- */
140  /* factor each block */
141  /* ---------------------------------------------------------------------- */
142 
143  if (scale <= 0)
144  {
145 
146  /* ------------------------------------------------------------------ */
147  /* no scaling */
148  /* ------------------------------------------------------------------ */
149 
150  for (block = 0 ; block < nblocks ; block++)
151  {
152 
153  /* -------------------------------------------------------------- */
154  /* the block is from rows/columns k1 to k2-1 */
155  /* -------------------------------------------------------------- */
156 
157  k1 = R [block] ;
158  k2 = R [block+1] ;
159  nk = k2 - k1 ;
160 
161  if (nk == 1)
162  {
163 
164  /* ---------------------------------------------------------- */
165  /* singleton case */
166  /* ---------------------------------------------------------- */
167 
168  oldcol = Q [k1] ;
169  pend = Ap [oldcol+1] ;
170  CLEAR (s) ;
171  for (p = Ap [oldcol] ; p < pend ; p++)
172  {
173  newrow = Pinv [Ai [p]] - k1 ;
174  if (newrow < 0 && poff < nzoff)
175  {
176  /* entry in off-diagonal block */
177  Offx [poff] = Az [p] ;
178  poff++ ;
179  }
180  else
181  {
182  /* singleton */
183  s = Az [p] ;
184  }
185  }
186  Udiag [k1] = s ;
187 
188  }
189  else
190  {
191 
192  /* ---------------------------------------------------------- */
193  /* construct and factor the kth block */
194  /* ---------------------------------------------------------- */
195 
196  Lip = Numeric->Lip + k1 ;
197  Llen = Numeric->Llen + k1 ;
198  Uip = Numeric->Uip + k1 ;
199  Ulen = Numeric->Ulen + k1 ;
200  LU = LUbx [block] ;
201 
202  for (k = 0 ; k < nk ; k++)
203  {
204 
205  /* ------------------------------------------------------ */
206  /* scatter kth column of the block into workspace X */
207  /* ------------------------------------------------------ */
208 
209  oldcol = Q [k+k1] ;
210  pend = Ap [oldcol+1] ;
211  for (p = Ap [oldcol] ; p < pend ; p++)
212  {
213  newrow = Pinv [Ai [p]] - k1 ;
214  if (newrow < 0 && poff < nzoff)
215  {
216  /* entry in off-diagonal block */
217  Offx [poff] = Az [p] ;
218  poff++ ;
219  }
220  else
221  {
222  /* (newrow,k) is an entry in the block */
223  X [newrow] = Az [p] ;
224  }
225  }
226 
227  /* ------------------------------------------------------ */
228  /* compute kth column of U, and update kth column of A */
229  /* ------------------------------------------------------ */
230 
231  GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ;
232  for (up = 0 ; up < ulen ; up++)
233  {
234  j = Ui [up] ;
235  ujk = X [j] ;
236  /* X [j] = 0 */
237  CLEAR (X [j]) ;
238  Ux [up] = ujk ;
239  GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ;
240  for (p = 0 ; p < llen ; p++)
241  {
242  /* X [Li [p]] -= Lx [p] * ujk */
243  MULT_SUB (X [Li [p]], Lx [p], ujk) ;
244  }
245  }
246  /* get the diagonal entry of U */
247  ukk = X [k] ;
248  /* X [k] = 0 */
249  CLEAR (X [k]) ;
250  /* singular case */
251  if (IS_ZERO (ukk))
252  {
253  /* matrix is numerically singular */
254  Common->status = KLU_SINGULAR ;
255  if (Common->numerical_rank == EMPTY)
256  {
257  Common->numerical_rank = k+k1 ;
258  Common->singular_col = Q [k+k1] ;
259  }
260  if (Common->halt_if_singular)
261  {
262  /* do not continue the factorization */
263  return (FALSE) ;
264  }
265  }
266  Udiag [k+k1] = ukk ;
267  /* gather and divide by pivot to get kth column of L */
268  GET_POINTER (LU, Lip, Llen, Li, Lx, k, llen) ;
269  for (p = 0 ; p < llen ; p++)
270  {
271  i = Li [p] ;
272  DIV (Lx [p], X [i], ukk) ;
273  CLEAR (X [i]) ;
274  }
275 
276  }
277  }
278  }
279 
280  }
281  else
282  {
283 
284  /* ------------------------------------------------------------------ */
285  /* scaling */
286  /* ------------------------------------------------------------------ */
287 
288  for (block = 0 ; block < nblocks ; block++)
289  {
290 
291  /* -------------------------------------------------------------- */
292  /* the block is from rows/columns k1 to k2-1 */
293  /* -------------------------------------------------------------- */
294 
295  k1 = R [block] ;
296  k2 = R [block+1] ;
297  nk = k2 - k1 ;
298 
299  if (nk == 1)
300  {
301 
302  /* ---------------------------------------------------------- */
303  /* singleton case */
304  /* ---------------------------------------------------------- */
305 
306  oldcol = Q [k1] ;
307  pend = Ap [oldcol+1] ;
308  CLEAR (s) ;
309  for (p = Ap [oldcol] ; p < pend ; p++)
310  {
311  oldrow = Ai [p] ;
312  newrow = Pinv [oldrow] - k1 ;
313  if (newrow < 0 && poff < nzoff)
314  {
315  /* entry in off-diagonal block */
316  /* Offx [poff] = Az [p] / Rs [oldrow] */
317  SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]) ;
318  poff++ ;
319  }
320  else
321  {
322  /* singleton */
323  /* s = Az [p] / Rs [oldrow] */
324  SCALE_DIV_ASSIGN (s, Az [p], Rs [oldrow]) ;
325  }
326  }
327  Udiag [k1] = s ;
328 
329  }
330  else
331  {
332 
333  /* ---------------------------------------------------------- */
334  /* construct and factor the kth block */
335  /* ---------------------------------------------------------- */
336 
337  Lip = Numeric->Lip + k1 ;
338  Llen = Numeric->Llen + k1 ;
339  Uip = Numeric->Uip + k1 ;
340  Ulen = Numeric->Ulen + k1 ;
341  LU = LUbx [block] ;
342 
343  for (k = 0 ; k < nk ; k++)
344  {
345 
346  /* ------------------------------------------------------ */
347  /* scatter kth column of the block into workspace X */
348  /* ------------------------------------------------------ */
349 
350  oldcol = Q [k+k1] ;
351  pend = Ap [oldcol+1] ;
352  for (p = Ap [oldcol] ; p < pend ; p++)
353  {
354  oldrow = Ai [p] ;
355  newrow = Pinv [oldrow] - k1 ;
356  if (newrow < 0 && poff < nzoff)
357  {
358  /* entry in off-diagonal part */
359  /* Offx [poff] = Az [p] / Rs [oldrow] */
360  SCALE_DIV_ASSIGN (Offx [poff], Az [p], Rs [oldrow]);
361  poff++ ;
362  }
363  else
364  {
365  /* (newrow,k) is an entry in the block */
366  /* X [newrow] = Az [p] / Rs [oldrow] */
367  SCALE_DIV_ASSIGN (X [newrow], Az [p], Rs [oldrow]) ;
368  }
369  }
370 
371  /* ------------------------------------------------------ */
372  /* compute kth column of U, and update kth column of A */
373  /* ------------------------------------------------------ */
374 
375  GET_POINTER (LU, Uip, Ulen, Ui, Ux, k, ulen) ;
376  for (up = 0 ; up < ulen ; up++)
377  {
378  j = Ui [up] ;
379  ujk = X [j] ;
380  /* X [j] = 0 */
381  CLEAR (X [j]) ;
382  Ux [up] = ujk ;
383  GET_POINTER (LU, Lip, Llen, Li, Lx, j, llen) ;
384  for (p = 0 ; p < llen ; p++)
385  {
386  /* X [Li [p]] -= Lx [p] * ujk */
387  MULT_SUB (X [Li [p]], Lx [p], ujk) ;
388  }
389  }
390  /* get the diagonal entry of U */
391  ukk = X [k] ;
392  /* X [k] = 0 */
393  CLEAR (X [k]) ;
394  /* singular case */
395  if (IS_ZERO (ukk))
396  {
397  /* matrix is numerically singular */
398  Common->status = KLU_SINGULAR ;
399  if (Common->numerical_rank == EMPTY)
400  {
401  Common->numerical_rank = k+k1 ;
402  Common->singular_col = Q [k+k1] ;
403  }
404  if (Common->halt_if_singular)
405  {
406  /* do not continue the factorization */
407  return (FALSE) ;
408  }
409  }
410  Udiag [k+k1] = ukk ;
411  /* gather and divide by pivot to get kth column of L */
412  GET_POINTER (LU, Lip, Llen, Li, Lx, k, llen) ;
413  for (p = 0 ; p < llen ; p++)
414  {
415  i = Li [p] ;
416  DIV (Lx [p], X [i], ukk) ;
417  CLEAR (X [i]) ;
418  }
419  }
420  }
421  }
422  }
423 
424  /* ---------------------------------------------------------------------- */
425  /* permute scale factors Rs according to pivotal row order */
426  /* ---------------------------------------------------------------------- */
427 
428  if (scale > 0)
429  {
430  for (k = 0 ; k < n ; k++)
431  {
432  REAL (X [k]) = Rs [Pnum [k]] ;
433  }
434  for (k = 0 ; k < n ; k++)
435  {
436  Rs [k] = REAL (X [k]) ;
437  }
438  }
439 
440 #ifndef NDEBUG
441  ASSERT (Offp [n] == poff) ;
442  ASSERT (Symbolic->nzoff == poff) ;
443  PRINTF (("\n------------------- Off diagonal entries, new:\n")) ;
444  ASSERT (KLU_valid (n, Offp, Offi, Offx)) ;
445  if (Common->status == KLU_OK)
446  {
447  PRINTF (("\n ########### KLU_BTF_REFACTOR done, nblocks %d\n",nblocks));
448  for (block = 0 ; block < nblocks ; block++)
449  {
450  k1 = R [block] ;
451  k2 = R [block+1] ;
452  nk = k2 - k1 ;
453  PRINTF ((
454  "\n================KLU_refactor output: k1 %d k2 %d nk %d\n",
455  k1, k2, nk)) ;
456  if (nk == 1)
457  {
458  PRINTF (("singleton ")) ;
459  PRINT_ENTRY (Udiag [k1]) ;
460  }
461  else
462  {
463  Lip = Numeric->Lip + k1 ;
464  Llen = Numeric->Llen + k1 ;
465  LU = (Unit *) Numeric->LUbx [block] ;
466  PRINTF (("\n---- L block %d\n", block)) ;
467  ASSERT (KLU_valid_LU (nk, TRUE, Lip, Llen, LU)) ;
468  Uip = Numeric->Uip + k1 ;
469  Ulen = Numeric->Ulen + k1 ;
470  PRINTF (("\n---- U block %d\n", block)) ;
471  ASSERT (KLU_valid_LU (nk, FALSE, Uip, Ulen, LU)) ;
472  }
473  }
474  }
475 #endif
476 
477  return (TRUE) ;
478 }
#define GET_POINTER(LU, Xip, Xlen, Xi, Xx, k, xlen)
#define REAL
#define KLU_INVALID
#define PRINT_ENTRY(a)
#define EMPTY
Int KLU_refactor(Int Ap[], Int Ai[], double Ax[], KLU_symbolic *Symbolic, KLU_numeric *Numeric, KLU_common *Common)
#define KLU_symbolic
#define Int
#define FALSE
#define P(k)
double Unit
#define KLU_OUT_OF_MEMORY
#define NULL
#define CLEAR(c)
#define ASSERT(expression)
#define MULT_SUB(c, a, b)
#define KLU_numeric
#define KLU_valid_LU
#define KLU_malloc
#define IS_ZERO(x)
#define SCALE_DIV_ASSIGN(a, c, s)
#define KLU_scale
#define KLU_valid
#define DIV(c, a, b)
#define KLU_common
#define KLU_SINGULAR
#define Entry
#define PRINTF(params)
int n
#define TRUE
#define KLU_free
#define KLU_OK