Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_paraklete_analyze.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === paraklete_analyze ==================================================== */
3 /* ========================================================================== */
4 
6 
7 /* LUsymbolic = paraklete_analyze (A, Common) finds a fill-reducing permutation
8  * of A and its separator tree, and returns a paraklete_symbolic object
9  * containing the symbolic analysis.
10  *
11  * TODO: check return values of MPI
12  *
13  * PARAKLETE version 0.3: parallel sparse LU factorization. Nov 13, 2007
14  * Copyright (C) 2007, Univ. of Florida. Author: Timothy A. Davis
15  * See License.txt for the Version 2.1 of the GNU Lesser General Public License
16  * http://www.cise.ufl.edu/research/sparse
17  */
18 
19 /* ========================================================================== */
20 /* === paraklete_bcast_symbolic ============================================= */
21 /* ========================================================================== */
22 
23 /* Process 0 has computed the symbolic object; broadcast it to all processes.
24  * Returns TRUE and a non-NULL LUsymbolic object if successful. Otherwise,
25  * returns FALSE and a NULL LUsymbolic object. This routine is not used for
26  * the sequential case.
27  *
28  * If the symbolic analysis fails, all processes receive an object with
29  * n=-1, which denotes a failure. All processes then return NULL.
30  */
31 
32 #ifndef NMPI
33 
35 (
36  paraklete_symbolic **LUsymbolicHandle,
37  paraklete_common *Common
38 )
39 
40 {
41  paraklete_symbolic *LUsymbolic = NULL ;
42  Int n, ncomponents, header [2] ;
43  int ok, all_ok ;
44  cholmod_common *cm ;
45 
46  cm = &(Common->cm) ;
47  n = EMPTY ;
48  ncomponents = EMPTY ;
49 
50  if (Common->myid == 0)
51  {
52  LUsymbolic = *LUsymbolicHandle ;
53  if (LUsymbolic != NULL)
54  {
55  n = LUsymbolic->n ;
56  ncomponents = LUsymbolic->ncomponents ;
57  }
58  }
59  else
60  {
61  /* other processes do not yet have the symbolic object */
62  *LUsymbolicHandle = NULL ;
63  }
64 
65  /* broadcast the size of the object, or -1 if a failure occured */
66  header [0] = n ;
67  header [1] = ncomponents ;
68  MPI_Bcast (&header, 2, MPI_Int, TAG0, MPI_COMM_WORLD) ;
69  n = header [0] ;
70  ncomponents = header [1] ;
71  if (n == EMPTY)
72  {
73  /* the analysis in the root process failed */
74  PR0 ((Common->file, "proc "ID" root analyze fails\n", Common->myid)) ;
75  return (FALSE) ;
76  }
77 
78  PR1 ((Common->file, "proc "ID" in bcast symbolic: status "ID" header "ID" "ID"\n",
79  Common->myid, cm->status, header [0], header [1])) ;
80 
81  if (Common->myid != 0)
82  {
83  LUsymbolic = amesos_paraklete_alloc_symbolic (n, ncomponents, FALSE, Common) ;
84  *LUsymbolicHandle = LUsymbolic ;
85  }
86 
87  ok = (cm->status == CHOLMOD_OK) && (LUsymbolic != NULL) ;
88  all_ok = ok ;
89 
90  /* all processes find out if any one process fails to allocate memory */
91  MPI_Allreduce (&ok, &all_ok, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD) ;
92  if (!all_ok)
93  {
94  /* out of memory; inform all processes */
95  PR0 ((Common->file, "proc "ID" all fail in analyze\n", Common->myid)) ;
96  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
97  *LUsymbolicHandle = NULL ;
98  return (FALSE) ;
99  }
100 
101  /* broadcast the contents of the symbolic object */
102  MPI_Bcast (LUsymbolic->Mem_n, 3*n, MPI_Int, TAG0, MPI_COMM_WORLD) ;
103  MPI_Bcast (LUsymbolic->Mem_c, 7*ncomponents+2, MPI_Int, TAG0,
104  MPI_COMM_WORLD) ;
105 
106 #if 0
107  {
108  /* each of size ncomponents: */
109  Int *Child = LUsymbolic->Child ;
110  Int *Clnz = LUsymbolic->Clnz ;
111  Int *Cn = LUsymbolic->Cn ;
112  Int *Cnz = LUsymbolic->Cnz ;
113  Int *Sched = LUsymbolic->Sched ;
114 
115  /* each of size ncomponents+1: */
116  Int *Cstart = LUsymbolic->Cstart ;
117  Int *Childp = LUsymbolic->Childp ;
118  Int cc ;
119 
120  for (cc = 0 ; cc < ncomponents ; cc++)
121  {
122  printf ("component "ID"\n", cc) ;
123  printf ("Child "ID"\n", Child [cc]) ;
124  printf ("Clnz "ID"\n", Clnz [cc]) ;
125  printf ("Cn "ID"\n", Cn [cc]) ;
126  printf ("Cnz "ID"\n", Cnz [cc]) ;
127  printf ("Sched "ID"\n", Sched [cc]) ;
128  printf ("Cstart "ID"\n", Cstart [cc]) ;
129  printf ("Childp "ID"\n", Childp [cc]) ;
130  }
131  printf ("Cstart "ID"\n", Cstart [ncomponents]) ;
132  printf ("Childp "ID"\n", Childp [ncomponents]) ;
133 
134  }
135 #endif
136 
137  return (TRUE) ;
138 }
139 #endif
140 
141 
142 /* ========================================================================== */
143 /* === paraklete_analyze ==================================================== */
144 /* ========================================================================== */
145 
147 (
148  /* matrix to analyze */
149  cholmod_sparse *A,
150  paraklete_common *Common
151 )
152 {
153  double cnt ;
154  double *Cwork ;
155  cholmod_common *cm ;
156  paraklete_symbolic *LUsymbolic ;
157  cholmod_sparse *C, *AT, *Elo, *Eup ;
158  Int *Cperm, *RpermInv, *Cparent, *Cmember, *ColCount, *Cstart, *Childp,
159  *Clnz, *Cn, *Cnz, *Parent, *Post, *First, *Level, *Child, *Ap, *Ai,
160  *Sched, *W, *Rperm,
161  *Lo_id, *Hi_id ;
162  double one [2] = {1,1} ;
163  Int p, k, n, ncomponents, ci, cj, i, j, clast, c, parent, nparent, nroots,
164  nproc, cp, nc0, nc1 ;
165  int ok = TRUE ;
166  size_t n5, nc7 ;
167 
168 #if 0
169  double work ;
170  Int proc = 0, parent2, ncomp2, c2, cc, cmerge, nleaves,
171  Int *NewNode, *Cparent2, *Merged, *Leaves, *Nchildren ;
172 #endif
173 
174  /* ---------------------------------------------------------------------- */
175  /* all processes except process 0 get the symbolic object from process 0 */
176  /* ---------------------------------------------------------------------- */
177 
178  LUsymbolic = NULL ;
179  if (Common->myid != 0)
180  {
181  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
182  return (LUsymbolic) ;
183  }
184 
185  /* ---------------------------------------------------------------------- */
186  /* process 0 does the analysis */
187  /* ---------------------------------------------------------------------- */
188 
189  nproc = Common->nproc ;
190 
191  /* ---------------------------------------------------------------------- */
192  /* get inputs */
193  /* ---------------------------------------------------------------------- */
194 
195 #if 0
197  RETURN_IF_NULL (A, NULL) ;
198  if (A->nrow != A->ncol || A->stype)
199  {
200  CHOLMOD (error) (CHOLMOD_INVALID, "paraklete: invalid matrix", cm) ;
201  return (NULL) ;
202  }
203 #endif
204 
205  n = A->nrow ;
206  C = NULL ;
207  W = NULL ;
208 
209  /* ---------------------------------------------------------------------- */
210  /* allocate workspace */
211  /* ---------------------------------------------------------------------- */
212 
213  cm = &(Common->cm) ;
214  CHOLMOD (allocate_work) (n, 2*n, n, cm) ;
215  if (cm->status != CHOLMOD_OK)
216  {
217  /* out of memory; inform all processes */
218  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
219  /*
220  printf (" analyze failed 1!\n") ;
221  */
222  return (NULL) ;
223  }
224 
225  /* ---------------------------------------------------------------------- */
226  /* allocate first part of symbolic factor */
227  /* ---------------------------------------------------------------------- */
228 
229  LUsymbolic = amesos_paraklete_alloc_symbolic (n, 0, TRUE, Common) ;
230 
231  if (LUsymbolic == NULL)
232  {
233  /* out of memory; inform all processes */
234  PR0 ((Common->file, "oops, proc 0 ran out\n")) ;
235  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
236  /*
237  printf (" analyze failed 2!\n") ;
238  */
239  return (NULL) ;
240  }
241 
242  Cperm = LUsymbolic->Cperm ;
243  RpermInv = LUsymbolic->RpermInv ;
244  Cparent = LUsymbolic->Cparent ;
245 
246  Cmember = RpermInv ; /* use RpermInv as workspace for Cmember */
247 
248  /* ---------------------------------------------------------------------- */
249  /* C = pattern of triu (A+A'), in symmetric/upper form */
250  /* ---------------------------------------------------------------------- */
251 
252  /*
253  printf ("pattern of A+A', n = "ID" ("ID")\n", A->nrow, cm->status) ;
254  printf ("A "ID" by "ID", nzmax "ID"\n", A->nrow, A->ncol, A->nzmax) ;
255  */
256  AT = CHOLMOD (transpose) (A, FALSE, cm) ;
257  /*
258  printf ("AT is %p ("ID")\n", (void *) AT, cm->status) ;
259  */
260  C = CHOLMOD (add) (A, AT, one, one, FALSE, FALSE, cm) ;
261  /*
262  printf ("C is %p ("ID")\n", (void *) C, cm->status) ;
263  */
264  CHOLMOD (free_sparse) (&AT, cm) ;
265  CHOLMOD (band_inplace) (0, n, 0, C, cm) ;
266  /*
267  printf ("status is ("ID")\n", cm->status) ;
268  */
269 
270  if (cm->status != CHOLMOD_OK)
271  {
272  /* out of memory; inform all processes */
273  PR0 ((Common->file, "oops, proc 0 ran out here2\n")) ;
274  CHOLMOD (free_sparse) (&C, cm) ;
275  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
276  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
277  /*
278  printf (" analyze failed 3!\n") ;
279  */
280  return (NULL) ;
281  }
282 
283  C->stype = 1 ;
284 
285  /* ---------------------------------------------------------------------- */
286  /* fill-reducing nested dissection ordering of C */
287  /* ---------------------------------------------------------------------- */
288 
289  /* Cperm [k] = i if row/col i of A is the kth row/col of A(p,p)
290  * ncomponents = # of components in separator tree
291  * Cparent [c] is parent of c in separator tree, or EMPTY if c is a root
292  * Cmember [i] = c if row/col i of A is in component c
293  */
294 
295  /* TODO rename Common->nleaves to be something else */
296  cm->method [0].nd_oksep = 0.1 ;
297 
298  if (Common->nleaves <= 0)
299  {
300  cm->method [0].nd_small = MAX (1000, -(Common->nleaves)) ;
301  }
302  else
303  {
304  cm->method [0].nd_small = n / Common->nleaves ;
305  }
306 
307  cm->current = 0 ;
308  cm->method [0].nd_components = 0 ; /* default value */
309  /*
310  printf ("nd_components "ID"\n", cm->method [0].nd_components) ;
311  */
312 
313  ncomponents = CHOLMOD (nested_dissection) (C, NULL, 0, Cperm, Cparent,
314  Cmember, cm) ;
315 
316  nc0 = ncomponents ; /* from CHOLMOD (nested_dissection) */
317  nc1 = ncomponents ; /* after collapsing */
318 
319 #ifndef NDEBUG
320  /* check results: */
321  clast = EMPTY ;
322  for (k = 0 ; k < n ; k++)
323  {
324  c = Cmember [Cperm [k]] ;
325  if (c != clast)
326  {
327  /*
328  printf ("Cmember ["ID"] = "ID"\n", k, Cmember [Cperm [k]]) ;
329  printf ("start of component\n") ;
330  */
331  /* if (c != clast+1) { printf ("ERROR!\n") ; exit (1) ; } */
332  ASSERT (c == clast + 1) ;
333  }
334  clast = c ;
335  }
336 #endif
337 
338  if (cm->status != CHOLMOD_OK)
339  {
340  /* out of memory; inform all processes */
341  PR0 ((Common->file, "oops, proc 0 ran out here3\n")) ;
342  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
343  CHOLMOD (free_sparse) (&C, cm) ;
344  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
345  /*
346  printf (" analyze failed 4!\n") ;
347  */
348  return (NULL) ;
349  }
350 
351  /* ---------------------------------------------------------------------- */
352  /* Elo = C (p,p)', Eup = Elo' */
353  /* ---------------------------------------------------------------------- */
354 
355  Elo = CHOLMOD (ptranspose) (C, FALSE, Cperm, NULL, 0, cm) ;
356  CHOLMOD (free_sparse) (&C, cm) ;
357  Eup = CHOLMOD (transpose) (Elo, FALSE, cm) ;
358 
359  /* ---------------------------------------------------------------------- */
360  /* allocate more workspace */
361  /* ---------------------------------------------------------------------- */
362 
363  /* n5 = 5*(n+1) */
364  n5 = CHOLMOD (mult_size_t) (n+1, 5, &ok) ;
365  if (!ok) PARAKLETE_ERROR (PK_TOO_LARGE, "problem too large") ;
366 
367  W = CHOLMOD (malloc) (n5, sizeof (Int), cm) ;
368  ColCount = W ; /* size n [ */
369  Parent = W + n ; /* size n [ */
370  Post = W + 2*n ; /* size n [ */
371  First = W + 3*n ; /* size n [ */
372  Level = W + 4*n ; /* size n [ */
373 
374  if (cm->status != CHOLMOD_OK)
375  {
376  /* out of memory; inform all processes */
377  PR0 ((Common->file, "oops, proc 0 ran out here4\n")) ;
378  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
379  CHOLMOD (free_sparse) (&Eup, cm) ;
380  CHOLMOD (free_sparse) (&Elo, cm) ;
381  CHOLMOD (free) (n5, sizeof (Int), W, cm) ;
382  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
383  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
384  return (NULL) ;
385  }
386 
387  /* ---------------------------------------------------------------------- */
388  /* get an estimate of the # entries in L and U */
389  /* ---------------------------------------------------------------------- */
390 
391  /* This assumes an LU factorization of C, with no partial pivoting */
392  CHOLMOD (etree) (Eup, Parent, cm) ;
393  CHOLMOD (postorder) (Parent, n, NULL, Post, cm) ;
394  CHOLMOD (rowcolcounts) (Elo, NULL, 0, Parent, Post, NULL, ColCount,
395  First, Level, cm) ;
396 
397  CHOLMOD (free_sparse) (&Eup, cm) ;
398  CHOLMOD (free_sparse) (&Elo, cm) ;
399 
400  /* Parent, Post, First, Level no longer needed ]]]] */
401 
402  if (cm->status != CHOLMOD_OK)
403  {
404  /* out of memory or other error; inform all processes */
405  PARAKLETE_ERROR (PK_UNKNOWN, "out of memory or other error") ;
406  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
407  CHOLMOD (free) (n5, sizeof (Int), W, cm) ;
408  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
409  return (NULL) ;
410  }
411 
412  /* ---------------------------------------------------------------------- */
413  /* compute Cwork [c] = flops to be done at component c */
414  /* ---------------------------------------------------------------------- */
415 
416  Cwork = cm->Xwork ;
417  for (c = 0 ; c < ncomponents ; c++)
418  {
419  Cwork [c] = 0 ;
420  }
421  for (k = 0 ; k < n ; k++)
422  {
423  c = Cmember [Cperm [k]] ;
424  cnt = ColCount [k] ;
425  Cwork [c] += cnt * cnt ;
426  }
427 
428 #ifndef NDEBUG
429  for (c = 0 ; c < ncomponents ; c++)
430  {
431  PR1 ((Common->file, "Node "ID" work %g parent "ID"\n",
432  c, Cwork [c], Cparent [c])) ;
433  }
434 #endif
435 
436 #if 0
437 
438  /* ---------------------------------------------------------------------- */
439  /* compress the tree until it has <= nproc leaves */
440  /* ---------------------------------------------------------------------- */
441 
442  /* Nchildren [c] = the number of children of node c */
443  /* Merged [c] = node that c is merged into, or EMPTY if c is not merged */
444  /* Leaves [0..nleaves-1] is a list of the leaves of the current tree */
445 
446  /* Note that W [0..n-1] is still in use for ColCount [0..n-1] */
447  Merged = W + n ; /* size ncomponents+1 [ */
448  Nchildren = W + n + ncomponents + 1 ; /* size ncomponents+1 [ */
449  Leaves = W + n + 2 * (ncomponents+1) ; /* size ncomponents [ */
450 
451  for (c = 0 ; c <= ncomponents ; c++)
452  {
453  Nchildren [c] = 0 ;
454  Merged [c] = EMPTY ;
455  }
456  for (c = 0 ; c < ncomponents ; c++)
457  {
458  parent = Cparent [c] ;
459  if (parent == EMPTY)
460  {
461  parent = ncomponents ;
462  }
463  ASSERT (parent > c && parent <= ncomponents) ;
464  Nchildren [parent]++ ;
465  }
466 
467  /* make a list of all leaves */
468  nleaves = 0 ;
469  for (c = 0 ; c < ncomponents ; c++)
470  {
471  PR1 ((Common->file, "Node "ID" has "ID" children\n", c, Nchildren [c])) ;
472  if (Nchildren [c] == 0)
473  {
474  PR1 ((Common->file, "Leaf: "ID"\n", c)) ;
475  Leaves [nleaves++] = c ;
476  }
477  }
478 
479  /* CHOLMOD (nested_dissection) returns a graph with
480  * 2 nodes (one parent and one child) for vanHeukelum/cage3
481  *
482  * could use a heap for the leaves
483  */
484 
485  while (nleaves > target_nleaves)
486  {
487  PR1 ((Common->file, "\n------------ nleaves: "ID"\n", nleaves)) ;
488 
489  /* find the lightest leaf (skip node ncomponents-1) */
490  work = EMPTY ;
491  c = EMPTY ;
492  cp = EMPTY ;
493  for (p = 0 ; p < nleaves ; p++)
494  {
495  PR2 ((Common->file, "Leaf "ID" work %g\n",
496  Leaves [p], Cwork [Leaves [p]])) ;
497  ASSERT (Merged [Leaves [p]] == EMPTY) ;
498  if (Leaves [p] == ncomponents-1)
499  {
500  /* node ncomponents-1 has no live node to its right (that is,
501  * a higher-numbered node), so skip it. The alternative is to
502  * merge a node cmerge to its left into node ncomponents-1.
503  * This may lead to a better balance of work, but is more
504  * complicated. The parent of the children of cmerge would
505  * have to be updated. FUTURE WORK: consider handling this
506  * case. */
507  continue ;
508  }
509  if (work == EMPTY || Cwork [Leaves [p]] < work)
510  {
511  c = Leaves [p] ;
512  work = Cwork [c] ;
513  cp = p ;
514  }
515  }
516  ASSERT (c != EMPTY) ;
517  PR2 ((Common->file,"Lightest leaf is "ID" with work %g\n", c, Cwork [c]));
518  ASSERT (c < ncomponents-1) ;
519  ASSERT (Nchildren [c] == 0) ;
520 
521  /* find the live node to the right of this node */
522  for (cmerge = c+1 ; cmerge < ncomponents ; cmerge++)
523  {
524  if (Merged [cmerge] == EMPTY)
525  {
526  break ;
527  }
528  }
529 
530  /* find the parent of c */
531  parent = Cparent [c] ;
532  if (parent == EMPTY)
533  {
534  parent = ncomponents ;
535  }
536 
537  /* merge c into cmerge node, where c is a leaf */
538  PR1 ((Common->file,"merge "ID" into "ID", parent "ID"\n", c, cmerge, parent));
539  ASSERT (cmerge < ncomponents) ;
540  Cwork [cmerge] += Cwork [c] ;
541  Cwork [c] = 0 ;
542  Merged [c] = cmerge ;
543  Leaves [cp] = Leaves [--nleaves] ;
544  Nchildren [parent]-- ;
545  ASSERT (Merged [parent] == EMPTY) ;
546 
547  if (Nchildren [parent] == 0 && parent != ncomponents)
548  {
549  /* parent is a new leaf, add it to the list of Leaves */
550  PR1 ((Common->file, "parent is new leaf: "ID"\n", parent)) ;
551  Leaves [nleaves++] = parent ;
552  }
553  }
554 
555  /* Leaves no longer needed ] */
556 
557  PR1 ((Common->file, "\n-------------------------- done merging leaves\n")) ;
558 
559  /* merge nodes that have just one child, with the one child */
560  for (c = 0 ; c < ncomponents-1 ; c++)
561  {
562  if (Merged [c] == EMPTY)
563  {
564  parent = Cparent [c] ;
565  if (parent == EMPTY) continue ;
566  if (Nchildren [parent] == 1)
567  {
568  PR1 ((Common->file, "\nparent "ID" of c "ID" has one child\n",
569  parent, c));
570  Cwork [parent] += Cwork [c] ;
571  Cwork [c] = 0 ;
572  Merged [c] = parent ;
573  for (cc = c+1 ; cc < parent ; cc++)
574  {
575  PR1 ((Common->file, "merge "ID" into "ID"\n", cc, parent)) ;
576  ASSERT (Merged [cc] != EMPTY) ;
577  Merged [cc] = parent ;
578  }
579  }
580  }
581  }
582 
583  /* Nchildren no longer needed ] */
584 
585  /* compress the paths in Merged */
586  for (c = 0 ; c < ncomponents ; c++)
587  {
588  /* find the ultimate node that node c was merged into */
589  PR1 ((Common->file, "\nFind ultimate node for "ID"\n", c)) ;
590  for (cc = c ; Merged [cc] != EMPTY ; cc = Merged [cc]) ;
591  for (c2 = c ; Merged [c2] != EMPTY ; c2 = Merged [c2])
592  {
593  PR1 ((Common->file, " merge "ID" into "ID"\n", c2, cc)) ;
594  Merged [c2] = cc ;
595  }
596  }
597 
598  /* find the new node numbering, using Leaves as workspace */
599  NewNode = Leaves ;
600  ncomp2 = 0 ;
601  for (c = 0 ; c < ncomponents ; c++)
602  {
603  if (Merged [c] == EMPTY)
604  {
605  PR1 ((Common->file, "Live node "ID" becomes node "ID"\n", c, ncomp2)) ;
606  NewNode [c] = ncomp2++ ;
607  }
608  }
609  for (c = 0 ; c < ncomponents ; c++)
610  {
611  if (Merged [c] != EMPTY)
612  {
613  NewNode [c] = NewNode [Merged [c]] ;
614  PR1 ((Common->file, "Dead node "ID" becomes part of node "ID"\n",
615  c, NewNode [c])) ;
616  }
617  }
618 
619  /* fix Cmember */
620  for (k = 0 ; k < n ; k++)
621  {
622  c = Cmember [k] ;
623  c = NewNode [c] ;
624  Cmember [k] = c ;
625  }
626 
627  /* fix Cparent, using Nchildren as workspace */
628  Cparent2 = Nchildren ;
629  for (c = 0 ; c < ncomponents ; c++)
630  {
631  if (Merged [c] == EMPTY)
632  {
633  c2 = NewNode [c] ;
634  parent = Cparent [c] ;
635  parent2 = (parent == EMPTY) ? EMPTY : (NewNode [parent]) ;
636  Cparent2 [c2] = parent2 ;
637  }
638  }
639 
640  /* Merged no longer needed ] */
641 
642  for (c = 0 ; c < ncomponents ; c++)
643  {
644  Cwork [c] = 0 ;
645  }
646 
647  ncomponents = ncomp2 ;
648  for (c = 0 ; c < ncomponents ; c++)
649  {
650  Cparent [c] = Cparent2 [c] ;
651  }
652 
653 #ifndef NDEBUG
654  printf ("Final components: "ID" leaves: "ID"\n", ncomponents, nleaves) ;
655  for (c = 0 ; c < ncomponents ; c++)
656  {
657  PR1 ((Common->file, "New node: "ID" new parent "ID"\n", c, Cparent [c])) ;
658  }
659 #endif
660 
661 #endif
662 
663  /* ---------------------------------------------------------------------- */
664  /* allocate remainder of symbolic factor */
665  /* ---------------------------------------------------------------------- */
666 
667  /* nc7 = 7*ncomponents + 2 */
668  nc7 = CHOLMOD (mult_size_t) (ncomponents, 7, &ok) ;
669  nc7 = CHOLMOD (add_size_t) (nc7, 2, &ok) ;
670  if (!ok) PARAKLETE_ERROR (PK_TOO_LARGE, "problem too large") ;
671 
672  LUsymbolic->Mem_c = CHOLMOD (malloc) (nc7, sizeof (Int), cm) ;
673 
674  /* each of size ncomponents: */
675  Child = LUsymbolic->Child = LUsymbolic->Mem_c ;
676  Clnz = LUsymbolic->Clnz = LUsymbolic->Mem_c + ncomponents ;
677  Cn = LUsymbolic->Cn = LUsymbolic->Mem_c + 2*ncomponents ;
678  Cnz = LUsymbolic->Cnz = LUsymbolic->Mem_c + 3*ncomponents ;
679  Sched = LUsymbolic->Sched = LUsymbolic->Mem_c + 4*ncomponents ;
680 
681  /* each of size ncomponents+1: */
682  Cstart = LUsymbolic->Cstart = LUsymbolic->Mem_c + 5*ncomponents ;
683  Childp = LUsymbolic->Childp = LUsymbolic->Mem_c + 6*ncomponents + 1 ;
684 
685  LUsymbolic->ncomponents = ncomponents ;
686  LUsymbolic->ncomp0 = nc0 ;
687  LUsymbolic->ncomp1 = nc1 ;
688 
689  if (cm->status != CHOLMOD_OK)
690  {
691  /* out of memory or other error; inform all processes */
692  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
693  CHOLMOD (free) (n5, sizeof (Int), W, cm) ;
694  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
695  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
696  return (NULL) ;
697  }
698 
699  /* ---------------------------------------------------------------------- */
700  /* Cstart = start and end nodes of each component */
701  /* ---------------------------------------------------------------------- */
702 
703  clast = EMPTY ;
704  for (k = 0 ; k < n ; k++)
705  {
706  c = Cmember [Cperm [k]] ;
707  if (c != clast)
708  {
709  /* if (c != clast+1) { printf ("Error!\n") ; exit (1) ; } */
710  ASSERT (c == clast + 1) ;
711  Cstart [c] = k ;
712  }
713  clast = c ;
714  }
715  Cstart [ncomponents] = n ;
716 
717  /* ---------------------------------------------------------------------- */
718  /* Clnz = estimate of # of entries in L for each component */
719  /* ---------------------------------------------------------------------- */
720 
721  for (c = 0 ; c < ncomponents ; c++)
722  {
723  size_t s = 0 ;
724  for (k = Cstart [c] ; k < Cstart [c+1] ; k++)
725  {
726  s = CHOLMOD (add_size_t) (s, ColCount [k], &ok) ;
727  }
728  if (!ok)
729  {
730  /* TODO return NULL, and broadcast error to all processes */
731  PARAKLETE_ERROR (PK_TOO_LARGE, "problem too large") ;
732  }
733  /*
734  printf ("Clnz ["ID"] = "ID", cols "ID" to "ID"\n", c, Clnz [c],
735  Cstart [c], Cstart [c+1]-1) ;
736  */
737  Clnz [c] = s ;
738  }
739 
740  /* ColCount no longer needed ] */
741 
742  /* ---------------------------------------------------------------------- */
743  /* Child, Childp: list of children of each component */
744  /* ---------------------------------------------------------------------- */
745 
746  /* count the number of children of each node, using Cn as workspace */
747  for (c = 0 ; c < ncomponents ; c++)
748  {
749  Cn [c] = 0 ;
750  }
751  nroots = 0 ;
752  for (c = 0 ; c < ncomponents ; c++)
753  {
754  parent = Cparent [c] ;
755  PR1 ((Common->file, "node "ID": parent "ID"\n", c, parent)) ;
756  if (parent == EMPTY)
757  {
758  nroots++ ;
759  }
760  else
761  {
762  ASSERT (parent > 0 && parent < ncomponents) ;
763  Cn [parent]++ ;
764  }
765  }
766 
767  if (nroots > 1)
768  {
769  /* TODO - this is an assertion */
770  PARAKLETE_ERROR (PK_UNKNOWN, "separator tree cannot be forest") ;
771  abort ( ) ;
772  }
773 
774 #ifndef NDEBUG
775  for (c = 0 ; c < ncomponents ; c++)
776  {
777  PR1 ((Common->file, "node "ID": "ID" children\n", c, Cn [c])) ;
778  }
779 #endif
780 
781  /* find the cumulative sum of the children */
782  k = 0 ;
783  for (c = 0 ; c < ncomponents ; c++)
784  {
785  Childp [c] = k ;
786  k += Cn [c] ;
787  }
788  PR1 ((Common->file, "k "ID" ncomponents "ID"\n", k, ncomponents)) ;
789  ASSERT (k == ncomponents - nroots) ;
790  Childp [ncomponents] = k ;
791 
792  /* create a list of children for each node */
793  for (c = 0 ; c < ncomponents ; c++)
794  {
795  Cn [c] = Childp [c] ;
796  }
797  for (k = 0 ; k < ncomponents ; k++)
798  {
799  Child [k] = -1 ;
800  }
801  for (c = 0 ; c < ncomponents ; c++)
802  {
803  parent = Cparent [c] ;
804  if (parent != EMPTY)
805  {
806  Child [Cn [parent]++] = c ;
807  }
808  }
809 
810 #ifndef NDEBUG
811  for (c = 0 ; c < ncomponents ; c++)
812  {
813  PR1 ((Common->file, "Node "ID" children: ", c)) ;
814  for (cp = Childp [c] ; cp < Childp [c+1] ; cp++)
815  {
816  PR1 ((Common->file, ""ID" ", Child [cp])) ;
817  }
818  PR1 ((Common->file, "\n")) ;
819  }
820 #endif
821 
822  /* ---------------------------------------------------------------------- */
823  /* find the nominal dimensions of each node (assuming no pivot delays) */
824  /* ---------------------------------------------------------------------- */
825 
826  for (c = ncomponents - 1 ; c >= 0 ; c--)
827  {
828  parent = Cparent [c] ;
829  nparent = (parent == EMPTY) ? 0 : Cn [parent] ;
830  Cn [c] = (Cstart [c+1] - Cstart [c]) + nparent ;
831  PR1 ((Common->file, "node "ID" Cn: "ID"\n", c, Cn [c])) ;
832  }
833 
834  /* ---------------------------------------------------------------------- */
835  /* count the nonzeros in A that map to node c */
836  /* ---------------------------------------------------------------------- */
837 
838  for (c = 0 ; c < ncomponents ; c++)
839  {
840  Cnz [c] = 0 ;
841  }
842  Ap = A->p ;
843  Ai = A->i ;
844  for (j = 0 ; j < n ; j++)
845  {
846  cj = Cmember [j] ;
847  for (p = Ap [j] ; p < Ap [j+1] ; p++)
848  {
849  i = Ai [p] ;
850  ci = Cmember [i] ;
851  c = MIN (ci, cj) ;
852  Cnz [c]++ ;
853  PR3 ((Common->file, "A(1+"ID",1+"ID") = %g ; c(1+"ID",1+"ID") = "ID" ;\n",
854  i,j,
855  A->x ? 0 : (((double *) (A->x)) [p]),
856  i,j, c)) ;
857  }
858  }
859 
860 #ifndef NDEBUG
861  for (c = 0 ; c < ncomponents ; c++)
862  {
863  PR0 ((Common->file, "Cnz ["ID"] = "ID"\n", c, Cnz [c])) ;
864  }
865 #endif
866 
867  /* ---------------------------------------------------------------------- */
868  /* compute RpermInv = inverse of Cperm */
869  /* ---------------------------------------------------------------------- */
870 
871  Rperm = LUsymbolic->Rperm ;
872  ASSERT (Rperm != NULL) ;
873 
874  /* Rperm starts out equal to Cperm */
875  for (k = 0 ; k < n ; k++)
876  {
877  Rperm [k] = Cperm [k] ;
878  }
879  for (k = 0 ; k < n ; k++)
880  {
881  RpermInv [Rperm [k]] = k ;
882  }
883 
884  /* ---------------------------------------------------------------------- */
885  /* schedule the processes to the nodes */
886  /* ---------------------------------------------------------------------- */
887 
888 #ifndef NMPI
889  /* processes Lo_id [c] to Hi_id [c] are assigned to node c or descendants */
890  Lo_id = W ;
891  Hi_id = W + ncomponents ;
892 
893  for (c = 0 ; c < ncomponents ; c++)
894  {
895  Sched [c] = EMPTY ;
896  Lo_id [c] = -1 ;
897  Hi_id [c] = -1 ;
898  }
899 
900  Lo_id [ncomponents-1] = 0 ;
901  Hi_id [ncomponents-1] = nproc-1 ;
902 
903  for (c = ncomponents - 1 ; c >= 0 ; c--)
904  {
905  Int nchild, child, child_left, child_right, c_nproc ;
906 
907  /* first available process does this node */
908  Sched [c] = Lo_id [c] ;
909 
910  /* split the processes amongst the children */
911  nchild = Childp [c+1] - Childp [c] ;
912  cp = Childp [c] ;
913 
914  if (nchild == 0)
915  {
916  /* nothing else to do */
917  }
918  else if (nchild == 1)
919  {
920  /* all processes go to the one child */
921  child = Child [cp] ;
922  Lo_id [child] = Lo_id [c] ;
923  Hi_id [child] = Hi_id [c] ;
924  }
925  else if (nchild == 2)
926  {
927  /* two children; split the processors between them */
928  child_left = Child [cp] ;
929  child_right = Child [cp+1] ;
930 
931  c_nproc = Hi_id [c] - Lo_id [c] + 1 ;
932  if (c_nproc > 1)
933  {
934  Lo_id [child_left ] = Lo_id [c] ;
935  Hi_id [child_left ] = Lo_id [c] + c_nproc / 2 - 1 ;
936  Lo_id [child_right] = Lo_id [c] + c_nproc / 2 ;
937  Hi_id [child_right] = Hi_id [c] ;
938  }
939  else
940  {
941  Lo_id [child_left ] = Lo_id [c] ;
942  Hi_id [child_left ] = Lo_id [c] ;
943  Lo_id [child_right] = Lo_id [c] ;
944  Hi_id [child_right] = Lo_id [c] ;
945  }
946  }
947  else
948  {
949  /* TODO this is an assertion - it cannot occur */
950  PARAKLETE_ERROR (PK_UNKNOWN, "invalid separator tree") ;
951  abort ( ) ;
952  }
953  }
954 
955 #if 0
956  proc = 0 ;
957  for (c = 0 ; c < ncomponents ; c++)
958  {
959  Int nchild = Childp [c+1] - Childp [c] ;
960  if (nchild == 0)
961  {
962  PR1 ((Common->file,"\nSchedule child "ID" to process "ID"\n", c, proc));
963  for (cc = c ; cc != EMPTY && Sched [cc] == EMPTY ; cc = Cparent[cc])
964  {
965  PR1 ((Common->file, " node "ID" to process "ID"\n", cc, proc)) ;
966  Sched [cc] = proc ;
967  }
968  /* advance to the next process */
969  proc = (proc + 1) % nproc ;
970  }
971  }
972 #endif
973 
974 #else
975  /* all components are done by process zero */
976  proc = 0 ;
977  for (c = 0 ; c < ncomponents ; c++)
978  {
979  Sched [c] = proc ;
980  }
981 #endif
982 
983 #ifndef NDEBUG
984  PR0 ((Common->file, "\nncomponents:: "ID"\n", ncomponents)) ;
985  for (c = 0 ; c < ncomponents ; c++)
986  {
987  PR0 ((Common->file, " node "ID" Sched "ID" : Cparent "ID" proc "ID"\n",
988  c, Sched [c], Cparent [c],
989  (Cparent [c] == EMPTY) ? EMPTY : Sched [Cparent [c]])) ;
990  }
991 #endif
992 
993 #if 0
994  for (c = 0 ; c < ncomponents ; c++)
995  {
996  printf (" node "ID" on "ID" : Cparent "ID" on "ID"\n",
997  c, Sched [c], Cparent [c],
998  (Cparent [c] == EMPTY) ? EMPTY : Sched [Cparent [c]]) ;
999  }
1000 #endif
1001 
1002  /* ---------------------------------------------------------------------- */
1003  /* return the symbolic factorization, and broadcast it to all processes */
1004  /* ---------------------------------------------------------------------- */
1005 
1006  CHOLMOD (free) (n5, sizeof (Int), W, cm) ;
1007  PR1 ((Common->file, "analysis done\n")) ;
1008  MPI (paraklete_bcast_symbolic (&LUsymbolic, Common)) ;
1009  return (LUsymbolic) ;
1010 }
1011 
1012 
1013 /* ========================================================================== */
1014 /* === paraklete_alloc_symbolic ============================================= */
1015 /* ========================================================================== */
1016 
1017 /* allocate a symbolic object */
1018 
1021  Int n,
1022  Int ncomponents,
1023  Int do_Rperm,
1024  paraklete_common *Common
1025 )
1026 {
1027  paraklete_symbolic *LUsymbolic ;
1028  cholmod_common *cm ;
1029  size_t n3, nc7 ;
1030  int ok = TRUE ;
1031 
1032  cm = &(Common->cm) ;
1033 
1034  /* n3 = 3*n */
1035  n3 = CHOLMOD (mult_size_t) (n, 3, &ok) ;
1036  if (!ok) PARAKLETE_ERROR (PK_TOO_LARGE, "problem too large") ;
1037 
1038  /* nc7 = 7*ncomponents + 2 */
1039  nc7 = CHOLMOD (mult_size_t) (ncomponents, 7, &ok) ;
1040  nc7 = CHOLMOD (add_size_t) (nc7, 2, &ok) ;
1041  if (!ok) PARAKLETE_ERROR (PK_TOO_LARGE, "problem too large") ;
1042 
1043  LUsymbolic = CHOLMOD (malloc) (1, sizeof (paraklete_symbolic), cm) ;
1044 
1045  if (cm->status != CHOLMOD_OK)
1046  {
1047  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
1048  return (NULL) ;
1049  }
1050 
1051  if (n > 0)
1052  {
1053  LUsymbolic->Mem_n = CHOLMOD (malloc) (n3, sizeof (Int), cm) ;
1054  LUsymbolic->Cperm = LUsymbolic->Mem_n ;
1055  LUsymbolic->RpermInv = LUsymbolic->Mem_n + n ;
1056  LUsymbolic->Cparent = LUsymbolic->Mem_n + 2*n ;
1057 
1058  if (do_Rperm)
1059  {
1060  LUsymbolic->Rperm = CHOLMOD (malloc) (n, sizeof (Int), cm) ;
1061  }
1062  else
1063  {
1064  /* fill-reducing ordering is symmetric, Rperm is implicitly
1065  * equal to Cperm */
1066  LUsymbolic->Rperm = NULL ;
1067  }
1068  }
1069  else
1070  {
1071  LUsymbolic->Mem_n = NULL ;
1072  LUsymbolic->Cperm = NULL ;
1073  LUsymbolic->RpermInv = NULL ;
1074  LUsymbolic->Cparent = NULL ;
1075  LUsymbolic->Rperm = NULL ;
1076  }
1077 
1078  if (ncomponents > 0)
1079  {
1080 
1081  LUsymbolic->Mem_c = CHOLMOD (malloc) (nc7, sizeof(Int), cm) ;
1082 
1083  /* each of size ncomponents: */
1084  LUsymbolic->Child = LUsymbolic->Mem_c ;
1085  LUsymbolic->Clnz = LUsymbolic->Mem_c + ncomponents ;
1086  LUsymbolic->Cn = LUsymbolic->Mem_c + 2*ncomponents ;
1087  LUsymbolic->Cnz = LUsymbolic->Mem_c + 3*ncomponents ;
1088  LUsymbolic->Sched = LUsymbolic->Mem_c + 4*ncomponents ;
1089 
1090  /* each of size ncomponents+1: */
1091  LUsymbolic->Cstart = LUsymbolic->Mem_c + 5*ncomponents ;
1092  LUsymbolic->Childp = LUsymbolic->Mem_c + 6*ncomponents + 1 ;
1093 
1094  }
1095  else
1096  {
1097  LUsymbolic->Mem_c = NULL ;
1098  LUsymbolic->Child = NULL ;
1099  LUsymbolic->Clnz = NULL ;
1100  LUsymbolic->Cn = NULL ;
1101  LUsymbolic->Cnz = NULL ;
1102  LUsymbolic->Sched = NULL ;
1103  LUsymbolic->Cstart = NULL ;
1104  LUsymbolic->Childp = NULL ;
1105  }
1106 
1107  LUsymbolic->n = n ;
1108  LUsymbolic->ncomponents = ncomponents ;
1109 
1110  if (cm->status != CHOLMOD_OK)
1111  {
1112  /* out of memory */
1113  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
1114  amesos_paraklete_free_symbolic (&LUsymbolic, Common) ;
1115  }
1116 
1117  return (LUsymbolic) ;
1118 }
1119 
1120 
1121 /* ========================================================================== */
1122 /* === paraklete_free_symbolic ============================================== */
1123 /* ========================================================================== */
1124 
1125 /* Free the symbolic object. All processes own a copy after it is broadcast. */
1126 
1129  paraklete_symbolic **LUsymbolicHandle,
1130  paraklete_common *Common
1131 )
1132 {
1133  paraklete_symbolic *LUsymbolic ;
1134  cholmod_common *cm ;
1135  Int n, ncomponents ;
1136 
1137  if (LUsymbolicHandle == NULL)
1138  {
1139  /* nothing to do */
1140  return ;
1141  }
1142  LUsymbolic = *LUsymbolicHandle ;
1143  if (LUsymbolic == NULL)
1144  {
1145  /* nothing to do */
1146  return ;
1147  }
1148 
1149  cm = &(Common->cm) ;
1150  ncomponents = LUsymbolic->ncomponents ;
1151  n = LUsymbolic->n ;
1152 
1153  /* size-3n space, in Mem_n */
1154  CHOLMOD (free) (3*n, sizeof (Int), LUsymbolic->Mem_n, cm) ;
1155  LUsymbolic->Cperm = NULL ;
1156  LUsymbolic->RpermInv = NULL ;
1157  LUsymbolic->Cparent = NULL ;
1158 
1159  /* size-n space, only used for reanalyze/refactorize, or if the fill-
1160  * reducing ordering is unsymmetric. Otherwise, Rperm is implicitly
1161  * equal to Cperm. */
1162  CHOLMOD (free) (n, sizeof (Int), LUsymbolic->Rperm, cm) ;
1163  LUsymbolic->Rperm = NULL ;
1164 
1165  /* size-(7*components+2) space, in Mem_c */
1166  CHOLMOD (free) (7*ncomponents + 2, sizeof (Int), LUsymbolic->Mem_c, cm) ;
1167  LUsymbolic->Cstart = NULL ;
1168  LUsymbolic->Child = NULL ;
1169  LUsymbolic->Childp = NULL ;
1170  LUsymbolic->Clnz = NULL ;
1171  LUsymbolic->Cn = NULL ;
1172  LUsymbolic->Cnz = NULL ;
1173  LUsymbolic->Sched = NULL ;
1174 
1175  *LUsymbolicHandle = CHOLMOD (free) (
1176  1, sizeof (paraklete_symbolic), (*LUsymbolicHandle), cm) ;
1177 }
#define TAG0
cholmod_sparse *CHOLMOD() add(cholmod_sparse *A, cholmod_sparse *B, double alpha[2], double beta[2], int values, int sorted, cholmod_common *Common)
int CHOLMOD() band_inplace(UF_long k1, UF_long k2, int mode, cholmod_sparse *A, cholmod_common *Common)
#define MPI_Int
#define EMPTY
#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
cholmod_sparse *CHOLMOD() transpose(cholmod_sparse *A, int values, cholmod_common *Common)
#define PR0(params)
#define RETURN_IF_NULL_COMMON(result)
struct cholmod_common_struct::cholmod_method_struct method[CHOLMOD_MAXMETHODS+1]
paraklete_symbolic * amesos_paraklete_alloc_symbolic(Int n, Int ncomponents, Int do_Rperm, paraklete_common *Common)
size_t CHOLMOD() mult_size_t(size_t a, size_t k, int *ok)
#define PARAKLETE_ERROR(status, message)
#define CHOLMOD(name)
#define MAX(a, b)
#define PK_TOO_LARGE
cholmod_sparse *CHOLMOD() ptranspose(cholmod_sparse *A, int values, Int *Perm, Int *fset, size_t fsize, cholmod_common *Common)
#define PR2(params)
int CHOLMOD() free_sparse(cholmod_sparse **AHandle, cholmod_common *Common)
#define NULL
#define ASSERT(expression)
int CHOLMOD() etree(cholmod_sparse *A, Int *Parent, cholmod_common *Common)
#define ID
int CHOLMOD() error(int status, char *file, int line, char *message, cholmod_common *Common)
#define CHOLMOD_INVALID
#define PR1(params)
#define PR3(params)
#define CHOLMOD_OK
#define PK_OUT_OF_MEMORY
#define MPI(statement)
paraklete_symbolic * amesos_paraklete_analyze(cholmod_sparse *A, paraklete_common *Common)
static Int paraklete_bcast_symbolic(paraklete_symbolic **LUsymbolicHandle, paraklete_common *Common)
int CHOLMOD() allocate_work(size_t nrow, size_t iworksize, size_t xworksize, cholmod_common *Common)
#define RETURN_IF_NULL(A, result)
#define MIN(a, b)
struct paraklete_symbolic_struct paraklete_symbolic
void amesos_paraklete_free_symbolic(paraklete_symbolic **LUsymbolicHandle, paraklete_common *Common)
int n
#define TRUE
#define PK_UNKNOWN