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