1 /*  DDviaFishnet.c  */
2 
3 #include "../GPart.h"
4 #include "../../IIheap.h"
5 #include "../../timings.h"
6 
7 /*--------------------------------------------------------------------*/
8 /*
9    ---------------------------------
10    declarations for static functions
11    ---------------------------------
12 */
13 static int
14 GPart_freeze (
15    GPart    *gpart,
16    double   freeze,
17    int      extdegs[]
18 ) ;
19 static void
20 GPart_indpSetGrowth (
21    GPart   *gpart,
22    int     maxWeight,
23    int     seed
24 ) ;
25 static void
26 GPart_absDomains (
27    GPart   *gpart,
28    int     minweight
29 ) ;
30 static void
31 GPart_absBoundary (
32    GPart   *gpart
33 ) ;
34 /*--------------------------------------------------------------------*/
35 /*
36    ---------------------------------------------------------------
37    purpose -- to construct and return a multisector
38               using the fishnet algorithm
39 
40    freeze    -- parameter used to keep nodes of high degree
41                 in the interface
42    minweight -- minimum weight for a domain
43    maxweight -- maximum weight for a domain
44    seed      -- random number seed
45 
46    created -- 96feb16, cca
47    ---------------------------------------------------------------
48 */
49 void
GPart_DDviaFishnet(GPart * gpart,double freeze,int minweight,int maxweight,int seed)50 GPart_DDviaFishnet (
51    GPart    *gpart,
52    double   freeze,
53    int      minweight,
54    int      maxweight,
55    int      seed
56 ) {
57 double   cpus[6], t1, t2 ;
58 int      nV, v ;
59 int      *extdegs ;
60 /*
61    ---------------
62    check the input
63    ---------------
64 */
65 if (  gpart == NULL || freeze < 0.0
66    || minweight < 0 || maxweight < 0 || minweight >= maxweight ) {
67    fprintf(stderr,
68           "\n fatal error in GPart_DDviaFishnet(%p,%f,%d,%d,%d)"
69           "\n bad input\n", gpart, freeze, minweight, maxweight, seed) ;
70    exit(-1) ;
71 }
72 /*
73    ----------------------------
74    compute the external degrees
75    ----------------------------
76 */
77 MARKTIME(t1) ;
78 nV = gpart->g->nvtx ;
79 extdegs = IVinit(nV, 0) ;
80 for ( v = 0 ; v < nV ; v++ ) {
81    extdegs[v] = Graph_externalDegree(gpart->g, v) ;
82 }
83 MARKTIME(t2) ;
84 cpus[0] = t2 - t1 ;
85 /*
86    -------------------
87    freeze the vertices
88    -------------------
89 */
90 MARKTIME(t1) ;
91 GPart_freeze(gpart, freeze, extdegs) ;
92 MARKTIME(t2) ;
93 cpus[1] = t2 - t1 ;
94 /*
95    ---------------------------------------------
96    grow the partition via independent set growth
97    ---------------------------------------------
98 */
99 MARKTIME(t1) ;
100 GPart_indpSetGrowth(gpart, maxweight, seed) ;
101 IVfree(extdegs) ;
102 MARKTIME(t2) ;
103 cpus[2] = t2 - t1 ;
104 if ( gpart->ncomp == 1 ) {
105    IV_fill(&gpart->compidsIV, 1) ;
106    return ;
107 }
108 /*
109    ------------------------
110    absorb the small domains
111    ------------------------
112 */
113 MARKTIME(t1) ;
114 GPart_absDomains(gpart, minweight) ;
115 MARKTIME(t2) ;
116 cpus[3] = t2 - t1 ;
117 if ( gpart->ncomp <= 1 ) {
118    IV_fill(&gpart->compidsIV, 1) ;
119    return  ;
120 }
121 /*
122    --------------------------
123    absorb the excess boundary
124    --------------------------
125 */
126 MARKTIME(t1) ;
127 GPart_absBoundary(gpart) ;
128 MARKTIME(t2) ;
129 cpus[4] = t2 - t1 ;
130 
131 if ( gpart->msglvl > 1 ) {
132    fprintf(gpart->msgFile,
133            "\n FISHNET CPU breakdown"
134            "\n CPU %8.3f : compute external degrees"
135            "\n CPU %8.3f : freeze vertices of high degree"
136            "\n CPU %8.3f : independent set growth"
137            "\n CPU %8.3f : absorb small domains"
138            "\n CPU %8.3f : absorb excess boundary",
139            cpus[0], cpus[1], cpus[2], cpus[3], cpus[4]) ;
140 }
141 
142 return ; }
143 
144 /*--------------------------------------------------------------------*/
145 /*
146    ---------------------------------------
147    freeze vertices into the interface that
148    have external degree >= freeze * cutoff
149 
150    return value -- # of frozen vertices
151 
152    created -- 95oct05, cca
153    ---------------------------------------
154 */
155 static int
GPart_freeze(GPart * gpart,double freeze,int extdegs[])156 GPart_freeze (
157    GPart    *gpart,
158    double   freeze,
159    int      extdegs[]
160 ) {
161 Graph   *g ;
162 int     cutoff, iv, median, nfrozen, nvtx ;
163 int     *compids, *vids ;
164 /*
165    ---------------
166    check the input
167    ---------------
168 */
169 if ( gpart == NULL || (g = gpart->g) == NULL || extdegs == NULL ) {
170    fprintf(stderr, "\n fatal error in GPart_freeze(%p,%f,%p)"
171            "\n bad input\n", gpart, freeze, extdegs) ;
172    exit(-1) ;
173  }
174 nvtx = gpart->nvtx ;
175 compids = IV_entries(&gpart->compidsIV) ;
176 /*
177    -------------------------------------------------------
178    sort the vertices in ascending order of external degree
179    -------------------------------------------------------
180 */
181 vids = IVinit(nvtx, 0) ;
182 IVramp(nvtx, vids, 0, 1) ;
183 if ( gpart->msglvl > 3 ) {
184    int v ;
185    for ( v = 0 ; v < nvtx ; v++ ) {
186       fprintf(gpart->msgFile,
187               "\n vertex %d, external degree %d", v, extdegs[v]) ;
188       fflush(gpart->msgFile) ;
189    }
190 }
191 IV2qsortUp(nvtx, extdegs, vids) ;
192 /*
193    --------------------------------
194    get the median and cutoff values
195    --------------------------------
196 */
197 median = extdegs[nvtx/2] ;
198 cutoff = (int) (freeze * median) ;
199 if ( gpart->msglvl > 2 ) {
200    fprintf(gpart->msgFile, "\n median = %d, cutoff = %d", median, cutoff) ;
201    fflush(gpart->msgFile) ;
202 }
203 /*
204    -------------------------------------------------------
205    freeze vertices whose degree is greater than the cutoff
206    -------------------------------------------------------
207 */
208 nfrozen = 0 ;
209 for ( iv = nvtx - 1 ; iv >= 0 ; iv-- ) {
210    if ( extdegs[iv] < cutoff ) {
211       break ;
212    }
213    compids[vids[iv]] = 0 ;
214    nfrozen++ ;
215 }
216 /*
217    ------------------------
218    free the working storage
219    ------------------------
220 */
221 IVfree(vids)    ;
222 
223 return(nfrozen) ; }
224 
225 /*--------------------------------------------------------------------*/
226 /*
227    -------------------------------------------------------------------
228    set up the partition via independent set growth
229 
230    maxWeight -- maximum weight for any domain
231    seed      -- random number seed, if seed > 0 then
232                 the vertices are visited in some random order,
233                 else the vertices are visited 0, 1, ..., nvtx - 1
234 
235    note : the gpart->compids[] vector is assumed to be initialized
236           outside this method. any vertex v such that compids[v] == -1
237           is eligible to be put into a domain. this allows the user
238           to pre-specify vertices to be in the separator (by setting
239           compids[v] = -1 prior to calling this method), e.g.,
240           vertices of abnormally high degree should be forced to be
241           separator vertices.
242 
243 
244    created -- 95oct05, cca
245    -------------------------------------------------------------------
246 */
247 static void
GPart_indpSetGrowth(GPart * gpart,int maxWeight,int seed)248 GPart_indpSetGrowth (
249    GPart   *gpart,
250    int     maxWeight,
251    int     seed
252 ) {
253 Graph   *g ;
254 int     domweight, i, iv, last, ndom, now, nvtx, v, vsize, w ;
255 int     *compids, *cweights, *list, *vadj, *vids, *vwghts ;
256 /*
257    ---------------
258    check the input
259    ---------------
260 */
261 if ( gpart == NULL || (g = gpart->g) == NULL || maxWeight < 0 ) {
262    fprintf(stderr, "\n fatal error in GPart_indpSepGrowth(%p,%d,%d)"
263            "\n bad input\n", gpart, maxWeight, seed) ;
264    exit(-1) ;
265 }
266 vwghts = g->vwghts ;
267 /*
268    --------------------------------
269    set all component ids != 0 to -1
270    --------------------------------
271 */
272 nvtx    = gpart->nvtx ;
273 compids = IV_entries(&gpart->compidsIV) ;
274 for ( v = 0 ; v < nvtx ; v++ ) {
275    if ( compids[v] != 0 ) {
276       compids[v] = -1 ;
277    }
278 }
279 /*
280    -----------------------------------------------------------------
281    set up the vector that determines the order to visit the vertices
282    -----------------------------------------------------------------
283 */
284 vids = IVinit2(nvtx) ;
285 IVramp(nvtx, vids, 0, 1) ;
286 if ( seed > 0 ) {
287    IVshuffle(nvtx, vids, seed) ;
288 }
289 /*
290    ------------------------------
291    set up the working list vector
292    ------------------------------
293 */
294 list = IVinit(nvtx, -1) ;
295 /*
296    -----------------------------------
297    visit the vertices and grow domains
298    -----------------------------------
299 */
300 ndom = 0 ;
301 for ( iv = 0 ; iv < nvtx ; iv++ ) {
302    v = vids[iv] ;
303    if ( gpart->msglvl > 4 ) {
304       fprintf(gpart->msgFile, "\n\n visiting v = %d, compids[%d] = %d",
305               v, v, compids[v]) ;
306    }
307    if ( compids[v] == -1 ) {
308 /*
309       -----------------------------------------
310       eligible vertex has not yet been visited,
311       create a new domain with v as the seed
312       -----------------------------------------
313 */
314       ndom++ ;
315       if ( gpart->msglvl > 3 ) {
316          fprintf(gpart->msgFile,
317                  "\n\n domain %d : seed vertex %d", ndom, v) ;
318          fflush(gpart->msgFile) ;
319       }
320       domweight = 0 ;
321       now = last = 0 ;
322       list[0] = v ;
323       while ( now <= last ) {
324          v = list[now++] ;
325          if ( gpart->msglvl > 4 ) {
326             fprintf(gpart->msgFile,
327                     "\n    adding %d to domain %d, weight %d",
328                     v, ndom, ((vwghts != NULL) ? vwghts[v] : 1)) ;
329             fflush(gpart->msgFile) ;
330          }
331 /*
332          ---------------------
333          add v to domain icomp
334          ---------------------
335 */
336          compids[v] = ndom ;
337          domweight += (vwghts != NULL) ? vwghts[v] : 1 ;
338          Graph_adjAndSize(g, v, &vsize, &vadj) ;
339          for ( i = 0 ; i < vsize ; i++ ) {
340             if ( (w = vadj[i]) < nvtx && compids[w] == -1 ) {
341 /*
342                -----------------------------------------
343                w has not yet been touched, put on list
344                set compids[w] = -2 to make sure it isn't
345                put on the list twice
346                -----------------------------------------
347 */
348                compids[w]   = -2 ;
349                list[++last] =  w ;
350             }
351          }
352          if ( domweight >= maxWeight ) {
353 /*
354             ---------------------------------------------
355             domain is large enough, mark all the rest of
356             the vertices in the list as boundary vertices
357             ---------------------------------------------
358 */
359             while ( now <= last ) {
360                w = list[now++] ;
361                if ( gpart->msglvl > 4 ) {
362                   fprintf(gpart->msgFile,
363                           "\n    adding %d to interface, weight %d",
364                           w, ((vwghts != NULL) ? vwghts[w] : 1)) ;
365                   fflush(gpart->msgFile) ;
366                }
367                compids[w] = 0 ;
368             }
369          }
370       }
371       if ( gpart->msglvl > 2 ) {
372          fprintf(gpart->msgFile,
373                  "\n domain %d, weight %d", ndom, domweight) ;
374          fflush(gpart->msgFile) ;
375       }
376    }
377 }
378 /*
379    ---------------------------------------------------------------------
380    set the number of components and resize the component weights vector
381    ---------------------------------------------------------------------
382 */
383 gpart->ncomp = ndom ;
384 IV_setSize(&gpart->cweightsIV, 1 + ndom) ;
385 IV_fill(&gpart->cweightsIV, 0) ;
386 cweights = IV_entries(&gpart->cweightsIV) ;
387 /*
388    -----------------------------------------------
389    set the weights of the interface and components
390    -----------------------------------------------
391 */
392 if ( vwghts != NULL ) {
393    for ( v = 0 ; v < nvtx ; v++ ) {
394       cweights[compids[v]] += vwghts[v] ;
395    }
396 } else {
397    for ( v = 0 ; v < nvtx ; v++ ) {
398       cweights[compids[v]]++ ;
399    }
400 }
401 /*
402    -------------------------
403    free the two work vectors
404    -------------------------
405 */
406 IVfree(list) ;
407 IVfree(vids) ;
408 
409 return ; }
410 
411 /*--------------------------------------------------------------------*/
412 /*
413    ------------------------------------------------------------------
414    absorb small domains into the interface.
415    this method assumes that the component weights vector has been set
416 
417    95oct05, cca
418    ------------------------------------------------------------------
419 */
420 static void
GPart_absDomains(GPart * gpart,int minweight)421 GPart_absDomains (
422    GPart   *gpart,
423    int     minweight
424 ) {
425 Graph   *g ;
426 int     c, ierr, ndom, nnewdom, nvtx, v ;
427 int     *compids, *cweights, *dmap, *head, *link, *vwghts ;
428 /*
429    ---------------
430    check the input
431    ---------------
432 */
433 if ( gpart == NULL || (g = gpart->g) == NULL ) {
434    fprintf(stderr, "\n fatal error in GPart_absDomains(%p,%d)"
435            "\n bad input\n", gpart, minweight) ;
436    exit(-1) ;
437 }
438 nvtx     = gpart->nvtx  ;
439 vwghts   = g->vwghts    ;
440 ndom     = gpart->ncomp ;
441 compids  = IV_entries(&gpart->compidsIV)  ;
442 cweights = IV_entries(&gpart->cweightsIV) ;
443 /*
444    ----------------------------------------------
445    get the linked list for vertices and component
446    ----------------------------------------------
447 */
448 head = IVinit(ndom+1, -1) ;
449 link = IVinit(nvtx,   -1) ;
450 for ( v = 0 ; v < nvtx ; v++ ) {
451    c       = compids[v] ;
452    link[v] = head[c]    ;
453    head[c] = v          ;
454 }
455 dmap    = IVinit(ndom+1, -1) ;
456 nnewdom = 0 ;
457 dmap[0] = 0 ;
458 for ( c = 1 ; c <= ndom ; c++ ) {
459    if ( cweights[c] < minweight ) {
460       if ( gpart->msglvl > 2 ) {
461          fprintf(gpart->msgFile,
462                  "\n interface absorbs component %d, weight %d",
463                  c, cweights[c]) ;
464          fflush(gpart->msgFile) ;
465       }
466       for ( v = head[c] ; v != -1 ; v = link[v] ) {
467          compids[v] = 0 ;
468       }
469       cweights[0] += cweights[c] ;
470       cweights[c] =  0 ;
471       dmap[c]     =  0 ;
472    } else {
473       dmap[c] = ++nnewdom ;
474    }
475    if ( gpart->msglvl > 2 ) {
476       fprintf(gpart->msgFile, "\n dmap[%d] = %d", c, dmap[c]) ;
477       fflush(gpart->msgFile) ;
478    }
479 }
480 if ( nnewdom != ndom ) {
481 /*
482    ------------------------
483    set the new # of domains
484    ------------------------
485 */
486    gpart->ncomp = nnewdom ;
487 /*
488    -------------------------
489    set the new component ids
490    -------------------------
491 */
492    if ( gpart->msglvl > 3 ) {
493       fprintf(gpart->msgFile, "\n old component ids") ;
494       IVfp80(gpart->msgFile, nvtx, compids, 80, &ierr) ;
495       fflush(gpart->msgFile) ;
496    }
497    for ( v = 0 ; v < nvtx ; v++ ) {
498       c = compids[v] ;
499       compids[v] = dmap[c] ;
500    }
501    if ( gpart->msglvl > 3 ) {
502       fprintf(gpart->msgFile, "\n new component ids") ;
503       IVfp80(gpart->msgFile, nvtx, compids, 80, &ierr) ;
504       fflush(gpart->msgFile) ;
505    }
506 /*
507    -----------------------------
508    set the new component weights
509    -----------------------------
510 */
511    if ( gpart->msglvl > 2 ) {
512       fprintf(gpart->msgFile, "\n old cweights") ;
513       IVfp80(gpart->msgFile, ndom+1, cweights, 80, &ierr) ;
514       fflush(gpart->msgFile) ;
515    }
516    for ( c = 1 ; c <= ndom ; c++ ) {
517       if ( dmap[c] != 0 ) {
518          cweights[dmap[c]] = cweights[c] ;
519       }
520    }
521    IV_setSize(&gpart->cweightsIV, nnewdom) ;
522    if ( gpart->msglvl > 2 ) {
523       fprintf(gpart->msgFile, "\n new cweights") ;
524       IVfp80(gpart->msgFile, nnewdom+1, cweights, 80, &ierr) ;
525       fflush(gpart->msgFile) ;
526    }
527 }
528 /*
529    ------------------------
530    free the working storage
531    ------------------------
532 */
533 IVfree(head) ;
534 IVfree(link) ;
535 IVfree(dmap) ;
536 
537 return ; }
538 
539 /*--------------------------------------------------------------------*/
540 /*
541    ------------------------------------------------------------
542    absorb the excess boundary
543 
544    created -- 95oct05, cca
545    revised -- 95oct19, cca
546       very simple scheme
547    ------------------------------------------------------------
548 */
549 static void
GPart_absBoundary(GPart * gpart)550 GPart_absBoundary (
551    GPart   *gpart
552 ) {
553 Graph    *g ;
554 int      count, domid, ierr, ii, oldcount, ntest, nvtx, rc, v, vwght ;
555 int      *compids, *cweights, *list, *vwghts ;
556 /*
557    ---------------
558    check the input
559    ---------------
560 */
561 if ( gpart == NULL || (g = gpart->g) == NULL ) {
562    fprintf(stderr, "\n fatal error in GPart_absBoundary(%p)"
563            "\n bad input\n", gpart) ;
564    exit(-1) ;
565 }
566 nvtx     = gpart->nvtx ;
567 compids  = IV_entries(&gpart->compidsIV)  ;
568 cweights = IV_entries(&gpart->cweightsIV) ;
569 vwghts   = gpart->g->vwghts ;
570 /*
571    ----------------------
572    create working storage
573    ----------------------
574 */
575 list = IVinit(nvtx, -1) ;
576 /*
577    -----------------------------------------
578    load all interface vertices into the list
579    ------------------------------------------
580 */
581 count = 0 ;
582 for ( v = 0 ; v < nvtx ; v++ ) {
583    if ( compids[v] == 0 ) {
584       list[count++] = v ;
585    }
586 }
587 oldcount = -1 ;
588 while ( count > 0 ) {
589    if ( gpart->msglvl > 2 ) {
590       fprintf(gpart->msgFile, "\n\n new pass, count = %d", count) ;
591    }
592    ntest = count ;
593    count = 0 ;
594    for ( ii = 0 ; ii < ntest ; ii++ ) {
595       v = list[ii] ;
596       rc = GPart_vtxIsAdjToOneDomain(gpart, v, &domid) ;
597       if ( rc == 1 ) {
598 /*
599          -----------------------------------------
600          transfer interface vertex v into domain c
601          -----------------------------------------
602 */
603          compids[v] = domid ;
604          vwght = (vwghts != NULL) ? vwghts[v] : 1 ;
605          cweights[0]     -= vwght ;
606          cweights[domid] += vwght ;
607          if ( gpart->msglvl > 3 ) {
608             fprintf(gpart->msgFile,
609                  "\n    moving vertex %d with weight %d to domain %d"
610                  "\n    now, cweights[0] = %d, cweights[%d] = %d",
611                  v, vwght, domid, cweights[0], domid, cweights[domid]) ;
612             fflush(gpart->msgFile) ;
613          }
614       } else if ( domid == -1 ) {
615 /*
616          ----------------------------------------------------------
617          vertex v is still not adjacent to any domain, keep on list
618          ----------------------------------------------------------
619 */
620          if ( gpart->msglvl > 3 ) {
621             fprintf(gpart->msgFile,
622                     "\n    keeping vertex %d on list", v) ;
623          }
624          list[count++] = v ;
625       }
626    }
627    if ( count == oldcount ) {
628       break ;
629    } else {
630       oldcount = count ;
631    }
632 }
633 IVfree(list) ;
634 
635 return ; }
636 
637 /*--------------------------------------------------------------------*/
638