Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_t_cholmod_rowfac.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === Cholesky/t_cholmod_rowfac ============================================ */
3 /* ========================================================================== */
4 
5 /* -----------------------------------------------------------------------------
6  * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis
7  * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
8  * Lesser General Public License. See lesser.txt for a text of the license.
9  * CHOLMOD is also available under other licenses; contact authors for details.
10  * http://www.cise.ufl.edu/research/sparse
11  * -------------------------------------------------------------------------- */
12 
13 /* Template routine for cholmod_rowfac. Supports any numeric xtype
14  * (real, complex, or zomplex).
15  *
16  * workspace: Iwork (n), Flag (n), Xwork (n if real, 2*n if complex)
17  */
18 
20 
21 #ifdef MASK
22 static int TEMPLATE (cholmod_rowfac_mask)
23 #else
24 static int TEMPLATE (cholmod_rowfac)
25 #endif
26 (
27  /* ---- input ---- */
28  cholmod_sparse *A, /* matrix to factorize */
29  cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */
30  double beta [2], /* factorize beta*I+A or beta*I+AA' (beta [0] only) */
31  size_t kstart, /* first row to factorize */
32  size_t kend, /* last row to factorize is kend-1 */
33 #ifdef MASK
34  /* These inputs are used for cholmod_rowfac_mask only */
35  Int *mask, /* size A->nrow. if mask[i] then W(i) is set to zero */
36  Int *RLinkUp, /* size A->nrow. link list of rows to compute */
37 #endif
38  /* ---- in/out --- */
39  cholmod_factor *L,
40  /* --------------- */
41  cholmod_common *Common
42 )
43 {
44  double yx [2], lx [2], fx [2], dk [1], di [1], fl = 0 ;
45 #ifdef ZOMPLEX
46  double yz [1], lz [1], fz [1] ;
47 #endif
48  double *Ax, *Az, *Lx, *Lz, *Wx, *Wz, *Fx, *Fz ;
49  Int *Ap, *Anz, *Ai, *Lp, *Lnz, *Li, *Lnext, *Flag, *Stack, *Fp, *Fi, *Fnz,
50  *Iwork ;
51  Int i, p, k, t, pf, pfend, top, s, mark, pend, n, lnz, is_ll, multadds,
52  use_dbound, packed, stype, Fpacked, sorted, nzmax, len, parent ;
53 #ifndef REAL
54  Int dk_imaginary ;
55 #endif
56 
57  /* ---------------------------------------------------------------------- */
58  /* get inputs */
59  /* ---------------------------------------------------------------------- */
60 
61  PRINT1 (("\nin cholmod_rowfac, kstart %d kend %d stype %d\n",
62  kstart, kend, A->stype)) ;
63  DEBUG (CHOLMOD(dump_factor) (L, "Initial L", Common)) ;
64 
65  n = A->nrow ;
66  stype = A->stype ;
67 
68  if (stype > 0)
69  {
70  /* symmetric upper case: F is not needed. It may be NULL */
71  Fp = NULL ;
72  Fi = NULL ;
73  Fx = NULL ;
74  Fz = NULL ;
75  Fnz = NULL ;
76  Fpacked = TRUE ;
77  }
78  else
79  {
80  /* unsymmetric case: F is required. */
81  Fp = F->p ;
82  Fi = F->i ;
83  Fx = F->x ;
84  Fz = F->z ;
85  Fnz = F->nz ;
86  Fpacked = F->packed ;
87  }
88 
89  Ap = A->p ; /* size A->ncol+1, column pointers of A */
90  Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */
91  Ax = A->x ; /* size nz, numeric values of A */
92  Az = A->z ;
93  Anz = A->nz ;
94  packed = A->packed ;
95  sorted = A->sorted ;
96 
97  use_dbound = IS_GT_ZERO (Common->dbound) ;
98 
99  /* get the current factors L (and D for LDL'); allocate space if needed */
100  is_ll = L->is_ll ;
101  if (L->xtype == CHOLMOD_PATTERN)
102  {
103  /* ------------------------------------------------------------------ */
104  /* L is symbolic only; allocate and initialize L (and D for LDL') */
105  /* ------------------------------------------------------------------ */
106 
107  /* workspace: none */
108  CHOLMOD(change_factor) (A->xtype, is_ll, FALSE, FALSE, TRUE, L, Common);
109  if (Common->status < CHOLMOD_OK)
110  {
111  /* out of memory */
112  return (FALSE) ;
113  }
114  ASSERT (L->minor == (size_t) n) ;
115  }
116  else if (kstart == 0 && kend == (size_t) n)
117  {
118  /* ------------------------------------------------------------------ */
119  /* refactorization; reset L->nz and L->minor to restart factorization */
120  /* ------------------------------------------------------------------ */
121 
122  L->minor = n ;
123  Lnz = L->nz ;
124  for (k = 0 ; k < n ; k++)
125  {
126  Lnz [k] = 1 ;
127  }
128  }
129 
130  ASSERT (is_ll == L->is_ll) ;
131  ASSERT (L->xtype != CHOLMOD_PATTERN) ;
132  DEBUG (CHOLMOD(dump_factor) (L, "L ready", Common)) ;
133  DEBUG (CHOLMOD(dump_sparse) (A, "A ready", Common)) ;
134  DEBUG (if (stype == 0) CHOLMOD(dump_sparse) (F, "F ready", Common)) ;
135 
136  /* inputs, can be modified on output: */
137  Lp = L->p ; /* size n+1 */
138  ASSERT (Lp != NULL) ;
139 
140  /* outputs, contents defined on input for incremental case only: */
141  Lnz = L->nz ; /* size n */
142  Lnext = L->next ; /* size n+2 */
143  Li = L->i ; /* size L->nzmax, can change in size */
144  Lx = L->x ; /* size L->nzmax or 2*L->nzmax, can change in size */
145  Lz = L->z ; /* size L->nzmax for zomplex case, can change in size */
146  nzmax = L->nzmax ;
147  ASSERT (Lnz != NULL && Li != NULL && Lx != NULL) ;
148 
149  /* ---------------------------------------------------------------------- */
150  /* get workspace */
151  /* ---------------------------------------------------------------------- */
152 
153  Iwork = Common->Iwork ;
154  Stack = Iwork ; /* size n (i/i/l) */
155  Flag = Common->Flag ; /* size n, Flag [i] < mark must hold */
156  Wx = Common->Xwork ; /* size n if real, 2*n if complex or
157  * zomplex. Xwork [i] == 0 must hold. */
158  Wz = Wx + n ; /* size n for zomplex case only */
159  mark = Common->mark ;
160  ASSERT ((Int) Common->xworksize >= (L->xtype == CHOLMOD_REAL ? 1:2)*n) ;
161 
162  /* ---------------------------------------------------------------------- */
163  /* compute LDL' or LL' factorization by rows */
164  /* ---------------------------------------------------------------------- */
165 
166 #ifdef MASK
167 #define NEXT(k) k = RLinkUp [k]
168 #else
169 #define NEXT(k) k++
170 #endif
171 
172  for (k = kstart ; k < ((Int) kend) ; NEXT(k))
173  {
174  PRINT1 (("\n===============K "ID" Lnz [k] "ID"\n", k, Lnz [k])) ;
175 
176  /* ------------------------------------------------------------------ */
177  /* compute pattern of kth row of L and scatter kth input column */
178  /* ------------------------------------------------------------------ */
179 
180  /* column k of L is currently empty */
181  ASSERT (Lnz [k] == 1) ;
182  ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
183 
184  top = n ; /* Stack is empty */
185  Flag [k] = mark ; /* do not include diagonal entry in Stack */
186 
187  /* use Li [Lp [i]+1] for etree */
188 #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
189 
190  if (stype > 0)
191  {
192  /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
193  p = Ap [k] ;
194  pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ;
195  /* W [i] = Ax [i] ; scatter column of A */
196 #define SCATTER ASSIGN(Wx,Wz,i, Ax,Az,p)
197  SUBTREE ;
198 #undef SCATTER
199  }
200  else
201  {
202  /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
203  pf = Fp [k] ;
204  pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ;
205  for ( ; pf < pfend ; pf++)
206  {
207  /* get nonzero entry F (t,k) */
208  t = Fi [pf] ;
209  /* fk = Fx [pf] */
210  ASSIGN (fx, fz, 0, Fx, Fz, pf) ;
211  p = Ap [t] ;
212  pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
213  multadds = 0 ;
214  /* W [i] += Ax [p] * fx ; scatter column of A*A' */
215 #define SCATTER MULTADD (Wx,Wz,i, Ax,Az,p, fx,fz,0) ; multadds++ ;
216  SUBTREE ;
217 #undef SCATTER
218 #ifdef REAL
219  fl += 2 * ((double) multadds) ;
220 #else
221  fl += 8 * ((double) multadds) ;
222 #endif
223  }
224  }
225 
226 #undef PARENT
227 
228  /* ------------------------------------------------------------------ */
229  /* if mask is present, set the corresponding entries in W to zero */
230  /* ------------------------------------------------------------------ */
231 
232 #ifdef MASK
233  /* remove the dead element of Wx */
234  if (mask != NULL)
235  {
236 
237 #if 0
238  /* older version */
239  for (p = n; p > top;)
240  {
241  i = Stack [--p] ;
242  if ( mask [i] >= 0 )
243  {
244  CLEAR (Wx,Wz,i) ; /* set W(i) to zero */
245  }
246  }
247 #endif
248 
249  for (s = top ; s < n ; s++)
250  {
251  i = Stack [s] ;
252  if (mask [i] >= 0)
253  {
254  CLEAR (Wx,Wz,i) ; /* set W(i) to zero */
255  }
256  }
257 
258  }
259 #endif
260 
261  /* nonzero pattern of kth row of L is now in Stack [top..n-1].
262  * Flag [Stack [top..n-1]] is equal to mark, but no longer needed */
263 
264  mark = CHOLMOD(clear_flag) (Common) ;
265 
266  /* ------------------------------------------------------------------ */
267  /* compute kth row of L and store in column form */
268  /* ------------------------------------------------------------------ */
269 
270  /* Solve L (0:k-1, 0:k-1) * y (0:k-1) = b (0:k-1) where
271  * b (0:k) = A (0:k,k) or A(0:k,:) * F(:,k) is in W and Stack.
272  *
273  * For LDL' factorization:
274  * L (k, 0:k-1) = y (0:k-1) ./ D (0:k-1)
275  * D (k) = b (k) - L (k, 0:k-1) * y (0:k-1)
276  *
277  * For LL' factorization:
278  * L (k, 0:k-1) = y (0:k-1)
279  * L (k,k) = sqrt (b (k) - L (k, 0:k-1) * L (0:k-1, k))
280  */
281 
282  /* dk = W [k] + beta */
283  ADD_REAL (dk,0, Wx,k, beta,0) ;
284 
285 #ifndef REAL
286  /* In the unsymmetric case, the imaginary part of W[k] must be real,
287  * since F is assumed to be the complex conjugate transpose of A. In
288  * the symmetric case, W[k] is the diagonal of A. If the imaginary part
289  * of W[k] is nonzero, then the Cholesky factorization cannot be
290  * computed; A is not positive definite */
291  dk_imaginary = (stype > 0) ? (IMAG_IS_NONZERO (Wx,Wz,k)) : FALSE ;
292 #endif
293 
294  /* W [k] = 0.0 ; */
295  CLEAR (Wx,Wz,k) ;
296 
297  for (s = top ; s < n ; s++)
298  {
299  /* get i for each nonzero entry L(k,i) */
300  i = Stack [s] ;
301 
302  /* y = W [i] ; */
303  ASSIGN (yx,yz,0, Wx,Wz,i) ;
304 
305  /* W [i] = 0.0 ; */
306  CLEAR (Wx,Wz,i) ;
307 
308  lnz = Lnz [i] ;
309  p = Lp [i] ;
310  ASSERT (lnz > 0 && Li [p] == i) ;
311  pend = p + lnz ;
312 
313  /* di = Lx [p] ; the diagonal entry L or D(i,i), which is real */
314  ASSIGN_REAL (di,0, Lx,p) ;
315 
316  if (i >= (Int) L->minor || IS_ZERO (di [0]))
317  {
318  /* For the LL' factorization, L(i,i) is zero. For the LDL',
319  * D(i,i) is zero. Skip column i of L, and set L(k,i) = 0. */
320  CLEAR (lx,lz,0) ;
321  p = pend ;
322  }
323  else if (is_ll)
324  {
325 #ifdef REAL
326  fl += 2 * ((double) (pend - p - 1)) + 3 ;
327 #else
328  fl += 8 * ((double) (pend - p - 1)) + 6 ;
329 #endif
330  /* forward solve using L (i:(k-1),i) */
331  /* divide by L(i,i), which must be real and nonzero */
332  /* y /= di [0] */
333  DIV_REAL (yx,yz,0, yx,yz,0, di,0) ;
334  for (p++ ; p < pend ; p++)
335  {
336  /* W [Li [p]] -= Lx [p] * y ; */
337  MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ;
338  }
339  /* do not scale L; compute dot product for L(k,k) */
340  /* L(k,i) = conj(y) ; */
341  ASSIGN_CONJ (lx,lz,0, yx,yz,0) ;
342  /* d -= conj(y) * y ; */
343  LLDOT (dk,0, yx,yz,0) ;
344  }
345  else
346  {
347 #ifdef REAL
348  fl += 2 * ((double) (pend - p - 1)) + 3 ;
349 #else
350  fl += 8 * ((double) (pend - p - 1)) + 6 ;
351 #endif
352  /* forward solve using D (i,i) and L ((i+1):(k-1),i) */
353  for (p++ ; p < pend ; p++)
354  {
355  /* W [Li [p]] -= Lx [p] * y ; */
356  MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ;
357  }
358  /* Scale L (k,0:k-1) for LDL' factorization, compute D (k,k)*/
359 #ifdef REAL
360  /* L(k,i) = y/d */
361  lx [0] = yx [0] / di [0] ;
362  /* d -= L(k,i) * y */
363  dk [0] -= lx [0] * yx [0] ;
364 #else
365  /* L(k,i) = conj(y) ; */
366  ASSIGN_CONJ (lx,lz,0, yx,yz,0) ;
367  /* L(k,i) /= di ; */
368  DIV_REAL (lx,lz,0, lx,lz,0, di,0) ;
369  /* d -= conj(y) * y / di */
370  LDLDOT (dk,0, yx,yz,0, di,0) ;
371 #endif
372  }
373 
374  /* determine if column i of L can hold the new L(k,i) entry */
375  if (p >= Lp [Lnext [i]])
376  {
377  /* column i needs to grow */
378  PRINT1 (("Factor Colrealloc "ID", old Lnz "ID"\n", i, Lnz [i]));
379  if (!CHOLMOD(reallocate_column) (i, lnz + 1, L, Common))
380  {
381  /* out of memory, L is now simplicial symbolic */
382  for (i = 0 ; i < n ; i++)
383  {
384  /* W [i] = 0 ; */
385  CLEAR (Wx,Wz,i) ;
386  }
387  ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ;
388  return (FALSE) ;
389  }
390  Li = L->i ; /* L->i, L->x, L->z may have moved */
391  Lx = L->x ;
392  Lz = L->z ;
393  p = Lp [i] + lnz ; /* contents of L->p changed */
394  ASSERT (p < Lp [Lnext [i]]) ;
395  }
396 
397  /* store L (k,i) in the column form matrix of L */
398  Li [p] = k ;
399  /* Lx [p] = L(k,i) ; */
400  ASSIGN (Lx,Lz,p, lx,lz,0) ;
401  Lnz [i]++ ;
402  }
403 
404  /* ------------------------------------------------------------------ */
405  /* ensure abs (d) >= dbound if dbound is given, and store it in L */
406  /* ------------------------------------------------------------------ */
407 
408  p = Lp [k] ;
409  Li [p] = k ;
410 
411  if (k >= (Int) L->minor)
412  {
413  /* the matrix is already not positive definite */
414  dk [0] = 0 ;
415  }
416  else if (use_dbound)
417  {
418  /* modify the diagonal to force LL' or LDL' to exist */
419  dk [0] = CHOLMOD(dbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ;
420  }
421  else if ((is_ll ? (IS_LE_ZERO (dk [0])) : (IS_ZERO (dk [0])))
422 #ifndef REAL
423  || dk_imaginary
424 #endif
425  )
426  {
427  /* the matrix has just been found to be not positive definite */
428  dk [0] = 0 ;
429  L->minor = k ;
430  ERROR (CHOLMOD_NOT_POSDEF, "not positive definite") ;
431  }
432 
433  if (is_ll)
434  {
435  /* this is counted as one flop, below */
436  dk [0] = sqrt (dk [0]) ;
437  }
438 
439  /* Lx [p] = D(k,k) = d ; real part only */
440  ASSIGN_REAL (Lx,p, dk,0) ;
441  CLEAR_IMAG (Lx,Lz,p) ;
442  }
443 
444 #undef NEXT
445 
446  if (is_ll) fl += MAX ((Int) kend - (Int) kstart, 0) ; /* count sqrt's */
447  Common->rowfacfl = fl ;
448 
449  DEBUG (CHOLMOD(dump_factor) (L, "final cholmod_rowfac", Common)) ;
450  ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ;
451  return (TRUE) ;
452 }
453 #undef PATTERN
454 #undef REAL
455 #undef COMPLEX
456 #undef ZOMPLEX
int CHOLMOD() reallocate_column(size_t j, size_t need, cholmod_factor *L, cholmod_common *Common)
#define SUBTREE
#define Int
#define FALSE
#define PRINT1(params)
#define NEXT(k)
int CHOLMOD() dump_work(int flag, int head, UF_long wsize, cholmod_common *Common)
#define CHOLMOD_PATTERN
#define CHOLMOD(name)
#define MAX(a, b)
static int TEMPLATE() cholmod_rowfac(cholmod_sparse *A, cholmod_sparse *F, double beta[2], size_t kstart, size_t kend, cholmod_factor *L, cholmod_common *Common)
#define CHOLMOD_REAL
#define NULL
#define CLEAR(c)
#define ASSERT(expression)
#define ID
#define IS_ZERO(x)
#define CHOLMOD_NOT_POSDEF
#define CHOLMOD_OK
#define DEBUG(statement)
int CHOLMOD() change_factor(int to_xtype, int to_ll, int to_super, int to_packed, int to_monotonic, cholmod_factor *L, cholmod_common *Common)
int CHOLMOD() dump_factor(cholmod_factor *L, char *name, cholmod_common *Common)
#define IS_LE_ZERO(x)
UF_long CHOLMOD() clear_flag(cholmod_common *Common)
#define IS_GT_ZERO(x)
int n
#define ERROR(status, msg)
#define TRUE
#define ASSIGN(c, s1, s2, p, split)