1 /*  util.c  */
2 
3 #include "../ETree.h"
4 
5 #define MYDEBUG 0
6 
7 /*--------------------------------------------------------------------*/
8 /*
9    ----------------------------------------------
10    return the number of bytes taken by the object
11 
12    created -- 95nov15, cca
13    ----------------------------------------------
14 */
15 int
ETree_sizeOf(ETree * etree)16 ETree_sizeOf (
17    ETree   *etree
18 ) {
19 int   nbytes ;
20 /*
21    ---------------
22    check the input
23    ---------------
24 */
25 if ( etree == NULL ) {
26    fprintf(stderr, "\n fatal error in ETree_sizeOf(%p)"
27            "\n bad input\n", etree) ;
28    exit(-1) ;
29 }
30 nbytes = sizeof(struct _ETree) ;
31 if ( etree->tree != NULL ) {
32    nbytes += Tree_sizeOf(etree->tree) ;
33 }
34 if ( etree->nodwghtsIV != NULL ) {
35    nbytes += IV_sizeOf(etree->nodwghtsIV) ;
36 }
37 if ( etree->nodwghtsIV != NULL ) {
38    nbytes += IV_sizeOf(etree->bndwghtsIV) ;
39 }
40 if ( etree->vtxToFrontIV != NULL ) {
41    nbytes += IV_sizeOf(etree->vtxToFrontIV) ;
42 }
43 return(nbytes) ; }
44 
45 /*--------------------------------------------------------------------*/
46 /*
47    ----------------------------------------
48    return the number of factor indices
49 
50    created  -- 95nov15, cca
51    modified -- 96jan11, cca
52    ----------------------------------------
53 */
54 int
ETree_nFactorIndices(ETree * etree)55 ETree_nFactorIndices (
56    ETree   *etree
57 ) {
58 int   nb, nfront, nv, nind, nvtx, v ;
59 int   *bndwghts, *nodwghts ;
60 /*
61    ---------------
62    check the input
63    ---------------
64 */
65 if ( etree == NULL
66    || (nfront = etree->nfront) <= 0
67    || (nvtx = etree->nvtx) <= 0 ) {
68    fprintf(stderr, "\n fatal error in ETree_nFactorIndices(%p)"
69            "\n bad input\n", etree) ;
70    exit(-1) ;
71 }
72 nodwghts = IV_entries(etree->nodwghtsIV) ;
73 bndwghts = IV_entries(etree->bndwghtsIV) ;
74 nind = 0 ;
75 for ( v = 0 ; v < nfront ; v++ ) {
76    nv = nodwghts[v] ;
77    nb = bndwghts[v] ;
78    nind += nv + nb ;
79 }
80 return(nind) ; }
81 
82 /*--------------------------------------------------------------------*/
83 /*
84    ------------------------------------------
85    return the number of factor entries
86 
87    symflag -- symmetry flag
88      0 (SPOOLES_SYMMETRIC)    -- symmetric
89      1 (SPOOLES_HERMITIAN)    -- hermitian
90      2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric
91 
92    created -- 98jun05, cca
93    ------------------------------------------
94 */
95 int
ETree_nFactorEntries(ETree * etree,int symflag)96 ETree_nFactorEntries (
97    ETree   *etree,
98    int     symflag
99 ) {
100 int   J, nfront, nvtx, nzf ;
101 /*
102    ---------------
103    check the input
104    ---------------
105 */
106 if ( etree == NULL
107    || (nfront = etree->nfront) <= 0
108    || (nvtx = etree->nvtx) <= 0 ) {
109    fprintf(stderr, "\n fatal error in ETree_nFactorEntries(%p,%d)"
110            "\n bad input\n", etree, symflag) ;
111    exit(-1) ;
112 }
113 nzf = 0 ;
114 for ( J = 0 ; J < nfront ; J++ ) {
115    nzf += ETree_nFactorEntriesInFront(etree, symflag, J) ;
116 }
117 return(nzf) ; }
118 
119 /*--------------------------------------------------------------------*/
120 /*
121    ------------------------------------------
122    return the number of factor operations
123 
124    type -- type of matrix entries
125      1 (SPOOLES_REAL)    -- real entries
126      2 (SPOOLES_COMPLEX) -- complex entries
127    symflag -- symmetry flag
128      0 (SPOOLES_SYMMETRIC)    -- symmetric
129      1 (SPOOLES_HERMITIAN)    -- hermitian
130      2 (SPOOLES_NONSYMMETRIC) -- nonsymmetric
131 
132    created -- 98jun05, cca
133    ------------------------------------------
134 */
135 double
ETree_nFactorOps(ETree * etree,int type,int symflag)136 ETree_nFactorOps (
137    ETree   *etree,
138    int     type,
139    int     symflag
140 ) {
141 double   ops ;
142 int      J, nfront, nvtx ;
143 /*
144    ---------------
145    check the input
146    ---------------
147 */
148 if ( etree == NULL
149    || (nfront = etree->nfront) <= 0
150    || (nvtx = etree->nvtx) <= 0 ) {
151    fprintf(stderr, "\n fatal error in ETree_nFactorOps(%p,%d,%d)"
152            "\n bad input\n", etree, type, symflag) ;
153    exit(-1) ;
154 }
155 ops = 0 ;
156 for ( J = 0 ; J < nfront ; J++ ) {
157    ops += ETree_nInternalOpsInFront(etree, type, symflag, J)
158         + ETree_nExternalOpsInFront(etree, type, symflag, J) ;
159 }
160 return(ops) ; }
161 
162 /*--------------------------------------------------------------------*/
163 /*
164    ----------------------------------------
165    return the number of entries an LU front
166 
167    created -- 96dec04, cca
168    ----------------------------------------
169 */
170 double
ETree_nFactorEntriesInFront(ETree * etree,int symflag,int J)171 ETree_nFactorEntriesInFront (
172    ETree   *etree,
173    int     symflag,
174    int     J
175 ) {
176 int   b, m, nent ;
177 /*
178    ---------------
179    check the input
180    ---------------
181 */
182 if ( etree == NULL
183    || etree->nfront <= 0
184    || J < 0 || J >= etree->nfront ) {
185    fprintf(stderr,
186            "\n fatal error in ETree_nFactorEntriesInFront(%p,%d,%d)"
187            "\n bad input\n", etree, symflag, J) ;
188    exit(-1) ;
189 }
190 b = IV_entry(etree->nodwghtsIV, J) ;
191 m = IV_entry(etree->bndwghtsIV, J) ;
192 switch ( symflag ) {
193 case SPOOLES_SYMMETRIC :
194 case SPOOLES_HERMITIAN :
195    nent = (b*(b+1))/2 + b*m ;
196    break ;
197 case SPOOLES_NONSYMMETRIC :
198    nent = b*b + 2*b*m ;
199    break ;
200 default :
201    fprintf(stderr,
202            "\n fatal error in ETree_nFactorEntriesInFront(%p,%d,%d)"
203            "\n bad symflag\n", etree, symflag, J) ;
204    break ;
205 }
206 
207 return(nent) ; }
208 
209 /*--------------------------------------------------------------------*/
210 /*
211    -------------------------------------------------------
212    return the number of internal LU operations for a front
213 
214    created -- 96dec04, cca
215    -------------------------------------------------------
216 */
217 double
ETree_nInternalOpsInFront(ETree * etree,int type,int symflag,int J)218 ETree_nInternalOpsInFront (
219    ETree   *etree,
220    int     type,
221    int     symflag,
222    int     J
223 ) {
224 double   b, m, ops ;
225 /*
226    ---------------
227    check the input
228    ---------------
229 */
230 if ( etree == NULL
231    || etree->nfront <= 0
232    || J < 0 || J >= etree->nfront ) {
233    fprintf(stderr,
234            "\n fatal error in ETree_nInternalOpsInFront(%p,%d,%d,%d)"
235            "\n bad input\n", etree, type, symflag, J) ;
236    exit(-1) ;
237 }
238 b = ETree_frontSize(etree, J) ;
239 m = ETree_frontBoundarySize(etree, J) ;
240 switch ( symflag ) {
241 case SPOOLES_SYMMETRIC :
242 case SPOOLES_HERMITIAN :
243    ops = (b*(b+1)*(2*b+1))/6. + m*b*b ;
244    break ;
245 case SPOOLES_NONSYMMETRIC :
246    ops = b*(2*b*b+1)/3. + 2*m*b*b ;
247    break ;
248 default :
249    fprintf(stderr,
250            "\n fatal error in ETree_nInternalOpsInFront(%p,%d,%d,%d)"
251            "\n bad symflag\n", etree, type, symflag, J) ;
252    break ;
253 }
254 switch ( type ) {
255 case SPOOLES_REAL :
256    break ;
257 case SPOOLES_COMPLEX :
258    ops = 4*ops ;
259    break ;
260 default :
261    fprintf(stderr,
262            "\n fatal error in ETree_nInternalOpsInFront(%p,%d,%d,%d)"
263            "\n bad type\n", etree, type, symflag, J) ;
264    break ;
265 }
266 return(ops) ; }
267 
268 /*--------------------------------------------------------------------*/
269 /*
270    -------------------------------------------------------
271    return the number of external LU operations for a front
272 
273    created -- 96dec04, cca
274    -------------------------------------------------------
275 */
276 double
ETree_nExternalOpsInFront(ETree * etree,int type,int symflag,int J)277 ETree_nExternalOpsInFront (
278    ETree   *etree,
279    int     type,
280    int     symflag,
281    int     J
282 ) {
283 double   b, m, ops ;
284 /*
285    ---------------
286    check the input
287    ---------------
288 */
289 if ( etree == NULL
290    || etree->nfront <= 0
291    || J < 0 || J >= etree->nfront ) {
292    fprintf(stderr,
293            "\n fatal error in ETree_nExternalOpsInFront(%p,%d,%d,%d)"
294            "\n bad input\n", etree, J, type, symflag) ;
295    exit(-1) ;
296 }
297 b = IV_entry(etree->nodwghtsIV, J) ;
298 m = IV_entry(etree->bndwghtsIV, J) ;
299 switch ( symflag ) {
300 case SPOOLES_SYMMETRIC :
301 case SPOOLES_HERMITIAN :
302    ops = m*(m+1)*b ;
303    break ;
304 case SPOOLES_NONSYMMETRIC :
305    ops = 2*b*m*m ;
306    break ;
307 default :
308    break ;
309 }
310 switch ( type ) {
311 case SPOOLES_REAL :
312    break ;
313 case SPOOLES_COMPLEX :
314    ops = 4*ops ;
315    break ;
316 default :
317    fprintf(stderr,
318            "\n fatal error in ETree_nExternalOpsInFront(%p,%d,%d,%d)"
319            "\n bad input\n", etree, J, type, symflag) ;
320    break ;
321 }
322 return(ops) ; }
323 
324 /*--------------------------------------------------------------------*/
325 /*
326    ---------------------------------------------------------
327    return a DV object that contains the number of operations
328    for each front using a backward looking algorithm
329 
330    created -- 96dec04, cca
331    ---------------------------------------------------------
332 */
333 DV *
ETree_backwardOps(ETree * etree,int type,int symflag,int * vwghts,IVL * symbfacIVL)334 ETree_backwardOps (
335    ETree   *etree,
336    int     type,
337    int     symflag,
338    int     *vwghts,
339    IVL     *symbfacIVL
340 ) {
341 double   extops, opsKbndK, opsKK ;
342 double   *ops ;
343 DV       *opsDV ;
344 int      bndwghtJ, ii, J, k, K, kwght,
345          nadj, nfront, size, wghtJ, wghtK ;
346 int      *counts, *indices, *list, *mark, *vtxToFront ;
347 /*
348    ---------------
349    check the input
350    ---------------
351 */
352 if ( etree == NULL || symbfacIVL == NULL ) {
353    fprintf(stderr, "\n fatal error in ETree_backwardOps(%p,%p,%p)"
354            "\n bad input\n", etree, vwghts, symbfacIVL) ;
355    exit(-1) ;
356 }
357 nfront     = etree->nfront ;
358 vtxToFront = IV_entries(etree->vtxToFrontIV) ;
359 list   = IVinit(nfront, -1) ;
360 mark   = IVinit(nfront, -1) ;
361 counts = IVinit(nfront, 0) ;
362 /*
363    ----------------------------
364    initialize the ops DV object
365    ----------------------------
366 */
367 opsDV = DV_new() ;
368 DV_init(opsDV, nfront, NULL) ;
369 ops = DV_entries(opsDV) ;
370 DV_fill(opsDV, 0.0) ;
371 /*
372    -------------------
373    fill the ops vector
374    -------------------
375 */
376 for ( J = 0 ; J < nfront ; J++ ) {
377    ops[J]  += ETree_nInternalOpsInFront(etree, type, symflag, J) ;
378    wghtJ    = ETree_frontSize(etree, J) ;
379    bndwghtJ = ETree_frontBoundarySize(etree, J) ;
380    IVL_listAndSize(symbfacIVL, J, &size, &indices) ;
381    for ( ii = nadj = 0 ; ii < size ; ii++ ) {
382       k = indices[ii] ;
383       if ( (K = vtxToFront[k]) != J ) {
384          kwght = (vwghts == NULL) ? 1 : vwghts[k] ;
385          if ( mark[K] != J ) {
386             counts[K] = 0 ;
387             mark[K] = J ;
388             list[nadj++] = K ;
389          }
390          counts[K] += kwght ;
391       }
392    }
393    IVqsortUp(nadj, list) ;
394    extops = 0.0 ;
395    for ( ii = 0 ; ii < nadj ; ii++ ) {
396       K = list[ii] ;
397       wghtK = counts[K] ;
398       bndwghtJ -= wghtK ;
399       if ( type == SPOOLES_REAL ) {
400          opsKbndK = 2*wghtJ*wghtK*bndwghtJ ;
401          if ( symflag == SPOOLES_SYMMETRIC ) {
402             opsKK = wghtJ*wghtK*(wghtK+1) ;
403          } else if ( symflag == SPOOLES_NONSYMMETRIC ) {
404             opsKK = 2*wghtJ*wghtK*wghtK ;
405          }
406       } else if ( type == SPOOLES_COMPLEX ) {
407          opsKbndK = 8*wghtJ*wghtK*bndwghtJ ;
408          if (  symflag == SPOOLES_SYMMETRIC
409             || symflag == SPOOLES_HERMITIAN ) {
410             opsKK = 4*wghtJ*wghtK*(wghtK+1) ;
411          } else if ( symflag == SPOOLES_NONSYMMETRIC ) {
412             opsKK = 8*wghtJ*wghtK*wghtK ;
413          }
414       }
415       extops += opsKK + opsKbndK ;
416       ops[K] += opsKK + opsKbndK ;
417       if ( symflag == SPOOLES_NONSYMMETRIC ) {
418          extops += opsKbndK ;
419          ops[K] += opsKbndK ;
420       }
421    }
422 /*
423    fprintf(stdout,
424        "\n front %d, %.0f internal ops, %.0f external ops, %.0f extops",
425            J, ETree_nInternalOpsInFront(etree, type, symflag, J),
426            ETree_nExternalOpsInFront(etree, type, symflag, J), extops) ;
427 */
428 }
429 IVfree(list) ;
430 IVfree(mark) ;
431 IVfree(counts) ;
432 
433 return(opsDV) ; }
434 
435 /*--------------------------------------------------------------------*/
436 /*
437    ------------------------------------
438    return an IV object that contains
439    the number of entries for each front
440 
441    created -- 98jan30, cca
442    ------------------------------------
443 */
444 IV *
ETree_factorEntriesIV(ETree * etree,int symflag)445 ETree_factorEntriesIV (
446    ETree   *etree,
447    int     symflag
448 ) {
449 int   J, nfront ;
450 int   *nzf ;
451 IV    *nzfIV ;
452 /*
453    ---------------
454    check the input
455    ---------------
456 */
457 if ( etree == NULL ) {
458    fprintf(stderr, "\n fatal error in ETree_factorEntriesIV(%p,%d)"
459            "\n bad input\n", etree, symflag) ;
460    exit(-1) ;
461 }
462 nfront = ETree_nfront(etree) ;
463 /*
464    ------------------------
465    initialize the IV object
466    ------------------------
467 */
468 nzfIV = IV_new() ;
469 IV_init(nzfIV, nfront, NULL) ;
470 nzf = IV_entries(nzfIV) ;
471 IV_fill(nzfIV, 0) ;
472 /*
473    -------------------
474    fill the nzf vector
475    -------------------
476 */
477 for ( J = 0 ; J < nfront ; J++ ) {
478    nzf[J] = ETree_nFactorEntriesInFront(etree, symflag, J) ;
479 }
480 return(nzfIV) ; }
481 
482 /*--------------------------------------------------------------------*/
483 /*
484    ---------------------------------------------------------
485    return a DV object that contains the number of operations
486    for each front using a forward-looking algorithm
487 
488    created -- 96dec04, cca
489    ---------------------------------------------------------
490 */
491 DV *
ETree_forwardOps(ETree * etree,int type,int symflag)492 ETree_forwardOps (
493    ETree   *etree,
494    int     type,
495    int     symflag
496 ) {
497 double   *ops ;
498 DV       *opsDV ;
499 int      J, nfront ;
500 /*
501    ---------------
502    check the input
503    ---------------
504 */
505 if ( etree == NULL ) {
506    fprintf(stderr, "\n fatal error in ETree_forwardOps(%p)"
507            "\n bad input\n", etree) ;
508    exit(-1) ;
509 }
510 nfront     = etree->nfront ;
511 opsDV = DV_new() ;
512 DV_init(opsDV, nfront, NULL) ;
513 ops = DV_entries(opsDV) ;
514 DV_fill(opsDV, 0.0) ;
515 for ( J = 0 ; J < nfront ; J++ ) {
516    ops[J] += ETree_nInternalOpsInFront(etree, type, symflag, J)
517           +  ETree_nExternalOpsInFront(etree, type, symflag, J) ;
518 }
519 return(opsDV) ; }
520 
521 /*--------------------------------------------------------------------*/
522 /*
523    ---------------------------------------------------------------
524    given an IV object that maps uncompressed vertices to vertices,
525    create and return an ETree object that is relative to the
526    uncompressed graph.
527 
528    created -- 97feb13, cca
529    ---------------------------------------------------------------
530 */
531 ETree *
ETree_expand(ETree * etree,IV * eqmapIV)532 ETree_expand (
533    ETree   *etree,
534    IV      *eqmapIV
535 ) {
536 ETree   *etree2 ;
537 int     ii, ndof, nfront ;
538 int     *map, *vtxToFront, *vtxToFront2 ;
539 /*
540    ---------------
541    check the input
542    ---------------
543 */
544 if ( etree == NULL || eqmapIV == NULL ) {
545    fprintf(stderr, "\n fatal error in ETree_expand(%p,%p)"
546            "\n bad input\n", etree, eqmapIV) ;
547    exit(-1) ;
548 }
549 nfront = etree->nfront ;
550 IV_sizeAndEntries(eqmapIV, &ndof, &map) ;
551 /*
552    ---------------------------
553    create the new ETree object
554    ---------------------------
555 */
556 etree2 = ETree_new() ;
557 ETree_init1(etree2, nfront, ndof) ;
558 IV_copy(etree2->nodwghtsIV, etree->nodwghtsIV) ;
559 IV_copy(etree2->bndwghtsIV, etree->bndwghtsIV) ;
560 etree2->tree->root = etree->tree->root ;
561 IVcopy(nfront, etree2->tree->par, etree->tree->par) ;
562 IVcopy(nfront, etree2->tree->fch, etree->tree->fch) ;
563 IVcopy(nfront, etree2->tree->sib, etree->tree->sib) ;
564 vtxToFront  = IV_entries(etree->vtxToFrontIV) ;
565 vtxToFront2 = IV_entries(etree2->vtxToFrontIV) ;
566 for ( ii = 0 ; ii < ndof ; ii++ ) {
567    vtxToFront2[ii] = vtxToFront[map[ii]] ;
568 }
569 
570 return(etree2) ; }
571 
572 /*--------------------------------------------------------------------*/
573 /*
574    --------------------------------------------------------------
575    this method is used to splice together two front trees
576    when the domain vertices and schur complement vertices
577    have been ordered separately.
578 
579    etree0 -- the lower front tree is for vertices in the domains.
580    graph0 -- graph for all the vertices
581    mapIV  -- IV object that maps vertices to schur complement
582              vertices, if IV_entry(mapIV, v) < 0 then v is
583              a domain vertex.
584    etree1 -- the upper front tree is for vertices in the schur
585              complement.
586 
587    created -- 97feb01, cca
588    --------------------------------------------------------------
589 */
590 ETree *
ETree_spliceTwoETrees(ETree * etree0,Graph * graph0,IV * mapIV,ETree * etree1)591 ETree_spliceTwoETrees (
592    ETree   *etree0,
593    Graph   *graph0,
594    IV      *mapIV,
595    ETree   *etree1
596 ) {
597 ETree   *etree2 ;
598 int     *bndwghts0, *bndwghts1, *bndwghts2, *fch0, *head0, *link0,
599         *map, *mark, *nodwghts0, *nodwghts1, *nodwghts2, *par0,
600         *par1, *par2, *sib0, *vadj, *vtxToFront0, *vtxToFront1,
601         *vtxToFront2 ;
602 int     ii, J, K, nfront0, nfront1, nfront2, nvtx, phi, v, vsize, w ;
603 /*
604    ---------------
605    check the input
606    ---------------
607 */
608 if (  etree0 == NULL || graph0 == NULL
609    || mapIV == NULL || etree1 == NULL ) {
610    fprintf(stderr,
611            "\n fatal error in ETree_spliceTwoETrees(%p,%p,%p,%p)"
612            "\n bad input\n",
613            etree0, graph0, mapIV, etree1) ;
614    exit(-1) ;
615 }
616 nfront0     = etree0->nfront ;
617 nvtx        = etree0->nvtx    ;
618 par0        = etree0->tree->par ;
619 fch0        = etree0->tree->fch ;
620 sib0        = etree0->tree->sib ;
621 nodwghts0   = IV_entries(etree0->nodwghtsIV) ;
622 bndwghts0   = IV_entries(etree0->bndwghtsIV) ;
623 vtxToFront0 = IV_entries(etree0->vtxToFrontIV) ;
624 nfront1     = etree1->nfront ;
625 par1        = etree1->tree->par ;
626 bndwghts1   = IV_entries(etree1->bndwghtsIV) ;
627 nodwghts1   = IV_entries(etree1->nodwghtsIV) ;
628 vtxToFront1 = IV_entries(etree1->vtxToFrontIV) ;
629 map         = IV_entries(mapIV) ;
630 /*
631    -------------------------
632    create the new front tree
633    -------------------------
634 */
635 nfront2 = nfront0 + nfront1 ;
636 etree2 = ETree_new() ;
637 ETree_init1(etree2, nfront2, etree0->nvtx) ;
638 par2        = etree2->tree->par ;
639 nodwghts2   = IV_entries(etree2->nodwghtsIV) ;
640 bndwghts2   = IV_entries(etree2->bndwghtsIV) ;
641 vtxToFront2 = IV_entries(etree2->vtxToFrontIV) ;
642 /*
643    --------------------------------------------------
644    fill the parent fields for fronts in the same tree
645    --------------------------------------------------
646 */
647 for ( J = 0 ; J < nfront0 ; J++ ) {
648    par2[J]      = par0[J] ;
649    nodwghts2[J] = nodwghts0[J] ;
650    bndwghts2[J] = bndwghts0[J] ;
651 }
652 for ( J = 0 ; J < nfront1 ; J++ ) {
653    par2[J+nfront0]      = nfront0 + par1[J] ;
654    nodwghts2[J+nfront0] = nodwghts1[J] ;
655    bndwghts2[J+nfront0] = bndwghts1[J] ;
656 }
657 /*
658    ---------------------------
659    set the vertex to front map
660    ---------------------------
661 */
662 for ( v = 0 ; v < nvtx ; v++ ) {
663    if ( (J = vtxToFront0[v]) >= 0 ) {
664       vtxToFront2[v] = J ;
665    } else {
666       vtxToFront2[v] = vtxToFront1[map[v]] + nfront0 ;
667    }
668 }
669 /*
670    ---------------------------------------------
671    link the vertices to fronts in the lower tree
672    ---------------------------------------------
673 */
674 head0 = IVinit(nfront0, -1) ;
675 link0 = IVinit(nvtx,    -1) ;
676 for ( v = 0 ; v < nvtx ; v++ ) {
677    if ( (J = vtxToFront0[v]) >= 0 ) {
678       link0[v] = head0[J] ;
679       head0[J] = v ;
680    }
681 }
682 /*
683    -------------------------------------------------------
684    link roots of the lower tree to nodes in the upper tree
685    -------------------------------------------------------
686 */
687 mark = IVinit(nvtx, -1) ;
688 for ( J = etree0->tree->root ; J != -1 ; J = sib0[J] ) {
689 /*
690    ---------------------------------------
691    K is the parent front in the upper tree
692    ---------------------------------------
693 */
694    K = nfront1 ;
695 /*
696    ---------------------------------------
697    loop over vertices in the lower front J
698    ---------------------------------------
699 */
700    for ( v = head0[J] ; v != -1 ; v = link0[v] ) {
701       Graph_adjAndSize(graph0, v, &vsize, &vadj) ;
702       for ( ii = 0 ; ii < vsize ; ii++ ) {
703          w = vadj[ii] ;
704          if ( vtxToFront0[w] < 0 ) {
705             phi = map[w] ;
706 /*
707             ---------------------------------------------------
708             w is a vertex that belongs to phi in the upper tree
709             ---------------------------------------------------
710 */
711             if ( mark[phi] != J ) {
712                mark[phi] = J ;
713                if ( K > vtxToFront1[phi] ) {
714 /*
715                   ------------------------------------
716                   least numbered adjacent front so far
717                   ------------------------------------
718 */
719                   K = vtxToFront1[phi] ;
720                }
721             }
722          }
723       }
724    }
725    if ( K < nfront1 ) {
726    /*
727       --------------------
728       set the parent field
729       --------------------
730    */
731       par2[J] = nfront0 + K ;
732    }
733 }
734 /*
735    -----------------------------
736    set the remaining tree fields
737    -----------------------------
738 */
739 Tree_setFchSibRoot(etree2->tree) ;
740 /*
741    ------------------------
742    free the working storage
743    ------------------------
744 */
745 IVfree(head0) ;
746 IVfree(link0) ;
747 IVfree(mark)  ;
748 
749 return(etree2) ; }
750 
751 /*--------------------------------------------------------------------*/
752