Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_cholmod_change_factor.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === Core/cholmod_change_factor =========================================== */
3 /* ========================================================================== */
4 
5 /* -----------------------------------------------------------------------------
6  * CHOLMOD/Core Module. Copyright (C) 2005-2006,
7  * Univ. of Florida. Author: Timothy A. Davis
8  * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
9  * Lesser General Public License. See lesser.txt for a text of the license.
10  * CHOLMOD is also available under other licenses; contact authors for details.
11  * http://www.cise.ufl.edu/research/sparse
12  * -------------------------------------------------------------------------- */
13 
14 /* Change the numeric/symbolic, LL/LDL, simplicial/super, packed/unpacked,
15  * monotonic/non-monotonic status of a cholmod_factor object.
16  *
17  * There are four basic classes of factor types:
18  *
19  * (1) simplicial symbolic: Consists of two size-n arrays: the fill-reducing
20  * permutation (L->Perm) and the nonzero count for each column of L
21  * (L->ColCount). All other factor types also include this information.
22  * L->ColCount may be exact (obtained from the analysis routines), or
23  * it may be a guess. During factorization, and certainly after update/
24  * downdate, the columns of L can have a different number of nonzeros.
25  * L->ColCount is used to allocate space. L->ColCount is exact for the
26  * supernodal factorizations. The nonzero pattern of L is not kept.
27  *
28  * (2) simplicial numeric: These represent L in a compressed column form. The
29  * variants of this type are:
30  *
31  * LDL': L is unit diagonal. Row indices in column j are located in
32  * L->i [L->p [j] ... L->p [j] + L->nz [j]], and corresponding numeric
33  * values are in the same locations in L->x. The total number of
34  * entries is the sum of L->nz [j]. The unit diagonal is not stored;
35  * D is stored on the diagonal of L instead. L->p may or may not be
36  * monotonic. The order of storage of the columns in L->i and L->x is
37  * given by a doubly-linked list (L->prev and L->next). L->p is of
38  * size n+1, but only the first n entries are used (it is used if L
39  * is converted to a sparse matrix via cholmod_factor_to_sparse).
40  *
41  * For the complex case, L->x is stored interleaved with real/imag
42  * parts, and is of size 2*lnz*sizeof(double). For the zomplex case,
43  * L->x is of size lnz*sizeof(double) and holds the real part; L->z
44  * is the same size and holds the imaginary part.
45  *
46  * LL': This is identical to the LDL' form, except that the non-unit
47  * diagonal of L is stored as the first entry in each column of L.
48  *
49  * (3) supernodal symbolic: A representation of the nonzero pattern of the
50  * supernodes for a supernodal factorization. There are L->nsuper
51  * supernodes. Columns L->super [k] to L->super [k+1]-1 are in the kth
52  * supernode. The row indices for the kth supernode are in
53  * L->s [L->pi [k] ... L->pi [k+1]-1]. The numerical values are not
54  * allocated (L->x), but when they are they will be located in
55  * L->x [L->px [k] ... L->px [k+1]-1], and the L->px array is defined
56  * in this factor type.
57  *
58  * For the complex case, L->x is stored interleaved with real/imag parts,
59  * and is of size 2*L->xsize*sizeof(double). The zomplex supernodal case
60  * is not supported, since it is not compatible with LAPACK and the BLAS.
61  *
62  * (4) supernodal numeric: Always an LL' factorization. L is non-unit
63  * diagonal. L->x contains the numerical values of the supernodes, as
64  * described above for the supernodal symbolic factor.
65  * For the complex case, L->x is stored interleaved, and is of size
66  * 2*L->xsize*sizeof(double). The zomplex supernodal case is not
67  * supported, since it is not compatible with LAPACK and the BLAS.
68  *
69  * FUTURE WORK: support a supernodal LDL' factor.
70  *
71  *
72  * In all cases, the row indices in each column (L->i for simplicial L and
73  * L->s for supernodal L) are kept sorted from low indices to high indices.
74  * This means the diagonal of L (or D for LDL' factors) is always kept as the
75  * first entry in each column.
76  *
77  * The cholmod_change_factor routine can do almost all possible conversions.
78  * It cannot do the following conversions:
79  *
80  * (1) Simplicial numeric types cannot be converted to a supernodal
81  * symbolic type. This would simultaneously deallocate the
82  * simplicial pattern and numeric values and reallocate uninitialized
83  * space for the supernodal pattern. This isn't useful for the user,
84  * and not needed by CHOLMOD's own routines either.
85  *
86  * (2) Only a symbolic factor (simplicial to supernodal) can be converted
87  * to a supernodal numeric factor.
88  *
89  * Some conversions are meant only to be used internally by other CHOLMOD
90  * routines, and should not be performed by the end user. They allocate space
91  * whose contents are undefined:
92  *
93  * (1) converting from simplicial symbolic to supernodal symbolic.
94  * (2) converting any factor to supernodal numeric.
95  *
96  * workspace: no conversion routine uses workspace in Common. No temporary
97  * workspace is allocated.
98  *
99  * Supports all xtypes, except that there is no supernodal zomplex L.
100  *
101  * The to_xtype parameter is used only when converting from symbolic to numeric
102  * or numeric to symbolic. It cannot be used to convert a numeric xtype (real,
103  * complex, or zomplex) to a different numeric xtype. For that conversion,
104  * use cholmod_factor_xtype instead.
105  */
106 
107 #include "amesos_cholmod_internal.h"
108 #include "amesos_cholmod_core.h"
109 
110 static void natural_list (cholmod_factor *L) ;
111 
112 /* ========================================================================== */
113 /* === TEMPLATE ============================================================= */
114 /* ========================================================================== */
115 
116 #define REAL
118 #define COMPLEX
120 #define ZOMPLEX
122 
123 
124 /* ========================================================================== */
125 /* === L_is_packed ========================================================== */
126 /* ========================================================================== */
127 
128 /* Return TRUE if the columns of L are packed, FALSE otherwise. For debugging
129  * only. */
130 
131 #ifndef NDEBUG
132 static int L_is_packed (cholmod_factor *L, cholmod_common *Common)
133 {
134  Int j ;
135  Int *Lnz = L->nz ;
136  Int *Lp = L->p ;
137  Int n = L->n ;
138 
139  if (L->xtype == CHOLMOD_PATTERN || L->is_super)
140  {
141  return (TRUE) ;
142  }
143 
144  if (Lnz == NULL || Lp == NULL)
145  {
146  return (TRUE) ;
147  }
148 
149  for (j = 0 ; j < n ; j++)
150  {
151  PRINT3 (("j: "ID" Lnz "ID" Lp[j+1] "ID" Lp[j] "ID"\n", j, Lnz [j],
152  Lp [j+1], Lp [j])) ;
153  if (Lnz [j] != (Lp [j+1] - Lp [j]))
154  {
155  PRINT2 (("L is not packed\n")) ;
156  return (FALSE) ;
157  }
158  }
159  return (TRUE) ;
160 }
161 #endif
162 
163 
164 /* ========================================================================== */
165 /* === natural_list ========================================================= */
166 /* ========================================================================== */
167 
168 /* Create a naturally-ordered doubly-linked list of columns. */
169 
170 static void natural_list (cholmod_factor *L)
171 {
172  Int head, tail, n, j ;
173  Int *Lnext, *Lprev ;
174  Lnext = L->next ;
175  Lprev = L->prev ;
176  ASSERT (Lprev != NULL && Lnext != NULL) ;
177  n = L->n ;
178  head = n+1 ;
179  tail = n ;
180  Lnext [head] = 0 ;
181  Lprev [head] = EMPTY ;
182  Lnext [tail] = EMPTY ;
183  Lprev [tail] = n-1 ;
184  for (j = 0 ; j < n ; j++)
185  {
186  Lnext [j] = j+1 ;
187  Lprev [j] = j-1 ;
188  }
189  Lprev [0] = head ;
190  L->is_monotonic = TRUE ;
191 }
192 
193 
194 /* ========================================================================== */
195 /* === allocate_simplicial_numeric ========================================== */
196 /* ========================================================================== */
197 
198 /* Allocate O(n) arrays for simplicial numeric factorization. Initializes
199  * the link lists only. Does not allocate the L->i, L->x, or L->z arrays. */
200 
202 (
203  cholmod_factor *L,
204  cholmod_common *Common
205 )
206 {
207  Int n ;
208  Int *Lp, *Lnz, *Lprev, *Lnext ;
209  size_t n1, n2 ;
210 
211  PRINT1 (("Allocate simplicial\n")) ;
212 
213  ASSERT (L->xtype == CHOLMOD_PATTERN || L->is_super) ;
214  ASSERT (L->p == NULL) ;
215  ASSERT (L->nz == NULL) ;
216  ASSERT (L->prev == NULL) ;
217  ASSERT (L->next == NULL) ;
218 
219  n = L->n ;
220 
221  /* this cannot cause size_t overflow */
222  n1 = ((size_t) n) + 1 ;
223  n2 = ((size_t) n) + 2 ;
224 
225  Lp = CHOLMOD(malloc) (n1, sizeof (Int), Common) ;
226  Lnz = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
227  Lprev = CHOLMOD(malloc) (n2, sizeof (Int), Common) ;
228  Lnext = CHOLMOD(malloc) (n2, sizeof (Int), Common) ;
229 
230  if (Common->status < CHOLMOD_OK)
231  {
232  CHOLMOD(free) (n1, sizeof (Int), Lp, Common) ;
233  CHOLMOD(free) (n, sizeof (Int), Lnz, Common) ;
234  CHOLMOD(free) (n2, sizeof (Int), Lprev, Common) ;
235  CHOLMOD(free) (n2, sizeof (Int), Lnext, Common) ;
236  PRINT1 (("Allocate simplicial failed\n")) ;
237  return (FALSE) ; /* out of memory */
238  }
239 
240  /* ============================================== commit the changes to L */
241 
242  L->p = Lp ;
243  L->nz = Lnz ;
244  L->prev = Lprev ;
245  L->next = Lnext ;
246  /* initialize a doubly linked list for columns in natural order */
247  natural_list (L) ;
248  PRINT1 (("Allocate simplicial done\n")) ;
249  return (TRUE) ;
250 }
251 
252 
253 /* ========================================================================== */
254 /* === simplicial_symbolic_to_super_symbolic ================================ */
255 /* ========================================================================== */
256 
257 /* Convert a simplicial symbolic factor supernodal symbolic factor. Does not
258  * initialize the new space. */
259 
261 (
262  cholmod_factor *L,
263  cholmod_common *Common
264 )
265 {
266  Int nsuper, xsize, ssize ;
267  Int *Lsuper, *Lpi, *Lpx, *Ls ;
268  size_t nsuper1 ;
269 
270  ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ;
271 
272  xsize = L->xsize ;
273  ssize = L->ssize ;
274  nsuper = L->nsuper ;
275  nsuper1 = ((size_t) nsuper) + 1 ;
276 
277  PRINT1 (("simple sym to super sym: ssize "ID" xsize "ID" nsuper "ID""
278  " status %d\n", ssize, xsize, nsuper, Common->status)) ;
279 
280  /* O(nsuper) arrays, where nsuper <= n */
281  Lsuper = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
282  Lpi = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
283  Lpx = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
284 
285  /* O(ssize) array, where ssize <= nnz(L), and usually much smaller */
286  Ls = CHOLMOD(malloc) (ssize, sizeof (Int), Common) ;
287 
288  if (Common->status < CHOLMOD_OK)
289  {
290  CHOLMOD(free) (nsuper1, sizeof (Int), Lsuper, Common) ;
291  CHOLMOD(free) (nsuper1, sizeof (Int), Lpi, Common) ;
292  CHOLMOD(free) (nsuper1, sizeof (Int), Lpx, Common) ;
293  CHOLMOD(free) (ssize, sizeof (Int), Ls, Common) ;
294  return (FALSE) ; /* out of memory */
295  }
296 
297  /* ============================================== commit the changes to L */
298 
299  ASSERT (Lsuper != NULL && Lpi != NULL && Lpx != NULL && Ls != NULL) ;
300 
301  L->maxcsize = 0 ;
302  L->maxesize = 0 ;
303 
304  L->super = Lsuper ;
305  L->pi = Lpi ;
306  L->px = Lpx ;
307  L->s = Ls ;
308  Ls [0] = EMPTY ; /* supernodal pattern undefined */
309 
310  L->is_super = TRUE ;
311  L->is_ll = TRUE ; /* supernodal LDL' not supported */
312  L->xtype = CHOLMOD_PATTERN ;
313  L->dtype = DTYPE ;
314  L->minor = L->n ;
315  return (TRUE) ;
316 }
317 
318 
319 /* ========================================================================== */
320 /* === any_to_simplicial_symbolic =========================================== */
321 /* ========================================================================== */
322 
323 /* Convert any factor L to a simplicial symbolic factor, leaving only L->Perm
324  * and L->ColCount. Cannot fail. Any of the components of L (except Perm and
325  * ColCount) may already be free'd. */
326 
327 static void any_to_simplicial_symbolic
328 (
329  cholmod_factor *L,
330  int to_ll,
331  cholmod_common *Common
332 )
333 {
334  Int n, lnz, xs, ss, s, e ;
335  size_t n1, n2 ;
336 
337  /* ============================================== commit the changes to L */
338 
339  n = L->n ;
340  lnz = L->nzmax ;
341  s = L->nsuper + 1 ;
342  xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ;
343  e = (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) ;
344  ss = L->ssize ;
345 
346  /* this cannot cause size_t overflow */
347  n1 = ((size_t) n) + 1 ;
348  n2 = ((size_t) n) + 2 ;
349 
350  /* free all but the symbolic analysis (Perm and ColCount) */
351  L->p = CHOLMOD(free) (n1, sizeof (Int), L->p, Common) ;
352  L->i = CHOLMOD(free) (lnz, sizeof (Int), L->i, Common) ;
353  L->x = CHOLMOD(free) (xs, e*sizeof (double), L->x, Common) ;
354  L->z = CHOLMOD(free) (lnz, sizeof (double), L->z, Common) ;
355  L->nz = CHOLMOD(free) (n, sizeof (Int), L->nz, Common) ;
356  L->next = CHOLMOD(free) (n2, sizeof (Int), L->next, Common) ;
357  L->prev = CHOLMOD(free) (n2, sizeof (Int), L->prev, Common) ;
358  L->super = CHOLMOD(free) (s, sizeof (Int), L->super, Common) ;
359  L->pi = CHOLMOD(free) (s, sizeof (Int), L->pi, Common) ;
360  L->px = CHOLMOD(free) (s, sizeof (Int), L->px, Common) ;
361  L->s = CHOLMOD(free) (ss, sizeof (Int), L->s, Common) ;
362  L->nzmax = 0 ;
363  L->is_super = FALSE ;
364  L->xtype = CHOLMOD_PATTERN ;
365  L->dtype = DTYPE ;
366  L->minor = n ;
367  L->is_ll = to_ll ;
368 }
369 
370 
371 /* ========================================================================== */
372 /* === ll_super_to_super_symbolic =========================================== */
373 /* ========================================================================== */
374 
375 /* Convert a numerical supernodal L to symbolic supernodal. Cannot fail. */
376 
377 static void ll_super_to_super_symbolic
378 (
379  cholmod_factor *L,
380  cholmod_common *Common
381 )
382 {
383 
384  /* ============================================== commit the changes to L */
385 
386  /* free all but the supernodal numerical factor */
387  ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_super && L->is_ll) ;
388  DEBUG (CHOLMOD(dump_factor) (L, "start to super symbolic", Common)) ;
389  L->x = CHOLMOD(free) (L->xsize,
390  (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) * sizeof (double), L->x,
391  Common) ;
392  L->xtype = CHOLMOD_PATTERN ;
393  L->dtype = DTYPE ;
394  L->minor = L->n ;
395  L->is_ll = TRUE ; /* supernodal LDL' not supported */
396  DEBUG (CHOLMOD(dump_factor) (L, "done to super symbolic", Common)) ;
397 }
398 
399 
400 /* ========================================================================== */
401 /* === simplicial_symbolic_to_simplicial_numeric ============================ */
402 /* ========================================================================== */
403 
404 /* Convert a simplicial symbolic L to a simplicial numeric L; allocate space
405  * for L using L->ColCount from symbolic analysis, and set L to identity.
406  *
407  * If packed < 0, then this routine is creating a copy of another factor
408  * (via cholmod_copy_factor). In this case, the space is not initialized. */
409 
411 (
412  cholmod_factor *L,
413  int to_ll,
414  int packed,
415  int to_xtype,
416  cholmod_common *Common
417 )
418 {
419  double grow0, grow1, xlen, xlnz ;
420  double *Lx, *Lz ;
421  Int *Li, *Lp, *Lnz, *ColCount ;
422  Int n, grow, grow2, p, j, lnz, len, ok, e ;
423 
424  ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ;
425  if (!allocate_simplicial_numeric (L, Common))
426  {
427  PRINT1 (("out of memory, allocate simplicial numeric\n")) ;
428  return ; /* out of memory */
429  }
430  ASSERT (L->ColCount != NULL && L->nz != NULL && L->p != NULL) ;
431  ASSERT (L->x == NULL && L->z == NULL && L->i == NULL) ;
432 
433  ColCount = L->ColCount ;
434  Lnz = L->nz ;
435  Lp = L->p ;
436  ok = TRUE ;
437  n = L->n ;
438 
439  if (packed < 0)
440  {
441 
442  /* ------------------------------------------------------------------ */
443  /* used by cholmod_copy_factor to allocate a copy of a factor object */
444  /* ------------------------------------------------------------------ */
445 
446  lnz = L->nzmax ;
447  L->nzmax = 0 ;
448 
449  }
450  else if (packed)
451  {
452 
453  /* ------------------------------------------------------------------ */
454  /* LDL' or LL' packed */
455  /* ------------------------------------------------------------------ */
456 
457  PRINT1 (("convert to packed LL' or LDL'\n")) ;
458  lnz = 0 ;
459  for (j = 0 ; ok && j < n ; j++)
460  {
461  /* ensure len is in the range 1 to n-j */
462  len = ColCount [j] ;
463  len = MAX (1, len) ;
464  len = MIN (len, n-j) ;
465  lnz += len ;
466  ok = (lnz >= 0) ;
467  }
468  for (j = 0 ; j <= n ; j++)
469  {
470  Lp [j] = j ;
471  }
472  for (j = 0 ; j < n ; j++)
473  {
474  Lnz [j] = 1 ;
475  }
476 
477  }
478  else
479  {
480 
481  /* ------------------------------------------------------------------ */
482  /* LDL' unpacked */
483  /* ------------------------------------------------------------------ */
484 
485  PRINT1 (("convert to unpacked\n")) ;
486  /* compute new lnzmax */
487  /* if any parameter is NaN, grow is false */
488  grow0 = Common->grow0 ;
489  grow1 = Common->grow1 ;
490  grow2 = Common->grow2 ;
491  grow0 = IS_NAN (grow0) ? 1 : grow0 ;
492  grow1 = IS_NAN (grow1) ? 1 : grow1 ;
493  /* fl.pt. compare, but no NaN's: */
494  grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ;
495  PRINT1 (("init, grow1 %g grow2 "ID"\n", grow1, grow2)) ;
496  /* initialize Lp and Lnz for each column */
497  lnz = 0 ;
498  for (j = 0 ; ok && j < n ; j++)
499  {
500  Lp [j] = lnz ;
501  Lnz [j] = 1 ;
502 
503  /* ensure len is in the range 1 to n-j */
504  len = ColCount [j] ;
505  len = MAX (1, len) ;
506  len = MIN (len, n-j) ;
507 
508  /* compute len in double to avoid integer overflow */
509  PRINT1 (("ColCount ["ID"] = "ID"\n", j, len)) ;
510  if (grow)
511  {
512  xlen = (double) len ;
513  xlen = grow1 * xlen + grow2 ;
514  xlen = MIN (xlen, n-j) ;
515  len = (Int) xlen ;
516  }
517  ASSERT (len >= 1 && len <= n-j) ;
518  lnz += len ;
519  ok = (lnz >= 0) ;
520  }
521  if (ok)
522  {
523  Lp [n] = lnz ;
524  if (grow)
525  {
526  /* add extra space */
527  xlnz = (double) lnz ;
528  xlnz *= grow0 ;
529  xlnz = MIN (xlnz, Size_max) ;
530  xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ;
531  lnz = (Int) xlnz ;
532  }
533  }
534  }
535 
536  lnz = MAX (1, lnz) ;
537 
538  if (!ok)
539  {
540  ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
541  }
542 
543  /* allocate L->i, L->x, and L->z */
544  PRINT1 (("resizing from zero size to lnz "ID"\n", lnz)) ;
545  ASSERT (L->nzmax == 0) ;
546  e = (to_xtype == CHOLMOD_COMPLEX ? 2 : 1) ;
547  if (!ok || !CHOLMOD(realloc_multiple) (lnz, 1, to_xtype, &(L->i), NULL,
548  &(L->x), &(L->z), &(L->nzmax), Common))
549  {
550  L->p = CHOLMOD(free) (n+1, sizeof (Int), L->p, Common) ;
551  L->nz = CHOLMOD(free) (n, sizeof (Int), L->nz, Common) ;
552  L->prev = CHOLMOD(free) (n+2, sizeof (Int), L->prev, Common) ;
553  L->next = CHOLMOD(free) (n+2, sizeof (Int), L->next, Common) ;
554  L->i = CHOLMOD(free) (lnz, sizeof (Int), L->i, Common) ;
555  L->x = CHOLMOD(free) (lnz, e*sizeof (double), L->x, Common) ;
556  L->z = CHOLMOD(free) (lnz, sizeof (double), L->z, Common) ;
557  PRINT1 (("cannot realloc simplicial numeric\n")) ;
558  return ; /* out of memory */
559  }
560 
561  /* ============================================== commit the changes to L */
562 
563  /* initialize L to be the identity matrix */
564  L->xtype = to_xtype ;
565  L->dtype = DTYPE ;
566  L->minor = n ;
567 
568  Li = L->i ;
569  Lx = L->x ;
570  Lz = L->z ;
571 
572 #if 0
573  if (lnz == 1)
574  {
575  /* the user won't expect to access this entry, but some CHOLMOD
576  * routines may. Set it to zero so that valgrind doesn't complain. */
577  switch (to_xtype)
578  {
579  case CHOLMOD_REAL:
580  Lx [0] = 0 ;
581  break ;
582 
583  case CHOLMOD_COMPLEX:
584  Lx [0] = 0 ;
585  Lx [1] = 0 ;
586  break ;
587 
588  case CHOLMOD_ZOMPLEX:
589  Lx [0] = 0 ;
590  Lz [0] = 0 ;
591  break ;
592  }
593  }
594 #endif
595 
596  if (packed >= 0)
597  {
598  /* create the unit diagonal for either the LL' or LDL' case */
599 
600  switch (L->xtype)
601  {
602  case CHOLMOD_REAL:
603  for (j = 0 ; j < n ; j++)
604  {
605  ASSERT (Lp [j] < Lp [j+1]) ;
606  p = Lp [j] ;
607  Li [p] = j ;
608  Lx [p] = 1 ;
609  }
610  break ;
611 
612  case CHOLMOD_COMPLEX:
613  for (j = 0 ; j < n ; j++)
614  {
615  ASSERT (Lp [j] < Lp [j+1]) ;
616  p = Lp [j] ;
617  Li [p] = j ;
618  Lx [2*p ] = 1 ;
619  Lx [2*p+1] = 0 ;
620  }
621  break ;
622 
623  case CHOLMOD_ZOMPLEX:
624  for (j = 0 ; j < n ; j++)
625  {
626  ASSERT (Lp [j] < Lp [j+1]) ;
627  p = Lp [j] ;
628  Li [p] = j ;
629  Lx [p] = 1 ;
630  Lz [p] = 0 ;
631  }
632  break ;
633  }
634  }
635 
636  L->is_ll = to_ll ;
637 
638  PRINT1 (("done convert simplicial symbolic to numeric\n")) ;
639 }
640 
641 
642 /* ========================================================================== */
643 /* === change_simplicial_numeric ============================================ */
644 /* ========================================================================== */
645 
646 /* Change LL' to LDL', LDL' to LL', or leave as-is.
647  *
648  * If to_packed is TRUE, then the columns of L are packed and made monotonic
649  * (to_monotonic is ignored; it is implicitly TRUE).
650  *
651  * If to_monotonic is TRUE but to_packed is FALSE, the columns of L are made
652  * monotonic but not packed.
653  *
654  * If both to_packed and to_monotonic are FALSE, then the columns of L are
655  * left as-is, and the conversion is done in place.
656  *
657  * If L is already monotonic, or if it is to be left non-monotonic, then this
658  * conversion always succeeds.
659  *
660  * When converting an LDL' to LL' factorization, any column with a negative
661  * or zero diagonal entry is not modified so that conversion back to LDL' will
662  * succeed. This can result in a matrix L with a negative entry on the diagonal
663  * If the kth entry on the diagonal of D is negative, it and the kth column of
664  * L are left unchanged. A subsequent conversion back to an LDL' form will also
665  * leave the column unchanged, so the correct LDL' factorization will be
666  * restored. L->minor is set to the smallest k for which D (k,k) is negative.
667  */
668 
669 static void change_simplicial_numeric
670 (
671  cholmod_factor *L,
672  int to_ll,
673  int to_packed,
674  int to_monotonic,
675  cholmod_common *Common
676 )
677 {
678  double grow0, grow1, xlen, xlnz ;
679  void *newLi, *newLx, *newLz ;
680  double *Lx, *Lz ;
681  Int *Lp, *Li, *Lnz ;
682  Int make_monotonic, grow2, n, j, lnz, len, grow, ok, make_ll, make_ldl ;
683  size_t nzmax0 ;
684 
685  PRINT1 (("\n===Change simplicial numeric: %d %d %d\n",
686  to_ll, to_packed, to_monotonic)) ;
687  DEBUG (CHOLMOD(dump_factor) (L, "change simplicial numeric", Common)) ;
688  ASSERT (L->xtype != CHOLMOD_PATTERN && !(L->is_super)) ;
689 
690  make_monotonic = ((to_packed || to_monotonic) && !(L->is_monotonic)) ;
691  make_ll = (to_ll && !(L->is_ll)) ;
692  make_ldl = (!to_ll && L->is_ll) ;
693 
694  n = L->n ;
695  Lp = L->p ;
696  Li = L->i ;
697  Lx = L->x ;
698  Lz = L->z ;
699  Lnz = L->nz ;
700 
701  grow = FALSE ;
702  grow0 = Common->grow0 ;
703  grow1 = Common->grow1 ;
704  grow2 = Common->grow2 ;
705  grow0 = IS_NAN (grow0) ? 1 : grow0 ;
706  grow1 = IS_NAN (grow1) ? 1 : grow1 ;
707  ok = TRUE ;
708  newLi = NULL ;
709  newLx = NULL ;
710  newLz = NULL ;
711  lnz = 0 ;
712 
713  if (make_monotonic)
714  {
715 
716  /* ------------------------------------------------------------------ */
717  /* Columns out of order, but will be reordered and optionally packed. */
718  /* ------------------------------------------------------------------ */
719 
720  PRINT1 (("L is non-monotonic\n")) ;
721 
722  /* compute new L->nzmax */
723  if (!to_packed)
724  {
725  /* if any parameter is NaN, grow is false */
726  /* fl.pt. comparisons below are false if any parameter is NaN */
727  grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ;
728  }
729  for (j = 0 ; ok && j < n ; j++)
730  {
731  len = Lnz [j] ;
732  ASSERT (len >= 1 && len <= n-j) ;
733 
734  /* compute len in double to avoid integer overflow */
735  if (grow)
736  {
737  xlen = (double) len ;
738  xlen = grow1 * xlen + grow2 ;
739  xlen = MIN (xlen, n-j) ;
740  len = (Int) xlen ;
741  }
742  ASSERT (len >= Lnz [j] && len <= n-j) ;
743 
744  PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n",
745  j, Lnz [j], len, lnz)) ;
746 
747  lnz += len ;
748  ok = (lnz >= 0) ;
749  }
750 
751  if (!ok)
752  {
753  ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
754  return ;
755  }
756 
757  if (grow)
758  {
759  xlnz = (double) lnz ;
760  xlnz *= grow0 ;
761  xlnz = MIN (xlnz, Size_max) ;
762  xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ;
763  lnz = (Int) xlnz ;
764  }
765 
766  lnz = MAX (1, lnz) ;
767  PRINT1 (("final lnz "ID"\n", lnz)) ;
768  nzmax0 = 0 ;
769 
770  CHOLMOD(realloc_multiple) (lnz, 1, L->xtype, &newLi, NULL,
771  &newLx, &newLz, &nzmax0, Common) ;
772 
773  if (Common->status < CHOLMOD_OK)
774  {
775  return ; /* out of memory */
776  }
777  }
778 
779  /* ============================================== commit the changes to L */
780 
781  /* ---------------------------------------------------------------------- */
782  /* convert the simplicial L, using template routine */
783  /* ---------------------------------------------------------------------- */
784 
785  switch (L->xtype)
786  {
787 
788  case CHOLMOD_REAL:
789  amesos_r_change_simplicial_numeric (L, to_ll, to_packed,
790  newLi, newLx, newLz, lnz, grow, grow1, grow2,
791  make_ll, make_monotonic, make_ldl, Common) ;
792  break ;
793 
794  case CHOLMOD_COMPLEX:
795  amesos_c_change_simplicial_numeric (L, to_ll, to_packed,
796  newLi, newLx, newLz, lnz, grow, grow1, grow2,
797  make_ll, make_monotonic, make_ldl, Common) ;
798  break ;
799 
800  case CHOLMOD_ZOMPLEX:
801  amesos_z_change_simplicial_numeric (L, to_ll, to_packed,
802  newLi, newLx, newLz, lnz, grow, grow1, grow2,
803  make_ll, make_monotonic, make_ldl, Common) ;
804  break ;
805  }
806 
807  DEBUG (CHOLMOD(dump_factor) (L, "L simplicial changed", Common)) ;
808 }
809 
810 
811 /* ========================================================================== */
812 /* === ll_super_to_simplicial_numeric ======================================= */
813 /* ========================================================================== */
814 
815 /* Convert a supernodal numeric factorization to any simplicial numeric one.
816  * Leaves L->xtype unchanged (real or complex, not zomplex since there is
817  * no supernodal zomplex L). */
818 
820 (
821  cholmod_factor *L,
822  int to_packed,
823  int to_ll,
824  cholmod_common *Common
825 )
826 {
827  Int *Ls, *Lpi, *Lpx, *Super, *Li ;
828  Int n, lnz, s, nsuper, psi, psend, nsrow, nscol, k1, k2, erows ;
829 
830  DEBUG (CHOLMOD(dump_factor) (L, "start LL super to simplicial", Common)) ;
831  PRINT1 (("super -> simplicial (%d %d)\n", to_packed, to_ll)) ;
832  ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_ll && L->is_super) ;
833  ASSERT (L->x != NULL && L->i == NULL) ;
834 
835  n = L->n ;
836  nsuper = L->nsuper ;
837  Lpi = L->pi ;
838  Lpx = L->px ;
839  Ls = L->s ;
840  Super = L->super ;
841 
842  /* Int overflow cannot occur since supernodal L already exists */
843 
844  if (to_packed)
845  {
846  /* count the number of nonzeros in L. Each supernode is of the form
847  *
848  * l . . . For this example, nscol = 4 (# columns). nsrow = 9.
849  * l l . . The "." entries are allocated in the supernodal
850  * l l l . factor, but not used. They are not copied to the
851  * l l l l simplicial factor. Some "l" and "e" entries may be
852  * e e e e numerically zero and even symbolically zero if a
853  * e e e e tight simplicial factorization or resymbol were
854  * e e e e done, because of numerical cancellation and relaxed
855  * e e e e supernode amalgamation, respectively.
856  * e e e e
857  */
858  lnz = 0 ;
859  for (s = 0 ; s < nsuper ; s++)
860  {
861  k1 = Super [s] ;
862  k2 = Super [s+1] ;
863  psi = Lpi [s] ;
864  psend = Lpi [s+1] ;
865  nsrow = psend - psi ;
866  nscol = k2 - k1 ;
867  ASSERT (nsrow >= nscol) ;
868  erows = nsrow - nscol ;
869 
870  /* lower triangular part, including the diagonal,
871  * counting the "l" terms in the figure above. */
872  lnz += nscol * (nscol+1) / 2 ;
873 
874  /* rectangular part, below the diagonal block (the "e" terms) */
875  lnz += nscol * erows ;
876  }
877  ASSERT (lnz <= (Int) (L->xsize)) ;
878  }
879  else
880  {
881  /* Li will be the same size as Lx */
882  lnz = L->xsize ;
883  }
884  ASSERT (lnz >= 0) ;
885  PRINT1 (("simplicial lnz = "ID" to_packed: %d to_ll: %d L->xsize %g\n",
886  lnz, to_ll, to_packed, (double) L->xsize)) ;
887 
888  Li = CHOLMOD(malloc) (lnz, sizeof (Int), Common) ;
889  if (Common->status < CHOLMOD_OK)
890  {
891  return ; /* out of memory */
892  }
893 
894  if (!allocate_simplicial_numeric (L, Common))
895  {
896  CHOLMOD(free) (lnz, sizeof (Int), Li, Common) ;
897  return ; /* out of memory */
898  }
899 
900  /* ============================================== commit the changes to L */
901 
902  L->i = Li ;
903  L->nzmax = lnz ;
904 
905  /* ---------------------------------------------------------------------- */
906  /* convert the supernodal L, using template routine */
907  /* ---------------------------------------------------------------------- */
908 
909  switch (L->xtype)
910  {
911 
912  case CHOLMOD_REAL:
913  amesos_r_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
914  break ;
915 
916  case CHOLMOD_COMPLEX:
917  amesos_c_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
918  break ;
919  }
920 
921  /* ---------------------------------------------------------------------- */
922  /* free unused parts of L */
923  /* ---------------------------------------------------------------------- */
924 
925  L->super = CHOLMOD(free) (nsuper+1, sizeof (Int), L->super, Common) ;
926  L->pi = CHOLMOD(free) (nsuper+1, sizeof (Int), L->pi, Common) ;
927  L->px = CHOLMOD(free) (nsuper+1, sizeof (Int), L->px, Common) ;
928  L->s = CHOLMOD(free) (L->ssize, sizeof (Int), L->s, Common) ;
929 
930  L->ssize = 0 ;
931  L->xsize = 0 ;
932  L->nsuper = 0 ;
933  L->maxesize = 0 ;
934  L->maxcsize = 0 ;
935 
936  L->is_super = FALSE ;
937 
938  DEBUG (CHOLMOD(dump_factor) (L, "done LL super to simplicial", Common)) ;
939 }
940 
941 
942 /* ========================================================================== */
943 /* === super_symbolic_to_ll_super =========================================== */
944 /* ========================================================================== */
945 
946 /* Convert a supernodal symbolic factorization to a supernodal numeric
947  * factorization by allocating L->x. Contents of L->x are undefined.
948  */
949 
951 (
952  int to_xtype,
953  cholmod_factor *L,
954  cholmod_common *Common
955 )
956 {
957  double *Lx ;
958  Int wentry = (to_xtype == CHOLMOD_REAL) ? 1 : 2 ;
959  PRINT1 (("convert super sym to num\n")) ;
960  ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_super) ;
961  Lx = CHOLMOD(malloc) (L->xsize, wentry * sizeof (double), Common) ;
962  PRINT1 (("xsize %g\n", (double) L->xsize)) ;
963  if (Common->status < CHOLMOD_OK)
964  {
965  return (FALSE) ; /* out of memory */
966  }
967 
968  /* ============================================== commit the changes to L */
969 
970  if (L->xsize == 1)
971  {
972  /* the caller won't expect to access this entry, but some CHOLMOD
973  * routines may. Set it to zero so that valgrind doesn't complain. */
974  switch (to_xtype)
975  {
976  case CHOLMOD_REAL:
977  Lx [0] = 0 ;
978  break ;
979 
980  case CHOLMOD_COMPLEX:
981  Lx [0] = 0 ;
982  Lx [1] = 0 ;
983  break ;
984  }
985  }
986 
987  L->x = Lx ;
988  L->xtype = to_xtype ;
989  L->dtype = DTYPE ;
990  L->minor = L->n ;
991  return (TRUE) ;
992 }
993 
994 
995 /* ========================================================================== */
996 /* === cholmod_change_factor ================================================ */
997 /* ========================================================================== */
998 
999 /* Convert a factor L. Some conversions simply allocate uninitialized space
1000  * that meant to be filled later.
1001  *
1002  * If the conversion fails, the factor is left in its original form, with one
1003  * exception. Converting a supernodal symbolic factor to a simplicial numeric
1004  * one (with L=D=I) may leave the factor in simplicial symbolic form.
1005  *
1006  * Memory allocated for each conversion is listed below.
1007  */
1008 
1011  /* ---- input ---- */
1012  int to_xtype, /* convert to CHOLMOD_PATTERN, _REAL, _COMPLEX, or
1013  * _ZOMPLEX */
1014  int to_ll, /* TRUE: convert to LL', FALSE: LDL' */
1015  int to_super, /* TRUE: convert to supernodal, FALSE: simplicial */
1016  int to_packed, /* TRUE: pack simplicial columns, FALSE: do not pack */
1017  int to_monotonic, /* TRUE: put simplicial columns in order, FALSE: not */
1018  /* ---- in/out --- */
1019  cholmod_factor *L, /* factor to modify */
1020  /* --------------- */
1021  cholmod_common *Common
1022 )
1023 {
1024 
1025  /* ---------------------------------------------------------------------- */
1026  /* get inputs */
1027  /* ---------------------------------------------------------------------- */
1028 
1030  RETURN_IF_NULL (L, FALSE) ;
1032  if (to_xtype < CHOLMOD_PATTERN || to_xtype > CHOLMOD_ZOMPLEX)
1033  {
1034  ERROR (CHOLMOD_INVALID, "xtype invalid") ;
1035  return (FALSE) ;
1036  }
1037  Common->status = CHOLMOD_OK ;
1038 
1039  PRINT1 (("-----convert from (%d,%d,%d,%d,%d) to (%d,%d,%d,%d,%d)\n",
1040  L->xtype, L->is_ll, L->is_super, L_is_packed (L, Common), L->is_monotonic,
1041  to_xtype, to_ll, to_super, to_packed, to_monotonic)) ;
1042 
1043  /* ensure all parameters are TRUE/FALSE */
1044  to_ll = BOOLEAN (to_ll) ;
1045  to_super = BOOLEAN (to_super) ;
1046 
1047  ASSERT (BOOLEAN (L->is_ll) == L->is_ll) ;
1048  ASSERT (BOOLEAN (L->is_super) == L->is_super) ;
1049 
1050  if (to_super && to_xtype == CHOLMOD_ZOMPLEX)
1051  {
1052  ERROR (CHOLMOD_INVALID, "supernodal zomplex L not supported") ;
1053  return (FALSE) ;
1054  }
1055 
1056  /* ---------------------------------------------------------------------- */
1057  /* convert */
1058  /* ---------------------------------------------------------------------- */
1059 
1060  if (to_xtype == CHOLMOD_PATTERN)
1061  {
1062 
1063  /* ------------------------------------------------------------------ */
1064  /* convert to symbolic */
1065  /* ------------------------------------------------------------------ */
1066 
1067  if (!to_super)
1068  {
1069 
1070  /* -------------------------------------------------------------- */
1071  /* convert any factor into a simplicial symbolic factor */
1072  /* -------------------------------------------------------------- */
1073 
1074  any_to_simplicial_symbolic (L, to_ll, Common) ; /* cannot fail */
1075 
1076  }
1077  else
1078  {
1079 
1080  /* -------------------------------------------------------------- */
1081  /* convert to a supernodal symbolic factor */
1082  /* -------------------------------------------------------------- */
1083 
1084  if (L->xtype != CHOLMOD_PATTERN && L->is_super)
1085  {
1086  /* convert from supernodal numeric to supernodal symbolic.
1087  * this preserves symbolic pattern of L, discards numeric
1088  * values */
1089  ll_super_to_super_symbolic (L, Common) ; /* cannot fail */
1090  }
1091  else if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
1092  {
1093  /* convert from simplicial symbolic to supernodal symbolic.
1094  * contents of supernodal pattern are uninitialized. Not meant
1095  * for the end user. */
1097  }
1098  else
1099  {
1100  /* cannot convert from simplicial numeric to supernodal
1101  * symbolic */
1103  "cannot convert L to supernodal symbolic") ;
1104  }
1105  }
1106 
1107  }
1108  else
1109  {
1110 
1111  /* ------------------------------------------------------------------ */
1112  /* convert to numeric */
1113  /* ------------------------------------------------------------------ */
1114 
1115  if (to_super)
1116  {
1117 
1118  /* -------------------------------------------------------------- */
1119  /* convert to supernodal numeric factor */
1120  /* -------------------------------------------------------------- */
1121 
1122  if (L->xtype == CHOLMOD_PATTERN)
1123  {
1124  if (L->is_super)
1125  {
1126  /* Convert supernodal symbolic to supernodal numeric.
1127  * Contents of supernodal numeric values are uninitialized.
1128  * This is used by cholmod_super_numeric. Not meant for
1129  * the end user. */
1130  super_symbolic_to_ll_super (to_xtype, L, Common) ;
1131  }
1132  else
1133  {
1134  /* Convert simplicial symbolic to supernodal numeric.
1135  * Contents not defined. This is used by
1136  * Core/cholmod_copy_factor only. Not meant for the end
1137  * user. */
1138  if (!simplicial_symbolic_to_super_symbolic (L, Common))
1139  {
1140  /* failure, convert back to simplicial symbolic */
1141  any_to_simplicial_symbolic (L, to_ll, Common) ;
1142  }
1143  else
1144  {
1145  /* conversion to super symbolic OK, allocate numeric
1146  * part */
1147  super_symbolic_to_ll_super (to_xtype, L, Common) ;
1148  }
1149  }
1150  }
1151  else
1152  {
1153  /* nothing to do if L is already in supernodal numeric form */
1154  if (!(L->is_super))
1155  {
1157  "cannot convert simplicial L to supernodal") ;
1158  }
1159  /* FUTURE WORK: convert to/from supernodal LL' and LDL' */
1160  }
1161 
1162  }
1163  else
1164  {
1165 
1166  /* -------------------------------------------------------------- */
1167  /* convert any factor to simplicial numeric */
1168  /* -------------------------------------------------------------- */
1169 
1170  if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
1171  {
1172 
1173  /* ---------------------------------------------------------- */
1174  /* convert simplicial symbolic to simplicial numeric (L=I,D=I)*/
1175  /* ---------------------------------------------------------- */
1176 
1177  simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed,
1178  to_xtype, Common) ;
1179 
1180  }
1181  else if (L->xtype != CHOLMOD_PATTERN && L->is_super)
1182  {
1183 
1184  /* ---------------------------------------------------------- */
1185  /* convert a supernodal LL' to simplicial numeric */
1186  /* ---------------------------------------------------------- */
1187 
1188  ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
1189 
1190  }
1191  else if (L->xtype == CHOLMOD_PATTERN && L->is_super)
1192  {
1193 
1194  /* ---------------------------------------------------------- */
1195  /* convert a supernodal symbolic to simplicial numeric (L=D=I)*/
1196  /* ---------------------------------------------------------- */
1197 
1198  any_to_simplicial_symbolic (L, to_ll, Common) ;
1199  /* if the following fails, it leaves the factor in simplicial
1200  * symbolic form */
1201  simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed,
1202  to_xtype, Common) ;
1203 
1204  }
1205  else
1206  {
1207 
1208  /* ---------------------------------------------------------- */
1209  /* change a simplicial numeric factor */
1210  /* ---------------------------------------------------------- */
1211 
1212  /* change LL' to LDL', LDL' to LL', or leave as-is. pack the
1213  * columns of L, or leave as-is. Ensure the columns are
1214  * monotonic, or leave as-is. */
1215 
1216  change_simplicial_numeric (L, to_ll, to_packed, to_monotonic,
1217  Common) ;
1218  }
1219  }
1220  }
1221 
1222  /* ---------------------------------------------------------------------- */
1223  /* return result */
1224  /* ---------------------------------------------------------------------- */
1225 
1226  return (Common->status >= CHOLMOD_OK) ;
1227 }
static void simplicial_symbolic_to_simplicial_numeric(cholmod_factor *L, int to_ll, int packed, int to_xtype, cholmod_common *Common)
#define CHOLMOD_TOO_LARGE
static void ll_super_to_simplicial_numeric(cholmod_factor *L, int to_packed, int to_ll, cholmod_common *Common)
#define EMPTY
int CHOLMOD() realloc_multiple(size_t nnew, int nint, int xtype, void **I, void **J, void **X, void **Z, size_t *nold_p, cholmod_common *Common)
#define Int
#define CHOLMOD_COMPLEX
#define FALSE
#define PRINT1(params)
#define PRINT3(params)
#define RETURN_IF_NULL_COMMON(result)
static void any_to_simplicial_symbolic(cholmod_factor *L, int to_ll, cholmod_common *Common)
#define CHOLMOD_PATTERN
#define CHOLMOD(name)
#define BOOLEAN(x)
#define MAX(a, b)
#define CHOLMOD_REAL
#define NULL
#define ASSERT(expression)
#define PRINT2(params)
static void ll_super_to_super_symbolic(cholmod_factor *L, cholmod_common *Common)
#define ID
static int L_is_packed(cholmod_factor *L, cholmod_common *Common)
#define DTYPE
#define CHOLMOD_INVALID
#define CHOLMOD_OK
static int allocate_simplicial_numeric(cholmod_factor *L, cholmod_common *Common)
static int super_symbolic_to_ll_super(int to_xtype, cholmod_factor *L, cholmod_common *Common)
#define Size_max
static int simplicial_symbolic_to_super_symbolic(cholmod_factor *L, cholmod_common *Common)
#define RETURN_IF_NULL(A, result)
#define IS_NAN(x)
#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)
#define MIN(a, b)
int CHOLMOD() dump_factor(cholmod_factor *L, char *name, cholmod_common *Common)
static void natural_list(cholmod_factor *L)
int n
#define ERROR(status, msg)
#define TRUE
#define RETURN_IF_XTYPE_INVALID(A, xtype1, xtype2, result)
#define CHOLMOD_ZOMPLEX
static void change_simplicial_numeric(cholmod_factor *L, int to_ll, int to_packed, int to_monotonic, cholmod_common *Common)