Amesos Package Browser (Single Doxygen Collection)  Development
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_paraklete_node.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === paraklete_factorize_node ============================================= */
3 /* ========================================================================== */
4 
6 
7 /* Factorize node c of the separator tree:
8  * (1) obtain the Schur complements from the children of node c
9  * (2) sum up the Schur complements, and the input matrix at this node c
10  * (3) factorize node c
11  * (4) send the Schur complement of node c to its parent
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_free_children ============================================== */
21 /* ========================================================================== */
22 
23 /* Free the Schur complement of each child of node c. Free the input matrix
24  * A for this node c. */
25 
26 static void paraklete_free_children
27 (
28  Int c,
30  paraklete_symbolic *LUsymbolic,
31  paraklete_common *Common
32 )
33 {
34  Int *Child, *Childp ;
35  Int nchild, child, sn, cp ;
36  cholmod_common *cm ;
37 
38  cm = &(Common->cm) ;
39 
40  /* free A for this node */
41  CHOLMOD (free_sparse) (&(LU->LUnode [c]->A), cm) ;
42 
43  Child = LUsymbolic->Child ;
44  Childp = LUsymbolic->Childp ;
45  nchild = LU->LUnode [c]->nchild ;
46  ASSERT (nchild == Childp [c+1] - Childp [c]) ;
47 
48  for (cp = 0 ; cp < nchild ; cp++)
49  {
50  /* free the Schur complement of the child */
51  child = Child [Childp [c] + cp] ;
52  sn = LU->LUnode [child]->PK_SN ;
53 
54  LU->LUnode [child]->sx = CHOLMOD (free) (
55  LU->LUnode [child]->PK_SSIZE, sizeof (double),
56  LU->LUnode [child]->sx, cm) ;
57  LU->LUnode [child]->sp = CHOLMOD (free) (
58  sn, sizeof (Int), LU->LUnode [child]->sp, cm) ;
59  LU->LUnode [child]->slen = CHOLMOD (free) (
60  sn, sizeof (Int), LU->LUnode [child]->slen, cm) ;
61  }
62 }
63 
64 
65 /* ========================================================================== */
66 /* === paraklete_send_to_parent ============================================= */
67 /* ========================================================================== */
68 
69 /* Send the Schur complement or an error message to the parent */
70 
71 static void paraklete_send_to_parent
72 (
73  Int c,
74  Int status,
75  Int parent_id,
77  paraklete_symbolic *LUsymbolic,
78  paraklete_common *Common
79 )
80 {
81  int ok ;
82  cholmod_common *cm ;
83  paraklete_node *LUnode ;
84  MPI (MPI_Status ms) ;
85 
86  cm = &(Common->cm) ;
87  LUnode = LU->LUnode [c] ;
88 
89  /* workspace W2 and C no longer needed */
90  LUnode->W2 = CHOLMOD (free) (2*(LUnode->nlost_in), sizeof (Int),
91  LUnode->W2, cm) ;
92  CHOLMOD (free_sparse) (&(LUnode->C), cm) ;
93 
94  LUnode->PK_STATUS = status ;
95 
96  ok = TRUE ;
97  if (parent_id != EMPTY && parent_id != Common->myid)
98  {
99  /* send header to process that owns the parent node (parent_id) */
100  PR1 ((Common->file, "proc "ID" sends header parent proc "ID"\n",
101  Common->myid, parent_id)) ;
102  MPI (MPI_Send (LUnode->header, PK_HEADER, MPI_Int,
103  parent_id, TAG0, MPI_COMM_WORLD)) ;
104 
105  /* wait to see if parent_id is OK */
106  PR1 ((Common->file, "proc "ID" wait for parent "ID"\n",
107  Common->myid, parent_id)) ;
108  MPI (MPI_Recv (&ok, 1, MPI_INT, parent_id, TAG0, MPI_COMM_WORLD, &ms)) ;
109 
110  /* if status is not PK_OK, then parent_id will send back ok = FALSE */
111  ASSERT (IMPLIES (status != PK_OK, !ok)) ;
112 
113  if (ok)
114  {
115  /* both parent_id and myid agree to send the Schur complement */
116  /* TODO: send this as one or two messages */
117  MPI (MPI_Rsend (LUnode->sp, LUnode->PK_SN, MPI_Int,
118  parent_id, TAG0, MPI_COMM_WORLD)) ;
119  MPI (MPI_Rsend (LUnode->slen, LUnode->PK_SN, MPI_Int,
120  parent_id, TAG0, MPI_COMM_WORLD)) ;
121  MPI (MPI_Rsend (LUnode->sx, LUnode->PK_SSIZE, MPI_DOUBLE,
122  parent_id, TAG0, MPI_COMM_WORLD)) ;
123  MPI (MPI_Rsend (LUnode->Pglobal, LUnode->PK_NPIV, MPI_Int,
124  parent_id, TAG0, MPI_COMM_WORLD)) ;
125  MPI (MPI_Rsend (LUnode->Qglobal, LUnode->PK_NPIV, MPI_Int,
126  parent_id, TAG0, MPI_COMM_WORLD)) ;
127  }
128  }
129 
130  if (!ok || parent_id == EMPTY || parent_id != Common->myid)
131  {
132  /* free the Schur complement of node c if a failure occured, if node
133  * c has no parent, or if the Schur complement was sent to a
134  * different process (parent_id). */
135  LUnode->sx = CHOLMOD (free) (LUnode->PK_SSIZE,
136  sizeof (double), LUnode->sx, cm) ;
137  LUnode->sp = CHOLMOD (free) (LUnode->PK_SN,
138  sizeof (Int), LUnode->sp, cm) ;
139  LUnode->slen = CHOLMOD (free) (LUnode->PK_SN,
140  sizeof (Int), LUnode->slen, cm) ;
141  }
142 
143  if (!ok)
144  {
145  /* free the Schur complements of the children if a failure occured */
146  paraklete_free_children (c, LU, LUsymbolic, Common) ;
147  }
148 }
149 
150 
151 /* ========================================================================== */
152 /* === paraklete_factorize_node ============================================= */
153 /* ========================================================================== */
154 
156 (
157  Int c,
158  paraklete_numeric *LU,
159  paraklete_symbolic *LUsymbolic,
160  paraklete_common *Common
161 )
162 {
163  paraklete_node *LUnode ;
164  cholmod_common *cm ;
165  cholmod_sparse *C ;
166  double *Cx, *W, *Sx, *Ax, *S ;
167  Int *Child, *Childp, *Lost, *Lostp, *Plost_in, *Qlost_in, *Cp, *Ci, *Flag,
168  *Sp, *Si, *Slen, *Ap, *Ai, *Cn, *Plocal, *Qlocal, *Pglobal, *Qglobal,
169  *Sched, *Pinv ;
170  Int cp, cnz, clnz, nchild, k1, k2, child, cn, npiv, k, j, p, i, nfound,
171  mark, cj, ci, nlost_in, len, sn, myid, ssize, parent, nmessages,
172  status, parent_id ;
173  int ok ;
174  size_t s ;
175 
176  MPI (MPI_Status ms) ;
177  MPI (MPI_Request req [5]) ;
178 
179  /* ---------------------------------------------------------------------- */
180  /* get local workspace */
181  /* ---------------------------------------------------------------------- */
182 
183  cm = &(Common->cm) ;
184  PR0 ((Common->file, "\n\n######################## FACTORIZE NODE "ID"\n", c));
185 
186  /* ---------------------------------------------------------------------- */
187  /* get the symbolic analysis of this node */
188  /* ---------------------------------------------------------------------- */
189 
190  cnz = LUsymbolic->Cnz [c] ; /* # entries in A for this node c */
191  Childp = LUsymbolic->Childp ; /* Child [Childp [c]..Childp[c+1]-1] */
192  Child = LUsymbolic->Child ; /* is list of children of node c */
193  clnz = LUsymbolic->Clnz [c] ; /* est. # entries in L for node c */
194  nchild = Childp [c+1] - Childp [c] ; /* # of children of node c */
195  k1 = LUsymbolic->Cstart [c] ; /* global index of first pivot cand. */
196  k2 = LUsymbolic->Cstart [c+1] ; /* global index of last piv plus one */
197  Cn = LUsymbolic->Cn ; /* dimension of each node */
198  Sched = LUsymbolic->Sched ;
199  parent = LUsymbolic->Cparent [c] ;
200  myid = Common->myid ;
201  parent_id = (parent == EMPTY) ? EMPTY : Sched [parent] ;
202 
203  PR0 ((Common->file, "proc "ID" at node "ID", clnz: "ID"\n", myid, c, clnz)) ;
204 
205  /* ---------------------------------------------------------------------- */
206  /* get the arrowhead of the input matrix to factorize at this node */
207  /* ---------------------------------------------------------------------- */
208 
209  LUnode = LU->LUnode [c] ;
210  ASSERT (nchild == LUnode->nchild) ;
211  Ap = LUnode->A->p ; /* A matrix of dimension Cn [c] */
212  Ai = LUnode->A->i ;
213  Ax = LUnode->A->x ;
214  DEBUG (CHOLMOD (print_sparse) (LUnode->A, "Arrowhead", cm)) ;
215 
216 #ifndef NDEBUG
217  PR1 ((Common->file, "proc "ID" node "ID" nchild "ID"\n", myid, c, nchild)) ;
218  {
219  Int cc ;
220  for (cc = 0 ; cc < LUsymbolic->ncomponents ; cc++)
221  {
222  PR2 ((Common->file,
223  "proc "ID": node "ID" sched "ID" cparent "ID" childp ["ID":"ID"]\n",
224  myid, cc, Sched [cc], LUsymbolic->Cparent [cc], Childp [cc],
225  Childp [cc+1]-1)) ;
226  for (cp = 0 ; cp < Childp [cc+1] - Childp [cc] ; cp++)
227  {
228  PR2 ((Common->file, "node "ID": child node "ID"\n",
229  cc, Child [Childp[c] + cp])) ;
230  }
231  }
232  }
233 #endif
234 
235  /* ---------------------------------------------------------------------- */
236  /* post a non-blocking receive for the header information from each child */
237  /* ---------------------------------------------------------------------- */
238 
239  PR1 ((Common->file, "proc "ID" posting recv at node "ID", nchild "ID" status "ID"\n",
240  myid, c, nchild, cm->status)) ;
241  nmessages = 0 ;
242  for (cp = 0 ; cp < nchild ; cp++)
243  {
244  child = Child [Childp [c] + cp] ;
245  PR2 ((Common->file, "proc "ID" child "ID" owned by "ID"\n",
246  myid, child, Sched [child])) ;
247  if (Sched [child] != myid)
248  {
249  PR2 ((Common->file, "parent proc "ID" awaits header from "ID"\n",
250  myid, Sched [child])) ;
251  MPI (MPI_Irecv (LU->LUnode [child]->header, PK_HEADER, MPI_Int,
252  Sched [child], TAG0, MPI_COMM_WORLD, &(LUnode->Req [cp]))) ;
253  nmessages++ ;
254  }
255  else
256  {
257  MPI (LUnode->Req [cp] = MPI_REQUEST_NULL) ;
258  }
259  }
260 
261 #ifdef NMPI
262  /* all nodes in the tree are scheduled to process zero, if no MPI */
263  ASSERT (nmessages == 0) ;
264 #endif
265 
266  /* ---------------------------------------------------------------------- */
267  /* get header and Schur complement from each child */
268  /* ---------------------------------------------------------------------- */
269 
270  ok = TRUE ;
271  for (k = 0 ; k < nmessages ; k++)
272  {
273 
274  /* ------------------------------------------------------------------ */
275  /* get header from a child who is ready to send its Schur complement*/
276  /* ------------------------------------------------------------------ */
277 
278  cp = 0 ;
279  MPI (MPI_Waitany (nchild, LUnode->Req, &cp, &ms)) ;
280 
281  child = Child [Childp [c] + cp] ;
282  ASSERT (Sched [child] != myid) ;
283 
284  status = LU->LUnode [child]->PK_STATUS ;
285  sn = LU->LUnode [child]->PK_SN ;
286  nfound = LU->LUnode [child]->PK_NFOUND ;
287  npiv = LU->LUnode [child]->PK_NPIV ;
288  ssize = LU->LUnode [child]->PK_SSIZE ;
289  cn = LU->LUnode [child]->PK_NN ;
290 
291  ok = ok && (status == PK_OK) ;
292 
293  /* ------------------------------------------------------------------ */
294  /* allocate space for Schur complement of the child */
295  /* ------------------------------------------------------------------ */
296 
297  if (ok)
298  {
299  /* allocate space for next message: the Schur complement */
300  LU->LUnode [child]->sp = CHOLMOD (malloc) (sn,
301  sizeof (Int), cm) ;
302  LU->LUnode [child]->slen = CHOLMOD (malloc) (sn,
303  sizeof (Int), cm) ;
304  LU->LUnode [child]->Pglobal = CHOLMOD (malloc) (npiv,
305  sizeof (Int), cm) ;
306  LU->LUnode [child]->Qglobal = CHOLMOD (malloc) (npiv,
307  sizeof (Int), cm) ;
308  LU->LUnode [child]->sx = CHOLMOD (malloc) (ssize,
309  sizeof (double), cm) ;
310 
311  /* allocate space for foward/backsolve */
312  LU->LUnode [child]->X = CHOLMOD (malloc) (cn,
313  sizeof (double), cm) ;
314  }
315 
316  if (cm->status != CHOLMOD_OK)
317  {
318  /* TODO return NULL, and broadcast error to all processes */
319  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
320  }
321 
322  /* check if we ran out of memory */
323  ok = ok && (cm->status == CHOLMOD_OK) ;
324 
325  /* ------------------------------------------------------------------ */
326  /* post receives for the Schur complement from the child */
327  /* ------------------------------------------------------------------ */
328 
329  if (ok)
330  {
331  /* both parent and child agree to send the Schur complement */
332  /* TODO: fold this information into fewer messages */
333  MPI (MPI_Irecv (LU->LUnode [child]->sp, sn, MPI_Int,
334  Sched [child], TAG0, MPI_COMM_WORLD, &(req [0]))) ;
335  MPI (MPI_Irecv (LU->LUnode [child]->slen, sn, MPI_Int,
336  Sched [child], TAG0, MPI_COMM_WORLD, &(req [1]))) ;
337  MPI (MPI_Irecv (LU->LUnode [child]->sx, ssize, MPI_DOUBLE,
338  Sched [child], TAG0, MPI_COMM_WORLD, &(req [2]))) ;
339  MPI (MPI_Irecv (LU->LUnode [child]->Pglobal, npiv, MPI_Int,
340  Sched [child], TAG0, MPI_COMM_WORLD, &(req [3]))) ;
341  MPI (MPI_Irecv (LU->LUnode [child]->Qglobal, npiv, MPI_Int,
342  Sched [child], TAG0, MPI_COMM_WORLD, &(req [4]))) ;
343  }
344 
345  /* ------------------------------------------------------------------ */
346  /* tell child that we are ready to receive its Schur complement */
347  /* ------------------------------------------------------------------ */
348 
349  PR1 ((Common->file, "parent proc "ID" replies to proc "ID"\n",
350  myid, Sched [child])) ;
351  MPI (MPI_Send (&ok, 1, MPI_INT, Sched [child], TAG0, MPI_COMM_WORLD)) ;
352 
353  /* ------------------------------------------------------------------ */
354  /* wait for the Schur complement to be received */
355  /* ------------------------------------------------------------------ */
356 
357  if (ok)
358  {
359  MPI (MPI_Waitall (5, req, MPI_STATUSES_IGNORE)) ;
360  }
361  }
362 
363  PR1 ((Common->file, "proc "ID" node "ID" arrowhead again\n", myid, c)) ;
364  DEBUG (CHOLMOD (print_sparse) (LUnode->A, "Arrowhead again", cm)) ;
365 
366  /* ---------------------------------------------------------------------- */
367  /* report failure to parent of c, if a failure occured */
368  /* ---------------------------------------------------------------------- */
369 
370  if (!ok)
371  {
372  PR0 ((Common->file, "proc "ID", node "ID", report failure to parent: "ID"\n",
373  myid, c, parent_id)) ;
374  /*
375  printf ("proc "ID" out of memory at node "ID"\n", myid, c) ;
376  */
378  LU, LUsymbolic, Common) ;
379  return (FALSE) ;
380  }
381 
382  DEBUG (CHOLMOD (print_sparse) (LUnode->A, "Arrowhead yet again", cm)) ;
383 
384  /* ---------------------------------------------------------------------- */
385  /* get lost pivots and Schur complement from each child */
386  /* ---------------------------------------------------------------------- */
387 
388  nlost_in = 0 ;
389 
390  Lost = LUnode->Lost ;
391  Lostp = LUnode->Lostp ;
392  LUnode->nchild = nchild ;
393 
394  s = cnz ;
395  for (cp = 0 ; cp < nchild ; cp++)
396  {
397  /* find the failed pivot rows/cols of this child and add them
398  * to the pivot candidate sets of this node s */
399  child = Child [Childp [c] + cp] ;
400  Lostp [cp] = nlost_in ;
401  Lost [cp] = LU->LUnode [child]->PK_NLOST ;
402  PR1 ((Common->file, "child "ID" lost "ID" \n", child, Lost [cp])) ;
403  nlost_in += Lost [cp] ;
404  s = CHOLMOD (add_size_t) (s, LU->LUnode [child]->PK_SNZ, &ok) ;
405  if (!ok)
406  {
407  /* TODO broadcast the error to all processes */
408  PARAKLETE_ERROR (PK_TOO_LARGE, "problem too large") ;
409  }
410  }
411  cnz = s ;
412  Lostp [nchild] = nlost_in ;
413  LUnode->nlost_in = nlost_in ;
414 
415  /* The matrix to factorize at this node is cn-by-cn. Up to npiv pivots
416  * can be found in this node */
417  cn = nlost_in + Cn [c] ;
418  npiv = nlost_in + (k2 - k1) ;
419  LUnode->PK_NN = cn ;
420 
421  LUnode->W2 = CHOLMOD (malloc) (nlost_in, 2*sizeof (Int), cm) ;
422  Plost_in = LUnode->W2 ; /* size nlost_in */
423  Qlost_in = LUnode->W2 + nlost_in ; /* size nlost_in */
424 
425  /* get workspace */
426  CHOLMOD (allocate_work) (cn, 3*cn, cn, cm) ;
427 
428  DEBUG (CHOLMOD (print_sparse) (LUnode->A, "Arrowhead once again", cm)) ;
429 
430  /* ---------------------------------------------------------------------- */
431  /* C = original entries in this node, plus Schur complements of children */
432  /* ---------------------------------------------------------------------- */
433 
434  /* TODO: assemble the Schur complements but do not compute C, just to
435  * determine cnz. Then do the CHOLMOD (allocate_sparse), below: */
436 
437  C = CHOLMOD (allocate_sparse) (cn, cn, cnz, FALSE, TRUE, 0, TRUE, cm) ;
438  LUnode->C = C ;
439 
440  if (cm->status != CHOLMOD_OK)
441  {
442  /* out of memory; tell the parent that we failed */
443  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
445  LU, LUsymbolic, Common) ;
446  return (FALSE) ;
447  }
448 
449  Cp = C->p ;
450  Ci = C->i ;
451  Cx = C->x ;
452 
453  /* ---------------------------------------------------------------------- */
454  /* concatenate and remap the lost pivot columns of each child */
455  /* ---------------------------------------------------------------------- */
456 
457  k = 0 ;
458  cnz = 0 ;
459  for (cp = 0 ; cp < nchild ; cp++)
460  {
461  /* get the Schur complement of the child */
462  child = Child [Childp [c] + cp] ;
463  sn = LU->LUnode [child]->PK_SN ;
464 
465  PR1 ((Common->file, "\nconcatenate lost child "ID", Lost [cp] "ID"\n",
466  child, Lost [cp])) ;
467  S = LU->LUnode [child]->sx ;
468  Sp = LU->LUnode [child]->sp ;
469  Slen = LU->LUnode [child]->slen ;
470  nfound = LU->LUnode [child]->PK_NFOUND ;
471 
472  PR1 ((Common->file, "Cn [c] is "ID"\n", Cn [c])) ;
473  PR1 ((Common->file, "child is "ID"\n", child)) ;
474  PR1 ((Common->file, "Lost[cp] is "ID"\n", Lost [cp])) ;
475  PR1 ((Common->file, "sn "ID" Lost[cp]+Cn[cn] "ID"\n",
476  sn, Lost [cp] + Cn [c]));
477 
478  ASSERT (sn == Lost [cp] + Cn [c]) ;
479 
480  for (j = 0 ; j < Lost [cp] ; j++)
481  {
482  /* column j of the Schur complement of the child becomes column
483  * k of C */
484  PR2 ((Common->file, "lost child col "ID" becomes col "ID" of C\n",
485  j, k)) ;
486  Cp [k] = cnz ;
487  GET_COLUMN (Sp, Slen, S, j, Si, Sx, len) ;
488  for (p = 0 ; p < len ; p++)
489  {
490  i = Si [p] ;
491  ci = i + ((i < Lost [cp]) ? Lostp [cp] : (nlost_in - Lost[cp]));
492  Ci [cnz] = ci ;
493  Cx [cnz] = Sx [p] ;
494  PR3 ((Common->file,
495  " Lost child col: row "ID" newrow "ID" value %g\n",
496  i, ci, Sx [p])) ;
497  cnz++ ;
498  }
499  /* get the lost pivot row/column from the child */
500  Plost_in [k] = LU->LUnode [child]->Pglobal [nfound+j] ;
501  Qlost_in [k] = LU->LUnode [child]->Qglobal [nfound+j] ;
502  k++ ;
503  }
504  }
505  ASSERT (k == nlost_in) ;
506 
507  /* ---------------------------------------------------------------------- */
508  /* assemble original entries and Schur complements of each child */
509  /* ---------------------------------------------------------------------- */
510 
511  Flag = cm->Flag ;
512  W = cm->Xwork ;
513  /* mark = CHOLMOD (clear_flag) (cm) ; */
514  CHOLMOD_CLEAR_FLAG (cm) ;
515  mark = cm->mark ;
516 
517  ASSERT (cm->xworksize >= (size_t) cn) ;
518  DEBUG (for (cj = 0 ; cj < cn ; cj++) ASSERT (W [cj] == 0)) ;
519 
520  for (j = 0 ; j < Cn [c] ; j++)
521  {
522 
523  /* Column j is nominal column index, if there were no failed pivots.
524  * The column is shifted over to accomodate incoming lost pivot columns
525  * from the children, to obtain the new column cj. */
526 
527  cj = j + nlost_in ;
528  Cp [cj] = cnz ;
529  PR2 ((Common->file, "\nAdd column "ID" of Schur\n", cj)) ;
530 
531  /* ------------------------------------------------------------------ */
532  /* add up all the contributions to column cj of C */
533  /* ------------------------------------------------------------------ */
534 
535  /* scatter the original entries of column j. A is the input arrowhead
536  * for this node, with row/col indices already mapped to the local
537  * row/col index space (in range 0 to Cn [c]). */
538  for (p = Ap [j] ; p < Ap [j+1] ; p++)
539  {
540  i = Ai [p] ;
541  ci = i + nlost_in ;
542  PR3 ((Common->file, "scatter original ("ID","ID") %g to ("ID","ID")\n",
543  i, j, Ax [p], ci, cj)) ;
544  Flag [ci] = mark ;
545  Ci [cnz++] = ci ;
546  W [ci] = Ax [p] ;
547  }
548 
549  /* scatter and add the contributions from each child */
550  for (cp = 0 ; cp < nchild ; cp++)
551  {
552  /* get column j+Lost[cp] of the Schur complement of the child */
553  child = Child [Childp [c] + cp] ;
554  S = LU->LUnode [child]->sx ;
555  Sp = LU->LUnode [child]->sp ;
556  Slen = LU->LUnode [child]->slen ;
557  GET_COLUMN (Sp, Slen, S, j + Lost [cp], Si, Sx, len) ;
558  for (p = 0 ; p < len ; p++)
559  {
560  i = Si [p] ;
561  ci = i + ((i < Lost [cp]) ? Lostp [cp] : (nlost_in - Lost[cp]));
562  if (Flag [ci] < mark)
563  {
564  Flag [ci] = mark ;
565  Ci [cnz++] = ci ;
566  }
567  W [ci] += Sx [p] ;
568  }
569  }
570 
571  /* gather the results */
572  PR2 ((Common->file, "gather "ID" to "ID"-1\n", Cp [cj], cnz)) ;
573  for (p = Cp [cj] ; p < cnz ; p++)
574  {
575  ci = Ci [p] ;
576  Cx [p] = W [ci] ;
577  W [ci] = 0 ;
578  PR3 ((Common->file, ""ID": %g\n", ci, Cx [p])) ;
579  }
580  DEBUG (for (cj = 0 ; cj < cn ; cj++) ASSERT (W [cj] == 0)) ;
581 
582  /* clear Flag array */
583  /* mark = CHOLMOD (clear_flag) (cm) ; */
584  CHOLMOD_CLEAR_FLAG (cm) ;
585  mark = cm->mark ;
586  }
587 
588  Cp [cn] = cnz ;
589 
590  /* shrink C to be just large enough */
591  CHOLMOD (reallocate_sparse) (cnz, C, cm) ;
592  ASSERT (cm->status == CHOLMOD_OK) ;
593 
594  /* ---------------------------------------------------------------------- */
595  /* A for this node, and Schur complements of children, no longer needed */
596  /* ---------------------------------------------------------------------- */
597 
598  paraklete_free_children (c, LU, LUsymbolic, Common) ;
599 
600  /* ---------------------------------------------------------------------- */
601  /* allocate the LU factors for this node */
602  /* ---------------------------------------------------------------------- */
603 
604  /* LUnode->lusize = 1.2 * (2 * ((3*clnz)/2 + 2)) ; */
605  /* clnz is already checked for integer overflow */
606  s = clnz ;
607  s = CHOLMOD (mult_size_t) (s, 3, &ok) / 2 ; /* (3*clnz)/2 */
608  s = CHOLMOD (add_size_t) (s, 2, &ok) ; /* add 2 */
609  s = CHOLMOD (mult_size_t) (s, 2, &ok) ; /* times 2 */
610  s = CHOLMOD (add_size_t) (s, s/5, &ok) ; /* add s/5 */
611  LUnode->lusize = s ;
612 
613  LUnode->PK_NPIV = npiv ;
614 
615  LUnode->llen = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
616  LUnode->lp = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
617 
618  LUnode->ulen = CHOLMOD (malloc) (cn, sizeof (Int), cm) ;
619  LUnode->up = CHOLMOD (malloc) (cn, sizeof (Int), cm) ;
620 
621  LUnode->Plocal = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
622  LUnode->Pglobal = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
623  LUnode->Qlocal = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
624  LUnode->Qglobal = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
625 
626  LUnode->Pinv = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
627  LUnode->Qinv = CHOLMOD (malloc) (npiv, sizeof (Int), cm) ;
628 
629  /* this block of memory may grow in size */
630  LUnode->ix = CHOLMOD (malloc) (LUnode->lusize, sizeof (double), cm) ;
631  PR1 ((Common->file, "allocated LUnode->ix: size "ID"\n", LUnode->lusize)) ;
632 
633  if (cm->status != CHOLMOD_OK)
634  {
635  /* out of memory */
636  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
638  LU, LUsymbolic, Common) ;
639  return (FALSE) ;
640  }
641 
642  /* ---------------------------------------------------------------------- */
643  /* factorize P*C*Q into L*U+S */
644  /* ---------------------------------------------------------------------- */
645 
646  ASSERT (CHOLMOD (print_sparse) (C, "C = A + sum (Schur)", cm)) ;
647  ok = amesos_paraklete_kernel (C, LUnode, Common) ;
648 
649  if (!ok)
650  {
651  /* out of memory */
652  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
654  LU, LUsymbolic, Common) ;
655  return (FALSE) ;
656  }
657 
658  PR0 ((Common->file, "============= NODE "ID" NPIV "ID" FOUND "ID" LOST "ID"\n", c,
659  LUnode->PK_NPIV, LUnode->PK_NFOUND,
660  LUnode->PK_NPIV - LUnode->PK_NFOUND)) ;
661 
662  /* TODO ensure the kernel does this */
663  cm->mark = EMPTY ;
664  /* CHOLMOD (clear_flag) (cm) ; */
665  CHOLMOD_CLEAR_FLAG (cm)
666 
667  Plocal = LUnode->Plocal ;
668  Pinv = LUnode->Pinv ;
669  for (k = 0 ; k < npiv ; k++)
670  {
671  i = Plocal [k] ;
672  ASSERT (i >= 0 && i < npiv) ;
673  ASSERT (Pinv [i] == k) ;
674  }
675 
676  /* ---------------------------------------------------------------------- */
677  /* determine the global pivot ordering (not including LUsymbolic->Cperm) */
678  /* ---------------------------------------------------------------------- */
679 
680  Plocal = LUnode->Plocal ;
681  Qlocal = LUnode->Qlocal ;
682 
683  Pglobal = LUnode->Pglobal ;
684  Qglobal = LUnode->Qglobal ;
685 
686  DEBUG (CHOLMOD (print_perm) (Plocal, npiv, npiv, "Node P, local", cm)) ;
687  DEBUG (CHOLMOD (print_perm) (Qlocal, npiv, npiv, "Node Q, local", cm)) ;
688 
689  nfound = LUnode->PK_NFOUND ;
690 
691  for (k = 0 ; k < npiv ; k++)
692  {
693  i = Plocal [k] ;
694  if (i < nlost_in)
695  {
696  /* row i was the ith incoming lost row, from the children */
697  Pglobal [k] = Plost_in [i] ;
698  }
699  else
700  {
701  /* row i was an original candidate for this node. It was shifted
702  * by nlost_in to obtain the local index. Then k1 needs to be added
703  * to obtain the global index. */
704  Pglobal [k] = i - nlost_in + k1 ;
705  }
706  }
707  for (k = 0 ; k < npiv ; k++)
708  {
709  j = Qlocal [k] ;
710  if (j < nlost_in)
711  {
712  /* col j was the jth incoming lost col, from the children */
713  Qglobal [k] = Qlost_in [j] ;
714  }
715  else
716  {
717  /* col j was an original candidate for this node. It was shifted
718  * by nlost_in to obtain the local index. Then k1 needs to be added
719  * to obtain the global index. */
720  Qglobal [k] = j - nlost_in + k1 ;
721  }
722  }
723 
724  LUnode->PK_NLOST = npiv - nfound ;
725 
726  DEBUG (CHOLMOD (print_perm) (Pglobal, npiv, LU->n, "Node P, global", cm)) ;
727  DEBUG (CHOLMOD (print_perm) (Qglobal, npiv, LU->n, "Node Q, global", cm)) ;
728 
729  /* ---------------------------------------------------------------------- */
730  /* allocate space for subsequent forward/backsolve */
731  /* ---------------------------------------------------------------------- */
732 
733  LU->LUnode [c]->X = CHOLMOD (malloc) (cn, sizeof (double), cm) ;
734  ASSERT (k2-k1 == LUnode->nk) ;
735  LU->LUnode [c]->B = CHOLMOD (malloc) (k2-k1, sizeof (double), cm) ;
736 
737  if (cm->status != CHOLMOD_OK)
738  {
739  /* out of memory */
740  PARAKLETE_ERROR (PK_OUT_OF_MEMORY, "out of memory") ;
742  LU, LUsymbolic, Common) ;
743  return (FALSE) ;
744  }
745 
746  /* ---------------------------------------------------------------------- */
747  /* send Schur complement to the parent */
748  /* ---------------------------------------------------------------------- */
749 
750  PR0 ((Common->file, "proc "ID" done at node "ID"\n", myid, c)) ;
751 
752  paraklete_send_to_parent (c, PK_OK, parent_id, LU, LUsymbolic, Common) ;
753 
754  PR0 ((Common->file, "proc "ID" done send to parent at node "ID"\n", myid, c)) ;
755 
756  return (TRUE) ;
757 }
#define TAG0
#define MPI_Int
#define EMPTY
#define Int
size_t CHOLMOD() add_size_t(size_t a, size_t b, int *ok)
#define FALSE
#define PR0(params)
int CHOLMOD() reallocate_sparse(size_t nznew, cholmod_sparse *A, cholmod_common *Common)
#define PK_HEADER
size_t CHOLMOD() mult_size_t(size_t a, size_t k, int *ok)
#define PARAKLETE_ERROR(status, message)
#define CHOLMOD(name)
#define PK_TOO_LARGE
int CHOLMOD() print_sparse(cholmod_sparse *A, char *name, cholmod_common *Common)
#define PK_OK
#define PR2(params)
static void paraklete_send_to_parent(Int c, Int status, Int parent_id, paraklete_numeric *LU, paraklete_symbolic *LUsymbolic, paraklete_common *Common)
static void paraklete_free_children(Int c, paraklete_numeric *LU, paraklete_symbolic *LUsymbolic, paraklete_common *Common)
int CHOLMOD() free_sparse(cholmod_sparse **AHandle, cholmod_common *Common)
#define GET_COLUMN(Ap, Anz, Aix, j, Ai, Ax, len)
#define ASSERT(expression)
#define ID
#define PR1(params)
#define PR3(params)
#define CHOLMOD_OK
int CHOLMOD() print_perm(Int *Perm, size_t len, size_t n, char *name, cholmod_common *Common)
#define PK_OUT_OF_MEMORY
Int amesos_paraklete_kernel(cholmod_sparse *A, paraklete_node *LUnode, paraklete_common *Common)
#define MPI(statement)
cholmod_sparse *CHOLMOD() allocate_sparse(size_t nrow, size_t ncol, size_t nzmax, int sorted, int packed, int stype, int xtype, cholmod_common *Common)
int CHOLMOD() allocate_work(size_t nrow, size_t iworksize, size_t xworksize, cholmod_common *Common)
Int amesos_paraklete_factorize_node(Int c, paraklete_numeric *LU, paraklete_symbolic *LUsymbolic, paraklete_common *Common)
#define DEBUG(statement)
#define CHOLMOD_CLEAR_FLAG(Common)
#define IMPLIES(p, q)
#define TRUE