1 /* ========================================================================== */
2 /* === Supernodal/cholmod_super_numeric ===================================== */
3 /* ========================================================================== */
4
5 /* -----------------------------------------------------------------------------
6 * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis
7 * http://www.suitesparse.com
8 * -------------------------------------------------------------------------- */
9
10 /* Computes the Cholesky factorization of A+beta*I or A*F+beta*I. Only the
11 * the lower triangular part of A+beta*I or A*F+beta*I is accessed. The
12 * matrices A and F must already be permuted according to the fill-reduction
13 * permutation L->Perm. cholmod_factorize is an "easy" wrapper for this code
14 * which applies that permutation. beta is real.
15 *
16 * Symmetric case: A is a symmetric (lower) matrix. F is not accessed.
17 * With a fill-reducing permutation, A(p,p) should be passed instead, where is
18 * p is L->Perm.
19 *
20 * Unsymmetric case: A is unsymmetric, and F must be present. Normally, F=A'.
21 * With a fill-reducing permutation, A(p,f) and A(p,f)' should be passed as A
22 * and F, respectively, where f is a list of the subset of the columns of A.
23 *
24 * The input factorization L must be supernodal (L->is_super is TRUE). It can
25 * either be symbolic or numeric. In the first case, L has been analyzed by
26 * cholmod_analyze or cholmod_super_symbolic, but the matrix has not yet been
27 * numerically factorized. The numerical values are allocated here and the
28 * factorization is computed. In the second case, a prior matrix has been
29 * analyzed and numerically factorized, and a new matrix is being factorized.
30 * The numerical values of L are replaced with the new numerical factorization.
31 *
32 * L->is_ll is ignored, and set to TRUE. This routine always computes an LL'
33 * factorization. Supernodal LDL' factorization is not (yet) supported.
34 * FUTURE WORK: perform a supernodal LDL' factorization if L->is_ll is FALSE.
35 *
36 * Uses BLAS routines dsyrk, dgemm, dtrsm, and the LAPACK routine dpotrf.
37 * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm.
38 *
39 * If the matrix is not positive definite the routine returns TRUE, but sets
40 * Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the column at
41 * which the failure occurred. The supernode containing the non-positive
42 * diagonal entry is set to zero (this includes columns to the left of L->minor
43 * in the same supernode), as are all subsequent supernodes.
44 *
45 * workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow + 5*nsuper).
46 * Allocates temporary space of size L->maxcsize * sizeof(double)
47 * (twice that for the complex/zomplex case).
48 *
49 * If L is supernodal symbolic on input, it is converted to a supernodal numeric
50 * factor on output, with an xtype of real if A is real, or complex if A is
51 * complex or zomplex. If L is supernodal numeric on input, its xtype must
52 * match A (except that L can be complex and A zomplex). The xtype of A and F
53 * must match.
54 */
55
56 #ifndef NGPL
57 #ifndef NSUPERNODAL
58
59 #include "cholmod_internal.h"
60 #include "cholmod_supernodal.h"
61
62 #ifdef GPU_BLAS
63 #include "cholmod_gpu.h"
64 #endif
65
66 /* ========================================================================== */
67 /* === TEMPLATE codes for GPU and regular numeric factorization ============= */
68 /* ========================================================================== */
69
70 #ifdef DLONG
71 #ifdef GPU_BLAS
72 #define REAL
73 #include "../GPU/t_cholmod_gpu.c"
74 #define COMPLEX
75 #include "../GPU/t_cholmod_gpu.c"
76 #define ZOMPLEX
77 /* no #include of "../GPU/t_cholmod_gpu.c". Zomplex case relies on complex */
78 #endif
79 #endif
80
81 #define REAL
82 #include "t_cholmod_super_numeric.c"
83 #define COMPLEX
84 #include "t_cholmod_super_numeric.c"
85 #define ZOMPLEX
86 #include "t_cholmod_super_numeric.c"
87
88 /* ========================================================================== */
89 /* === cholmod_super_numeric ================================================ */
90 /* ========================================================================== */
91
92 /* Returns TRUE if successful, or if the matrix is not positive definite.
93 * Returns FALSE if out of memory, inputs are invalid, or other fatal error
94 * occurs.
95 */
96
CHOLMOD(super_numeric)97 int CHOLMOD(super_numeric)
98 (
99 /* ---- input ---- */
100 cholmod_sparse *A, /* matrix to factorize */
101 cholmod_sparse *F, /* F = A' or A(:,f)' */
102 double beta [2], /* beta*I is added to diagonal of matrix to factorize */
103 /* ---- in/out --- */
104 cholmod_factor *L, /* factorization */
105 /* --------------- */
106 cholmod_common *Common
107 )
108 {
109 cholmod_dense *C ;
110 Int *Super, *Map, *SuperMap ;
111 size_t maxcsize ;
112 Int nsuper, n, i, k, s, stype, nrow ;
113 int ok = TRUE, symbolic ;
114 size_t t, w ;
115
116 /* ---------------------------------------------------------------------- */
117 /* check inputs */
118 /* ---------------------------------------------------------------------- */
119
120 RETURN_IF_NULL_COMMON (FALSE) ;
121 RETURN_IF_NULL (L, FALSE) ;
122 RETURN_IF_NULL (A, FALSE) ;
123 RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
124 RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_COMPLEX, FALSE) ;
125 stype = A->stype ;
126 if (stype < 0)
127 {
128 if (A->nrow != A->ncol || A->nrow != L->n)
129 {
130 ERROR (CHOLMOD_INVALID, "invalid dimensions") ;
131 return (FALSE) ;
132 }
133 }
134 else if (stype == 0)
135 {
136 if (A->nrow != L->n)
137 {
138 ERROR (CHOLMOD_INVALID, "invalid dimensions") ;
139 return (FALSE) ;
140 }
141 RETURN_IF_NULL (F, FALSE) ;
142 RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
143 if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0)
144 {
145 ERROR (CHOLMOD_INVALID, "F invalid") ;
146 return (FALSE) ;
147 }
148 if (A->xtype != F->xtype)
149 {
150 ERROR (CHOLMOD_INVALID, "A and F must have same xtype") ;
151 return (FALSE) ;
152 }
153 }
154 else
155 {
156 /* symmetric upper case not suppored */
157 ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ;
158 return (FALSE) ;
159 }
160 if (!(L->is_super))
161 {
162 ERROR (CHOLMOD_INVALID, "L not supernodal") ;
163 return (FALSE) ;
164 }
165 if (L->xtype != CHOLMOD_PATTERN)
166 {
167 if (! ((A->xtype == CHOLMOD_REAL && L->xtype == CHOLMOD_REAL)
168 || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX)
169 || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX)))
170 {
171 ERROR (CHOLMOD_INVALID, "complex type mismatch") ;
172 return (FALSE) ;
173 }
174 }
175 Common->status = CHOLMOD_OK ;
176
177 /* ---------------------------------------------------------------------- */
178 /* allocate workspace in Common */
179 /* ---------------------------------------------------------------------- */
180
181 nsuper = L->nsuper ;
182 maxcsize = L->maxcsize ;
183 nrow = A->nrow ;
184 n = nrow ;
185
186 PRINT1 (("nsuper "ID" maxcsize %g\n", nsuper, (double) maxcsize)) ;
187 ASSERT (nsuper >= 0 && maxcsize > 0) ;
188
189 /* w = 2*n + 5*nsuper */
190 w = CHOLMOD(mult_size_t) (n, 2, &ok) ;
191 t = CHOLMOD(mult_size_t) (nsuper, 5, &ok) ;
192 w = CHOLMOD(add_size_t) (w, t, &ok) ;
193 if (!ok)
194 {
195 ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
196 return (FALSE) ;
197 }
198
199 CHOLMOD(allocate_work) (n, w, 0, Common) ;
200 if (Common->status < CHOLMOD_OK)
201 {
202 return (FALSE) ;
203 }
204 ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
205
206 /* ---------------------------------------------------------------------- */
207 /* get the current factor L and allocate numerical part, if needed */
208 /* ---------------------------------------------------------------------- */
209
210 Super = L->super ;
211 symbolic = (L->xtype == CHOLMOD_PATTERN) ;
212 if (symbolic)
213 {
214 /* convert to supernodal numeric by allocating L->x */
215 CHOLMOD(change_factor) (
216 (A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX,
217 TRUE, TRUE, TRUE, TRUE, L, Common) ;
218 if (Common->status < CHOLMOD_OK)
219 {
220 /* the factor L remains in symbolic supernodal form */
221 return (FALSE) ;
222 }
223 }
224 ASSERT (L->dtype == DTYPE) ;
225 ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ;
226
227 /* supernodal LDL' is not supported */
228 L->is_ll = TRUE ;
229
230 /* ---------------------------------------------------------------------- */
231 /* get more workspace */
232 /* ---------------------------------------------------------------------- */
233
234 C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype, Common) ;
235 if (Common->status < CHOLMOD_OK)
236 {
237 int status = Common->status ;
238 if (symbolic)
239 {
240 /* Change L back to symbolic, since the numeric values are not
241 * initialized. This cannot fail. */
242 CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE,
243 L, Common) ;
244 }
245 /* the factor L is now back to the form it had on input */
246 Common->status = status ;
247 return (FALSE) ;
248 }
249
250 /* ---------------------------------------------------------------------- */
251 /* get workspace */
252 /* ---------------------------------------------------------------------- */
253
254 SuperMap = Common->Iwork ; /* size n (i/i/l) */
255 Map = Common->Flag ; /* size n, use Flag as workspace for Map array */
256 for (i = 0 ; i < n ; i++)
257 {
258 Map [i] = EMPTY ;
259 }
260
261 /* ---------------------------------------------------------------------- */
262 /* find the mapping of nodes to relaxed supernodes */
263 /* ---------------------------------------------------------------------- */
264
265 /* SuperMap [k] = s if column k is contained in supernode s */
266 for (s = 0 ; s < nsuper ; s++)
267 {
268 PRINT1 (("Super ["ID"] "ID" ncols "ID"\n",
269 s, Super[s], Super[s+1]-Super[s]));
270 for (k = Super [s] ; k < Super [s+1] ; k++)
271 {
272 SuperMap [k] = s ;
273 PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ;
274 }
275 }
276
277 /* ---------------------------------------------------------------------- */
278 /* supernodal numerical factorization, using template routine */
279 /* ---------------------------------------------------------------------- */
280
281 switch (A->xtype)
282 {
283 case CHOLMOD_REAL:
284 ok = r_cholmod_super_numeric (A, F, beta, L, C, Common) ;
285 break ;
286
287 case CHOLMOD_COMPLEX:
288 ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ;
289 break ;
290
291 case CHOLMOD_ZOMPLEX:
292 /* This operates on complex L, not zomplex */
293 ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ;
294 break ;
295 }
296
297 /* ---------------------------------------------------------------------- */
298 /* clear Common workspace, free temp workspace C, and return */
299 /* ---------------------------------------------------------------------- */
300
301 /* Flag array was used as workspace, clear it */
302 Common->mark = EMPTY ;
303 /* CHOLMOD(clear_flag) (Common) ; */
304 CHOLMOD_CLEAR_FLAG (Common) ;
305 ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
306 CHOLMOD(free_dense) (&C, Common) ;
307 return (ok) ;
308 }
309 #endif
310 #endif
311