Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_cholmod_l_analyze.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === Cholesky/cholmod_analyze ============================================= */
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 /* Order and analyze a matrix (either simplicial or supernodal), in prepartion
14  * for numerical factorization via cholmod_factorize or via the "expert"
15  * routines cholmod_rowfac and cholmod_super_numeric.
16  *
17  * symmetric case: A or A(p,p)
18  * unsymmetric case: AA', A(p,:)*A(p,:)', A(:,f)*A(:,f)', or A(p,f)*A(p,f)'
19  *
20  * For the symmetric case, only the upper or lower triangular part of A is
21  * accessed (depending on the type of A). LL'=A (or permuted A) is analzed.
22  * For the unsymmetric case (LL'=AA' or permuted A).
23  *
24  * There can be no duplicate entries in p or f. p is of length m if A is
25  * m-by-n. f can be length 0 to n.
26  *
27  * In both cases, the columns of A need not be sorted. A can be in packed
28  * or unpacked form.
29  *
30  * Ordering options include:
31  *
32  * natural: A is not permuted to reduce fill-in
33  * given: a permutation can be provided to this routine (UserPerm)
34  * AMD: approximate minumum degree (AMD for the symmetric case,
35  * COLAMD for the AA' case).
36  * METIS: nested dissection with METIS_NodeND
37  * NESDIS: nested dissection using METIS_NodeComputeSeparator,
38  * typically followed by a constrained minimum degree
39  * (CAMD for the symmetric case, CCOLAMD for the AA' case).
40  *
41  * Multiple ordering options can be tried (up to 9 of them), and the best one
42  * is selected (the one that gives the smallest number of nonzeros in the
43  * simplicial factor L). If one method fails, cholmod_analyze keeps going, and
44  * picks the best among the methods that succeeded. This routine fails (and
45  * returns NULL) if either initial memory allocation fails, all ordering methods
46  * fail, or the supernodal analysis (if requested) fails. By default, the 9
47  * methods available are:
48  *
49  * 1) given permutation (skipped if UserPerm is NULL)
50  * 2) AMD (symmetric case) or COLAMD (unsymmetric case)
51  * 3) METIS with default parameters
52  * 4) NESDIS with default parameters (stopping the partitioning when
53  * the graph is of size nd_small = 200 or less, remove nodes with
54  * more than max (16, prune_dense * sqrt (n)) nodes where
55  * prune_dense = 10, and follow partitioning with CCOLAMD, a
56  * constrained minimum degree ordering).
57  * 5) natural
58  * 6) NESDIS, nd_small = 20000, prune_dense = 10
59  * 7) NESDIS, nd_small = 4, prune_dense = 10, no min degree
60  * 8) NESDIS, nd_small = 200, prune_dense = 0
61  * 9) COLAMD for A*A' or AMD for A
62  *
63  * By default, the first two are tried, and METIS is tried if AMD reports a high
64  * flop count and fill-in. Let fl denote the flop count for the AMD, ordering,
65  * nnz(L) the # of nonzeros in L, and nnz(tril(A)) (or A*A'). If
66  * fl/nnz(L) >= 500 and nnz(L)/nnz(tril(A)) >= 5, then METIS is attempted. The
67  * best ordering is used (UserPerm if given, AMD, and METIS if attempted). If
68  * you do not have METIS, only the first two will be tried (user permutation,
69  * if provided, and AMD/COLAMD). This default behavior is obtained when
70  * Common->nmethods is zero. In this case, methods 0, 1, and 2 in
71  * Common->method [..] are reset to User-provided, AMD, and METIS (or NESDIS
72  * if Common->default_nesdis is set to the non-default value of TRUE),
73  * respectively.
74  *
75  * You can modify these 9 methods and the number of methods tried by changing
76  * parameters in the Common argument. If you know the best ordering for your
77  * matrix, set Common->nmethods to 1 and set Common->method[0].ordering to the
78  * requested ordering method. Parameters for each method can also be modified
79  * (refer to cholmod.h for details).
80  *
81  * Note that it is possible for METIS to terminate your program if it runs out
82  * of memory. This is not the case for any CHOLMOD or minimum degree ordering
83  * routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). Since NESDIS relies on
84  * METIS, it too can terminate your program.
85  *
86  * The factor L is returned as simplicial symbolic (L->is_super FALSE) if
87  * Common->supernodal <= CHOLMOD_SIMPLICIAL (0) or as supernodal symbolic if
88  * Common->supernodal >= CHOLMOD_SUPERNODAL (2). If Common->supernodal is
89  * equal to CHOLMOD_AUTO (1), then L is simplicial if the flop count per
90  * nonzero in L is less than Common->supernodal_switch (default: 40), and
91  * is returned as a supernodal factor otherwise.
92  *
93  * In both cases, L->xtype is CHOLMOD_PATTERN.
94  * A subsequent call to cholmod_factorize will perform a
95  * simplicial or supernodal factorization, depending on the type of L.
96  *
97  * For the simplicial case, L contains the fill-reducing permutation (L->Perm)
98  * and the counts of nonzeros in each column of L (L->ColCount). For the
99  * supernodal case, L also contains the nonzero pattern of each supernode.
100  *
101  * workspace: Flag (nrow), Head (nrow+1)
102  * if symmetric: Iwork (6*nrow)
103  * if unsymmetric: Iwork (6*nrow+ncol).
104  * calls various ordering routines, which typically allocate O(nnz(A))
105  * temporary workspace ((2 to 3)*nnz(A) * sizeof (Int) is typical, but it
106  * can be much higher if A*A' must be explicitly formed for METIS). Also
107  * allocates up to 2 temporary (permuted/transpose) copies of the nonzero
108  * pattern of A, and up to 3*n*sizeof(Int) additional workspace.
109  *
110  * Supports any xtype (pattern, real, complex, or zomplex)
111  */
112 
113 #ifndef NCHOLESKY
114 
115 /* This file should make the long int version of CHOLMOD */
116 #define DLONG 1
117 
118 #include "amesos_cholmod_internal.h"
119 #include "amesos_cholmod_cholesky.h"
120 
121 #ifndef NPARTITION
123 #endif
124 
125 
126 /* ========================================================================== */
127 /* === cholmod_analyze ====================================================== */
128 /* ========================================================================== */
129 
130 /* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor
131  * that can later be passed to cholmod_factorize. */
132 
134 (
135  /* ---- input ---- */
136  cholmod_sparse *A, /* matrix to order and analyze */
137  /* --------------- */
138  cholmod_common *Common
139 )
140 {
141  return (CHOLMOD(analyze_p) (A, NULL, NULL, 0, Common)) ;
142 }
143 
144 
145 /* ========================================================================== */
146 /* === permute_matrices ===================================================== */
147 /* ========================================================================== */
148 
149 /* Permute and transpose a matrix. Allocates the A1 and A2 matrices, if needed,
150  * or returns them as NULL if not needed.
151  */
152 
153 static int amesos_permute_matrices
154 (
155  /* ---- input ---- */
156  cholmod_sparse *A, /* matrix to permute */
157  Int ordering, /* ordering method used */
158  Int *Perm, /* fill-reducing permutation */
159  Int *fset, /* subset of 0:(A->ncol)-1 */
160  size_t fsize, /* size of fset */
161  Int do_rowcolcounts,/* if TRUE, compute both S and F. If FALSE, only
162  * S is needed for the symmetric case, and only F for
163  * the unsymmetric case */
164  /* ---- output --- */
165  cholmod_sparse **A1_handle, /* see comments below for A1, A2, S, F */
166  cholmod_sparse **A2_handle,
167  cholmod_sparse **S_handle,
168  cholmod_sparse **F_handle,
169  /* --------------- */
170  cholmod_common *Common
171 )
172 {
173  cholmod_sparse *A1, *A2, *S, *F ;
174 
175  *A1_handle = NULL ;
176  *A2_handle = NULL ;
177  *S_handle = NULL ;
178  *F_handle = NULL ;
179  A1 = NULL ;
180  A2 = NULL ;
181 
182  if (ordering == CHOLMOD_NATURAL)
183  {
184 
185  /* ------------------------------------------------------------------ */
186  /* natural ordering of A */
187  /* ------------------------------------------------------------------ */
188 
189  if (A->stype < 0)
190  {
191  /* symmetric lower case: A already in lower form, so S=A' */
192  /* workspace: Iwork (nrow) */
193  A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ;
194  F = A ;
195  S = A2 ;
196  }
197  else if (A->stype > 0)
198  {
199  /* symmetric upper case: F = pattern of triu (A)', S = A */
200  /* workspace: Iwork (nrow) */
201  if (do_rowcolcounts)
202  {
203  /* F not needed for symmetric case if do_rowcolcounts FALSE */
204  A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ;
205  }
206  F = A1 ;
207  S = A ;
208  }
209  else
210  {
211  /* unsymmetric case: F = pattern of A (:,f)', S = A */
212  /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */
213  A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ;
214  F = A1 ;
215  S = A ;
216  }
217 
218  }
219  else
220  {
221 
222  /* ------------------------------------------------------------------ */
223  /* A is permuted */
224  /* ------------------------------------------------------------------ */
225 
226  if (A->stype < 0)
227  {
228  /* symmetric lower case: S = tril (A (p,p))' and F = S' */
229  /* workspace: Iwork (2*nrow) */
230  A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ;
231  S = A2 ;
232  /* workspace: Iwork (nrow) */
233  if (do_rowcolcounts)
234  {
235  /* F not needed for symmetric case if do_rowcolcounts FALSE */
236  A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ;
237  }
238  F = A1 ;
239  }
240  else if (A->stype > 0)
241  {
242  /* symmetric upper case: F = triu (A (p,p))' and S = F' */
243  /* workspace: Iwork (2*nrow) */
244  A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ;
245  F = A1 ;
246  /* workspace: Iwork (nrow) */
247  A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ;
248  S = A2 ;
249  }
250  else
251  {
252  /* unsymmetric case: F = A (p,f)' and S = F' */
253  /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */
254  A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ;
255  F = A1 ;
256  if (do_rowcolcounts)
257  {
258  /* S not needed for unsymmetric case if do_rowcolcounts FALSE */
259  /* workspace: Iwork (nrow) */
260  A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ;
261  }
262  S = A2 ;
263  }
264  }
265 
266  /* If any cholmod_*transpose fails, one or more matrices will be NULL */
267  *A1_handle = A1 ;
268  *A2_handle = A2 ;
269  *S_handle = S ;
270  *F_handle = F ;
271  return (Common->status == CHOLMOD_OK) ;
272 }
273 
274 
275 /* ========================================================================== */
276 /* === cholmod_analyze_ordering ============================================= */
277 /* ========================================================================== */
278 
279 /* Given a matrix A and its fill-reducing permutation, compute the elimination
280  * tree, its (non-weighted) postordering, and the number of nonzeros in each
281  * column of L. Also computes the flop count, the total nonzeros in L, and
282  * the nonzeros in A (Common->fl, Common->lnz, and Common->anz).
283  *
284  * The column counts of L, flop count, and other statistics from
285  * cholmod_rowcolcounts are not computed if ColCount is NULL.
286  *
287  * workspace: Iwork (2*nrow if symmetric, 2*nrow+ncol if unsymmetric),
288  * Flag (nrow), Head (nrow+1)
289  */
290 
292 (
293  /* ---- input ---- */
294  cholmod_sparse *A, /* matrix to analyze */
295  int ordering, /* ordering method used */
296  Int *Perm, /* size n, fill-reducing permutation to analyze */
297  Int *fset, /* subset of 0:(A->ncol)-1 */
298  size_t fsize, /* size of fset */
299  /* ---- output --- */
300  Int *Parent, /* size n, elimination tree */
301  Int *Post, /* size n, postordering of elimination tree */
302  Int *ColCount, /* size n, nnz in each column of L */
303  /* ---- workspace */
304  Int *First, /* size nworkspace for cholmod_postorder */
305  Int *Level, /* size n workspace for cholmod_postorder */
306  /* --------------- */
307  cholmod_common *Common
308 )
309 {
310  cholmod_sparse *A1, *A2, *S, *F ;
311  Int n, ok, do_rowcolcounts ;
312 
313  /* check inputs */
315  RETURN_IF_NULL (A, FALSE) ;
316 
317  n = A->nrow ;
318 
319  do_rowcolcounts = (ColCount != NULL) ;
320 
321  /* permute A according to Perm and fset */
322  ok = amesos_permute_matrices (A, ordering, Perm, fset, fsize, do_rowcolcounts,
323  &A1, &A2, &S, &F, Common) ;
324 
325  /* find etree of S (symmetric upper/lower case) or F (unsym case) */
326  /* workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) */
327  ok = ok && CHOLMOD(etree) (A->stype ? S:F, Parent, Common) ;
328 
329  /* postorder the etree (required by cholmod_rowcolcounts) */
330  /* workspace: Iwork (2*nrow) */
331  ok = ok && (CHOLMOD(postorder) (Parent, n, NULL, Post, Common) == n) ;
332 
333  /* cholmod_postorder doesn't set Common->status if it returns < n */
334  Common->status = (!ok && Common->status == CHOLMOD_OK) ?
335  CHOLMOD_INVALID : Common->status ;
336 
337  /* analyze LL'=S or SS' or S(:,f)*S(:,f)' */
338  /* workspace:
339  * if symmetric: Flag (nrow), Iwork (2*nrow)
340  * if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1)
341  */
342  if (do_rowcolcounts)
343  {
344  ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent,
345  Post, NULL, ColCount, First, Level, Common) ;
346  }
347 
348  /* free temporary matrices and return result */
349  CHOLMOD(free_sparse) (&A1, Common) ;
350  CHOLMOD(free_sparse) (&A2, Common) ;
351  return (ok) ;
352 }
353 
354 
355 /* ========================================================================== */
356 /* === Free workspace and return L ========================================== */
357 /* ========================================================================== */
358 
359 #define FREE_WORKSPACE_AND_RETURN \
360 { \
361  Common->no_workspace_reallocate = FALSE ; \
362  CHOLMOD(free) (n, sizeof (Int), Lparent, Common) ; \
363  CHOLMOD(free) (n, sizeof (Int), Perm, Common) ; \
364  CHOLMOD(free) (n, sizeof (Int), ColCount, Common) ; \
365  if (Common->status < CHOLMOD_OK) \
366  { \
367  CHOLMOD(free_factor) (&L, Common) ; \
368  } \
369  ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \
370  return (L) ; \
371 }
372 
373 
374 /* ========================================================================== */
375 /* === cholmod_analyze_p ==================================================== */
376 /* ========================================================================== */
377 
378 /* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a
379  * symbolic factor that can later be passed to cholmod_factorize, where
380  * F = A(:,fset) if fset is not NULL and A->stype is zero.
381  * UserPerm is tried if non-NULL. */
382 
384 (
385  /* ---- input ---- */
386  cholmod_sparse *A, /* matrix to order and analyze */
387  Int *UserPerm, /* user-provided permutation, size A->nrow */
388  Int *fset, /* subset of 0:(A->ncol)-1 */
389  size_t fsize, /* size of fset */
390  /* --------------- */
391  cholmod_common *Common
392 )
393 {
394  double lnz_best ;
395  Int *First, *Level, *Work4n, *Cmember, *CParent, *ColCount, *Lperm, *Parent,
396  *Post, *Perm, *Lparent, *Lcolcount ;
397  cholmod_factor *L ;
398  Int k, n, ordering, method, nmethods, status, default_strategy, ncol, uncol,
399  skip_analysis, skip_best ;
400  size_t s ;
401  int ok = TRUE ;
402 
403  /* ---------------------------------------------------------------------- */
404  /* check inputs */
405  /* ---------------------------------------------------------------------- */
406 
408  RETURN_IF_NULL (A, NULL) ;
410  Common->status = CHOLMOD_OK ;
411  status = CHOLMOD_OK ;
412  Common->selected = EMPTY ;
413  Common->called_nd = FALSE ;
414 
415  /* ---------------------------------------------------------------------- */
416  /* get inputs */
417  /* ---------------------------------------------------------------------- */
418 
419  n = A->nrow ;
420  ncol = A->ncol ;
421  uncol = (A->stype == 0) ? (A->ncol) : 0 ;
422 
423  /* ---------------------------------------------------------------------- */
424  /* set the default strategy */
425  /* ---------------------------------------------------------------------- */
426 
427  lnz_best = (double) EMPTY ;
428  skip_best = FALSE ;
429  nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ;
430  nmethods = MAX (0, nmethods) ;
431  PRINT1 (("nmethods "ID"\n", nmethods)) ;
432 
433  default_strategy = (nmethods == 0) ;
434  if (default_strategy)
435  {
436  /* default strategy: try UserPerm, if given. Try AMD for A, or COLAMD
437  * to order A*A'. Try METIS for the symmetric case only if AMD reports
438  * a high degree of fill-in and flop count. Always try METIS for the
439  * unsymmetric case. METIS is not tried if the Partition Module
440  * isn't installed. If Common->default_nesdis is TRUE, then NESDIS
441  * is used as the 3rd ordering instead. */
442  Common->method [0].ordering = CHOLMOD_GIVEN ;/* skip if UserPerm NULL */
443  Common->method [1].ordering = CHOLMOD_AMD ;
444  Common->method [2].ordering =
446 #ifndef NPARTITION
447  nmethods = 3 ;
448 #else
449  nmethods = 2 ;
450 #endif
451  }
452 
453 #ifdef NSUPERNODAL
454  /* CHOLMOD Supernodal module not installed, just do simplicial analysis */
455  Common->supernodal = CHOLMOD_SIMPLICIAL ;
456 #endif
457 
458  /* ---------------------------------------------------------------------- */
459  /* allocate workspace */
460  /* ---------------------------------------------------------------------- */
461 
462  /* Note: enough space needs to be allocated here so that routines called by
463  * cholmod_analyze do not reallocate the space.
464  */
465 
466  /* s = 6*n + uncol */
467  s = CHOLMOD(mult_size_t) (n, 6, &ok) ;
468  s = CHOLMOD(add_size_t) (s, uncol, &ok) ;
469  if (!ok)
470  {
471  ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
472  return (NULL) ;
473  }
474 
475  CHOLMOD(allocate_work) (n, s, 0, Common) ;
476  if (Common->status < CHOLMOD_OK)
477  {
478  return (NULL) ; /* out of memory */
479  }
480  ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
481 
482  /* ensure that subsequent routines, called by cholmod_analyze, do not
483  * reallocate any workspace. This is set back to FALSE in the
484  * FREE_WORKSPACE_AND_RETURN macro, which is the only way this function
485  * returns to its caller. */
486  Common->no_workspace_reallocate = TRUE ;
487 
488  /* Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since
489  * other CHOLMOD routines will use the first 2n+uncol space. The ordering
490  * routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis)
491  * are an exception. They can use all 6n + ncol space, since the contents
492  * of Parent, First, Level, and Post are not needed across calls to those
493  * routines. */
494  Work4n = Common->Iwork ;
495  Work4n += 2*((size_t) n) + uncol ;
496  Parent = Work4n ;
497  First = Work4n + n ;
498  Level = Work4n + 2*((size_t) n) ;
499  Post = Work4n + 3*((size_t) n) ;
500 
501  /* note that this assignment means that cholmod_nested_dissection,
502  * cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol
503  * space in Common->Iwork */
504  Cmember = Post ;
505  CParent = Level ;
506 
507  /* ---------------------------------------------------------------------- */
508  /* allocate more workspace, and an empty simplicial symbolic factor */
509  /* ---------------------------------------------------------------------- */
510 
511  L = CHOLMOD(allocate_factor) (n, Common) ;
512  Lparent = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
513  Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
514  ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
515  if (Common->status < CHOLMOD_OK)
516  {
517  /* out of memory */
519  }
520  Lperm = L->Perm ;
521  Lcolcount = L->ColCount ;
522  Common->anz = EMPTY ;
523 
524  /* ---------------------------------------------------------------------- */
525  /* try all the requested ordering options and backup to AMD if needed */
526  /* ---------------------------------------------------------------------- */
527 
528  /* turn off error handling [ */
529  Common->try_catch = TRUE ;
530 
531  for (method = 0 ; method <= nmethods ; method++)
532  {
533 
534  /* ------------------------------------------------------------------ */
535  /* determine the method to try */
536  /* ------------------------------------------------------------------ */
537 
538  Common->fl = EMPTY ;
539  Common->lnz = EMPTY ;
540  skip_analysis = FALSE ;
541 
542  if (method == nmethods)
543  {
544  /* All methods failed: backup to AMD */
545  if (Common->selected == EMPTY && !default_strategy)
546  {
547  PRINT1 (("All methods requested failed: backup to AMD\n")) ;
548  ordering = CHOLMOD_AMD ;
549  }
550  else
551  {
552  break ;
553  }
554  }
555  else
556  {
557  ordering = Common->method [method].ordering ;
558  }
559  Common->current = method ;
560  PRINT1 (("method "ID": Try method: "ID"\n", method, ordering)) ;
561 
562  /* ------------------------------------------------------------------ */
563  /* find the fill-reducing permutation */
564  /* ------------------------------------------------------------------ */
565 
566  if (ordering == CHOLMOD_NATURAL)
567  {
568 
569  /* -------------------------------------------------------------- */
570  /* natural ordering */
571  /* -------------------------------------------------------------- */
572 
573  for (k = 0 ; k < n ; k++)
574  {
575  Perm [k] = k ;
576  }
577 
578  }
579  else if (ordering == CHOLMOD_GIVEN)
580  {
581 
582  /* -------------------------------------------------------------- */
583  /* use given ordering of A, if provided */
584  /* -------------------------------------------------------------- */
585 
586  if (UserPerm == NULL)
587  {
588  /* this is not an error condition */
589  PRINT1 (("skip, no user perm given\n")) ;
590  continue ;
591  }
592  for (k = 0 ; k < n ; k++)
593  {
594  /* UserPerm is checked in cholmod_ptranspose */
595  Perm [k] = UserPerm [k] ;
596  }
597 
598  }
599  else if (ordering == CHOLMOD_AMD)
600  {
601 
602  /* -------------------------------------------------------------- */
603  /* AMD ordering of A, A*A', or A(:,f)*A(:,f)' */
604  /* -------------------------------------------------------------- */
605 
606  CHOLMOD(amd) (A, fset, fsize, Perm, Common) ;
607  skip_analysis = TRUE ;
608 
609  }
610  else if (ordering == CHOLMOD_COLAMD)
611  {
612 
613  /* -------------------------------------------------------------- */
614  /* AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' */
615  /* -------------------------------------------------------------- */
616 
617  if (A->stype)
618  {
619  CHOLMOD(amd) (A, fset, fsize, Perm, Common) ;
620  skip_analysis = TRUE ;
621  }
622  else
623  {
624  /* Alternative:
625  CHOLMOD(ccolamd) (A, fset, fsize, NULL, Perm, Common) ;
626  */
627  /* do not postorder, it is done later, below */
628  /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1)*/
629  CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ;
630  }
631 
632  }
633  else if (ordering == CHOLMOD_METIS)
634  {
635 
636  /* -------------------------------------------------------------- */
637  /* use METIS_NodeND directly (via a CHOLMOD wrapper) */
638  /* -------------------------------------------------------------- */
639 
640 #ifndef NPARTITION
641  /* postorder parameter is false, because it will be later, below */
642  /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) */
643  Common->called_nd = TRUE ;
644  CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ;
645 #else
646  Common->status = CHOLMOD_NOT_INSTALLED ;
647 #endif
648 
649  }
650  else if (ordering == CHOLMOD_NESDIS)
651  {
652 
653  /* -------------------------------------------------------------- */
654  /* use CHOLMOD's nested dissection */
655  /* -------------------------------------------------------------- */
656 
657  /* this method is based on METIS' node bissection routine
658  * (METIS_NodeComputeSeparator). In contrast to METIS_NodeND,
659  * it calls CAMD or CCOLAMD on the whole graph, instead of MMD
660  * on just the leaves. */
661 #ifndef NPARTITION
662  /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) */
663  Common->called_nd = TRUE ;
664  CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember,
665  Common) ;
666 #else
667  Common->status = CHOLMOD_NOT_INSTALLED ;
668 #endif
669 
670  }
671  else
672  {
673 
674  /* -------------------------------------------------------------- */
675  /* invalid ordering method */
676  /* -------------------------------------------------------------- */
677 
678  Common->status = CHOLMOD_INVALID ;
679  PRINT1 (("No such ordering: "ID"\n", ordering)) ;
680  }
681 
682  ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
683 
684  if (Common->status < CHOLMOD_OK)
685  {
686  /* out of memory, or method failed */
687  status = MIN (status, Common->status) ;
688  Common->status = CHOLMOD_OK ;
689  continue ;
690  }
691 
692  /* ------------------------------------------------------------------ */
693  /* analyze the ordering */
694  /* ------------------------------------------------------------------ */
695 
696  if (!skip_analysis)
697  {
698  if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize,
699  Parent, Post, ColCount, First, Level, Common))
700  {
701  /* ordering method failed; clear status and try next method */
702  status = MIN (status, Common->status) ;
703  Common->status = CHOLMOD_OK ;
704  continue ;
705  }
706  }
707 
708  ASSERT (Common->fl >= 0 && Common->lnz >= 0) ;
709  Common->method [method].fl = Common->fl ;
710  Common->method [method].lnz = Common->lnz ;
711  PRINT1 (("lnz %g fl %g\n", Common->lnz, Common->fl)) ;
712 
713  /* ------------------------------------------------------------------ */
714  /* pick the best method */
715  /* ------------------------------------------------------------------ */
716 
717  /* fl.pt. compare, but lnz can never be NaN */
718  if (Common->selected == EMPTY || Common->lnz < lnz_best)
719  {
720  Common->selected = method ;
721  PRINT1 (("this is best so far, method "ID"\n", method)) ;
722  L->ordering = ordering ;
723  lnz_best = Common->lnz ;
724  for (k = 0 ; k < n ; k++)
725  {
726  Lperm [k] = Perm [k] ;
727  }
728  /* save the results of cholmod_analyze_ordering, if it was called */
729  skip_best = skip_analysis ;
730  if (!skip_analysis)
731  {
732  /* save the column count; becomes permanent part of L */
733  for (k = 0 ; k < n ; k++)
734  {
735  Lcolcount [k] = ColCount [k] ;
736  }
737  /* Parent is needed for weighted postordering and for supernodal
738  * analysis. Does not become a permanent part of L */
739  for (k = 0 ; k < n ; k++)
740  {
741  Lparent [k] = Parent [k] ;
742  }
743  }
744  }
745 
746  /* ------------------------------------------------------------------ */
747  /* determine if METIS is to be skipped */
748  /* ------------------------------------------------------------------ */
749 
750  if (default_strategy && ordering == CHOLMOD_AMD)
751  {
752  if ((Common->fl < 500 * Common->lnz) ||
753  (Common->lnz < 5 * Common->anz))
754  {
755  /* AMD found an ordering with less than 500 flops per nonzero in
756  * L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than
757  * 5. This is pretty good, and it's unlikely that METIS will do
758  * better (this heuristic is based on tests on all symmetric
759  * positive definite matrices in the UF sparse matrix
760  * collection, and it works well across a wide range of
761  * problems). METIS can take much more time and AMD. */
762  break ;
763  }
764  }
765  }
766 
767  /* turn error printing back on ] */
768  Common->try_catch = FALSE ;
769 
770  /* ---------------------------------------------------------------------- */
771  /* return if no ordering method succeeded */
772  /* ---------------------------------------------------------------------- */
773 
774  if (Common->selected == EMPTY)
775  {
776  /* All methods failed.
777  * If two or more methods failed, they may have failed for different
778  * reasons. Both would clear Common->status and skip to the next
779  * method. Common->status needs to be restored here to the worst error
780  * obtained in any of the methods. CHOLMOD_INVALID is worse
781  * than CHOLMOD_OUT_OF_MEMORY, since the former implies something may
782  * be wrong with the user's input. CHOLMOD_OUT_OF_MEMORY is simply an
783  * indication of lack of resources. */
784  ASSERT (status < CHOLMOD_OK) ;
785  ERROR (status, "all methods failed") ;
787  }
788 
789  /* ---------------------------------------------------------------------- */
790  /* do the analysis for AMD, if skipped */
791  /* ---------------------------------------------------------------------- */
792 
793  Common->fl = Common->method [Common->selected].fl ;
794  Common->lnz = Common->method [Common->selected].lnz ;
795  ASSERT (Common->lnz >= 0) ;
796 
797  if (skip_best)
798  {
799  if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize,
800  Lparent, Post, Lcolcount, First, Level, Common))
801  {
802  /* out of memory, or method failed */
804  }
805  }
806 
807  /* ---------------------------------------------------------------------- */
808  /* postorder the etree, weighted by the column counts */
809  /* ---------------------------------------------------------------------- */
810 
811  if (Common->postorder)
812  {
813  /* combine the fill-reducing ordering with the weighted postorder */
814  /* workspace: Iwork (2*nrow) */
815  if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n)
816  {
817  /* use First and Level as workspace [ */
818  Int *Wi = First, *InvPost = Level ;
819  Int newchild, oldchild, newparent, oldparent ;
820 
821  for (k = 0 ; k < n ; k++)
822  {
823  Wi [k] = Lperm [Post [k]] ;
824  }
825  for (k = 0 ; k < n ; k++)
826  {
827  Lperm [k] = Wi [k] ;
828  }
829 
830  for (k = 0 ; k < n ; k++)
831  {
832  Wi [k] = Lcolcount [Post [k]] ;
833  }
834  for (k = 0 ; k < n ; k++)
835  {
836  Lcolcount [k] = Wi [k] ;
837  }
838  for (k = 0 ; k < n ; k++)
839  {
840  InvPost [Post [k]] = k ;
841  }
842 
843  /* updated Lparent needed only for supernodal case */
844  for (newchild = 0 ; newchild < n ; newchild++)
845  {
846  oldchild = Post [newchild] ;
847  oldparent = Lparent [oldchild] ;
848  newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ;
849  Wi [newchild] = newparent ;
850  }
851  for (k = 0 ; k < n ; k++)
852  {
853  Lparent [k] = Wi [k] ;
854  }
855  /* done using Iwork as workspace ] */
856 
857  /* L is now postordered, no longer in natural ordering */
858  if (L->ordering == CHOLMOD_NATURAL)
859  {
861  }
862  }
863  }
864 
865  /* ---------------------------------------------------------------------- */
866  /* supernodal analysis, if requested or if selected automatically */
867  /* ---------------------------------------------------------------------- */
868 
869 #ifndef NSUPERNODAL
870  if (Common->supernodal > CHOLMOD_AUTO
871  || (Common->supernodal == CHOLMOD_AUTO &&
872  Common->lnz > 0 &&
873  (Common->fl / Common->lnz) >= Common->supernodal_switch))
874  {
875  cholmod_sparse *S, *F, *A2, *A1 ;
876 
877  amesos_permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE,
878  &A1, &A2, &S, &F, Common) ;
879 
880  /* workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) */
881  CHOLMOD(super_symbolic) (S, F, Lparent, L, Common) ;
882  PRINT1 (("status %d\n", Common->status)) ;
883 
884  CHOLMOD(free_sparse) (&A1, Common) ;
885  CHOLMOD(free_sparse) (&A2, Common) ;
886  }
887 #endif
888 
889  /* ---------------------------------------------------------------------- */
890  /* free temporary matrices and workspace, and return result L */
891  /* ---------------------------------------------------------------------- */
892 
894 }
895 #endif
#define CHOLMOD_TOO_LARGE
int CHOLMOD() colamd(cholmod_sparse *A, Int *fset, size_t fsize, int postorder, Int *Perm, cholmod_common *Common)
#define CHOLMOD_NOT_INSTALLED
#define EMPTY
#define CHOLMOD_AUTO
static int amesos_permute_matrices(cholmod_sparse *A, Int ordering, Int *Perm, Int *fset, size_t fsize, Int do_rowcolcounts, cholmod_sparse **A1_handle, cholmod_sparse **A2_handle, cholmod_sparse **S_handle, cholmod_sparse **F_handle, cholmod_common *Common)
#define Int
size_t CHOLMOD() add_size_t(size_t a, size_t b, int *ok)
int CHOLMOD() rowcolcounts(cholmod_sparse *A, Int *fset, size_t fsize, Int *Parent, Int *Post, Int *RowCount, Int *ColCount, Int *First, Int *Level, cholmod_common *Common)
#define FALSE
#define PRINT1(params)
#define RETURN_IF_NULL_COMMON(result)
struct cholmod_common_struct::cholmod_method_struct method[CHOLMOD_MAXMETHODS+1]
size_t CHOLMOD() mult_size_t(size_t a, size_t k, int *ok)
int CHOLMOD() dump_work(int flag, int head, UF_long wsize, cholmod_common *Common)
#define CHOLMOD_PATTERN
#define CHOLMOD(name)
#define MAX(a, b)
#define CHOLMOD_GIVEN
#define CHOLMOD_AMD
cholmod_sparse *CHOLMOD() ptranspose(cholmod_sparse *A, int values, Int *Perm, Int *fset, size_t fsize, cholmod_common *Common)
int CHOLMOD() free_sparse(cholmod_sparse **AHandle, cholmod_common *Common)
#define NULL
cholmod_factor *CHOLMOD() analyze_p(cholmod_sparse *A, Int *UserPerm, Int *fset, size_t fsize, cholmod_common *Common)
#define ASSERT(expression)
int CHOLMOD() metis(cholmod_sparse *A, Int *fset, size_t fsize, int postorder, Int *Perm, cholmod_common *Common)
int CHOLMOD() etree(cholmod_sparse *A, Int *Parent, cholmod_common *Common)
#define ID
#define CHOLMOD_METIS
#define CHOLMOD_POSTORDERED
#define CHOLMOD_INVALID
int CHOLMOD() analyze_ordering(cholmod_sparse *A, int ordering, Int *Perm, Int *fset, size_t fsize, Int *Parent, Int *Post, Int *ColCount, Int *First, Int *Level, cholmod_common *Common)
#define CHOLMOD_OK
#define FREE_WORKSPACE_AND_RETURN
int CHOLMOD() allocate_work(size_t nrow, size_t iworksize, size_t xworksize, cholmod_common *Common)
#define CHOLMOD_MAXMETHODS
#define RETURN_IF_NULL(A, result)
#define CHOLMOD_COLAMD
#define MIN(a, b)
#define CHOLMOD_SIMPLICIAL
#define CHOLMOD_NESDIS
int n
#define ERROR(status, msg)
#define TRUE
int CHOLMOD() amd(cholmod_sparse *A, Int *fset, size_t fsize, Int *Perm, cholmod_common *Common)
#define RETURN_IF_XTYPE_INVALID(A, xtype1, xtype2, result)
#define CHOLMOD_ZOMPLEX
#define CHOLMOD_NATURAL
cholmod_factor *CHOLMOD() analyze(cholmod_sparse *A, cholmod_common *Common)
cholmod_factor *CHOLMOD() allocate_factor(size_t n, cholmod_common *Common)