1 /*!
2 \file
3 \brief Functions that deal with prunning the number of adjacent subdomains in kmetis
4
5 \date Started 7/15/98
6 \author George
7 \author Copyright 1997-2009, Regents of the University of Minnesota
8 \version $Id: minconn.c 10513 2011-07-07 22:06:03Z karypis $
9 */
10
11 #include "metislib.h"
12
13
14 /*************************************************************************/
15 /*! This function computes the subdomain graph storing the result in the
16 pre-allocated worspace arrays */
17 /*************************************************************************/
ComputeSubDomainGraph(ctrl_t * ctrl,graph_t * graph)18 void ComputeSubDomainGraph(ctrl_t *ctrl, graph_t *graph)
19 {
20 idx_t i, ii, j, pid, other, nparts, nvtxs, nnbrs;
21 idx_t *xadj, *adjncy, *adjwgt, *where;
22 idx_t *pptr, *pind;
23 idx_t nads=0, *vadids, *vadwgts;
24
25 WCOREPUSH;
26
27 nvtxs = graph->nvtxs;
28 xadj = graph->xadj;
29 adjncy = graph->adjncy;
30 adjwgt = graph->adjwgt;
31 where = graph->where;
32
33 nparts = ctrl->nparts;
34
35 vadids = ctrl->pvec1;
36 vadwgts = iset(nparts, 0, ctrl->pvec2);
37
38 pptr = iwspacemalloc(ctrl, nparts+1);
39 pind = iwspacemalloc(ctrl, nvtxs);
40 iarray2csr(nvtxs, nparts, where, pptr, pind);
41
42 for (pid=0; pid<nparts; pid++) {
43 switch (ctrl->objtype) {
44 case METIS_OBJTYPE_CUT:
45 {
46 ckrinfo_t *rinfo;
47 cnbr_t *nbrs;
48
49 rinfo = graph->ckrinfo;
50 for (nads=0, ii=pptr[pid]; ii<pptr[pid+1]; ii++) {
51 i = pind[ii];
52 ASSERT(pid == where[i]);
53
54 if (rinfo[i].ed > 0) {
55 nnbrs = rinfo[i].nnbrs;
56 nbrs = ctrl->cnbrpool + rinfo[i].inbr;
57
58 for (j=0; j<nnbrs; j++) {
59 other = nbrs[j].pid;
60 if (vadwgts[other] == 0)
61 vadids[nads++] = other;
62 vadwgts[other] += nbrs[j].ed;
63 }
64 }
65 }
66 }
67 break;
68
69 case METIS_OBJTYPE_VOL:
70 {
71 vkrinfo_t *rinfo;
72 vnbr_t *nbrs;
73
74 rinfo = graph->vkrinfo;
75 for (nads=0, ii=pptr[pid]; ii<pptr[pid+1]; ii++) {
76 i = pind[ii];
77 ASSERT(pid == where[i]);
78
79 if (rinfo[i].ned > 0) {
80 nnbrs = rinfo[i].nnbrs;
81 nbrs = ctrl->vnbrpool + rinfo[i].inbr;
82
83 for (j=0; j<nnbrs; j++) {
84 other = nbrs[j].pid;
85 if (vadwgts[other] == 0)
86 vadids[nads++] = other;
87 vadwgts[other] += nbrs[j].ned;
88 }
89 }
90 }
91 }
92 break;
93
94 default:
95 gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype);
96 }
97
98 /* See if you have enough memory to store the adjacent info for that subdomain */
99 if (ctrl->maxnads[pid] < nads) {
100 ctrl->maxnads[pid] = 2*nads;
101 ctrl->adids[pid] = irealloc(ctrl->adids[pid], ctrl->maxnads[pid],
102 "ComputeSubDomainGraph: adids[pid]");
103 ctrl->adwgts[pid] = irealloc(ctrl->adwgts[pid], ctrl->maxnads[pid],
104 "ComputeSubDomainGraph: adids[pid]");
105 }
106
107 ctrl->nads[pid] = nads;
108 for (j=0; j<nads; j++) {
109 ctrl->adids[pid][j] = vadids[j];
110 ctrl->adwgts[pid][j] = vadwgts[vadids[j]];
111
112 vadwgts[vadids[j]] = 0;
113 }
114 }
115
116 WCOREPOP;
117 }
118
119
120 /*************************************************************************/
121 /*! This function updates the weight of an edge in the subdomain graph by
122 adding to it the value of ewgt. The update can either increase or
123 decrease the weight of the subdomain edge based on the value of ewgt.
124
125 \param u is the ID of one of the incident subdomains to the edge
126 \param v is the ID of the other incident subdomains to the edge
127 \param ewgt is the weight to be added to the subdomain edge
128 \param nparts is the number of subdomains
129 \param r_maxndoms is the maximum number of adjacent subdomains and is
130 updated as necessary. The update is skipped if a NULL value is
131 supplied.
132 */
133 /*************************************************************************/
UpdateEdgeSubDomainGraph(ctrl_t * ctrl,idx_t u,idx_t v,idx_t ewgt,idx_t * r_maxndoms)134 void UpdateEdgeSubDomainGraph(ctrl_t *ctrl, idx_t u, idx_t v, idx_t ewgt,
135 idx_t *r_maxndoms)
136 {
137 idx_t i, j, nads;
138
139 if (ewgt == 0)
140 return;
141
142 for (i=0; i<2; i++) {
143 nads = ctrl->nads[u];
144 /* Find the edge */
145 for (j=0; j<nads; j++) {
146 if (ctrl->adids[u][j] == v) {
147 ctrl->adwgts[u][j] += ewgt;
148 break;
149 }
150 }
151
152 if (j == nads) {
153 /* Deal with the case in which the edge was not found */
154 ASSERT(ewgt > 0);
155 if (ctrl->maxnads[u] == nads) {
156 ctrl->maxnads[u] = 2*(nads+1);
157 ctrl->adids[u] = irealloc(ctrl->adids[u], ctrl->maxnads[u],
158 "IncreaseEdgeSubDomainGraph: adids[pid]");
159 ctrl->adwgts[u] = irealloc(ctrl->adwgts[u], ctrl->maxnads[u],
160 "IncreaseEdgeSubDomainGraph: adids[pid]");
161 }
162 ctrl->adids[u][nads] = v;
163 ctrl->adwgts[u][nads] = ewgt;
164 nads++;
165 if (r_maxndoms != NULL && nads > *r_maxndoms) {
166 printf("You just increased the maxndoms: %"PRIDX" %"PRIDX"\n",
167 nads, *r_maxndoms);
168 *r_maxndoms = nads;
169 }
170 }
171 else {
172 /* See if the updated edge becomes 0 */
173 ASSERT(ctrl->adwgts[u][j] >= 0);
174 if (ctrl->adwgts[u][j] == 0) {
175 ctrl->adids[u][j] = ctrl->adids[u][nads-1];
176 ctrl->adwgts[u][j] = ctrl->adwgts[u][nads-1];
177 nads--;
178 if (r_maxndoms != NULL && nads+1 == *r_maxndoms)
179 *r_maxndoms = ctrl->nads[iargmax(ctrl->nparts, ctrl->nads)];
180 }
181 }
182 ctrl->nads[u] = nads;
183
184 SWAP(u, v, j);
185 }
186 }
187
188
189 /*************************************************************************/
190 /*! This function computes the subdomain graph */
191 /*************************************************************************/
EliminateSubDomainEdges(ctrl_t * ctrl,graph_t * graph)192 void EliminateSubDomainEdges(ctrl_t *ctrl, graph_t *graph)
193 {
194 idx_t i, ii, j, k, ncon, nparts, scheme, pid_from, pid_to, me, other, nvtxs,
195 total, max, avg, totalout, nind=0, ncand=0, ncand2, target, target2,
196 nadd, bestnadd=0;
197 idx_t min, move, *cpwgt;
198 idx_t *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt,
199 *mypmat, *otherpmat, *kpmat, *ind;
200 idx_t *nads, **adids, **adwgts;
201 ikv_t *cand, *cand2;
202 ipq_t queue;
203 real_t *tpwgts, badfactor=1.4;
204 idx_t *pptr, *pind;
205 idx_t *vmarker=NULL, *pmarker=NULL, *modind=NULL; /* volume specific work arrays */
206
207 WCOREPUSH;
208
209 nvtxs = graph->nvtxs;
210 ncon = graph->ncon;
211 xadj = graph->xadj;
212 adjncy = graph->adjncy;
213 vwgt = graph->vwgt;
214 adjwgt = (ctrl->objtype == METIS_OBJTYPE_VOL ? NULL : graph->adjwgt);
215
216 where = graph->where;
217 pwgts = graph->pwgts; /* We assume that this is properly initialized */
218
219 nparts = ctrl->nparts;
220 tpwgts = ctrl->tpwgts;
221
222 cpwgt = iwspacemalloc(ctrl, ncon);
223 maxpwgt = iwspacemalloc(ctrl, nparts*ncon);
224 ind = iwspacemalloc(ctrl, nvtxs);
225 otherpmat = iset(nparts, 0, iwspacemalloc(ctrl, nparts));
226
227 cand = ikvwspacemalloc(ctrl, nparts);
228 cand2 = ikvwspacemalloc(ctrl, nparts);
229
230 pptr = iwspacemalloc(ctrl, nparts+1);
231 pind = iwspacemalloc(ctrl, nvtxs);
232 iarray2csr(nvtxs, nparts, where, pptr, pind);
233
234 if (ctrl->objtype == METIS_OBJTYPE_VOL) {
235 /* Vol-refinement specific working arrays */
236 modind = iwspacemalloc(ctrl, nvtxs);
237 vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
238 pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
239 }
240
241
242 /* Compute the pmat matrix and ndoms */
243 ComputeSubDomainGraph(ctrl, graph);
244
245 nads = ctrl->nads;
246 adids = ctrl->adids;
247 adwgts = ctrl->adwgts;
248
249 mypmat = iset(nparts, 0, ctrl->pvec1);
250 kpmat = iset(nparts, 0, ctrl->pvec2);
251
252 /* Compute the maximum allowed weight for each domain */
253 for (i=0; i<nparts; i++) {
254 for (j=0; j<ncon; j++)
255 maxpwgt[i*ncon+j] =
256 (ncon == 1 ? 1.25 : 1.025)*tpwgts[i]*graph->tvwgt[j]*ctrl->ubfactors[j];
257 }
258
259 ipqInit(&queue, nparts);
260
261 /* Get into the loop eliminating subdomain connections */
262 while (1) {
263 total = isum(nparts, nads, 1);
264 avg = total/nparts;
265 max = nads[iargmax(nparts, nads)];
266
267 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
268 printf("Adjacent Subdomain Stats: Total: %3"PRIDX", "
269 "Max: %3"PRIDX"[%zu], Avg: %3"PRIDX"\n",
270 total, max, iargmax(nparts, nads), avg));
271
272 if (max < badfactor*avg)
273 break;
274
275 /* Add the subdomains that you will try to reduce their connectivity */
276 ipqReset(&queue);
277 for (i=0; i<nparts; i++) {
278 if (nads[i] >= avg + (max-avg)/2)
279 ipqInsert(&queue, i, nads[i]);
280 }
281
282 move = 0;
283 while ((me = ipqGetTop(&queue)) != -1) {
284 totalout = isum(nads[me], adwgts[me], 1);
285
286 for (ncand2=0, i=0; i<nads[me]; i++) {
287 mypmat[adids[me][i]] = adwgts[me][i];
288
289 /* keep track of the weakly connected adjacent subdomains */
290 if (2*nads[me]*adwgts[me][i] < totalout) {
291 cand2[ncand2].val = adids[me][i];
292 cand2[ncand2++].key = adwgts[me][i];
293 }
294 }
295
296 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
297 printf("Me: %"PRIDX", Degree: %4"PRIDX", TotalOut: %"PRIDX",\n",
298 me, nads[me], totalout));
299
300 /* Sort the connections according to their cut */
301 ikvsorti(ncand2, cand2);
302
303 /* Two schemes are used for eliminating subdomain edges.
304 The first, tries to eliminate subdomain edges by moving remote groups
305 of vertices to subdomains that 'me' is already connected to.
306 The second, tries to eliminate subdomain edges by moving entire sets of
307 my vertices that connect to the 'other' subdomain to a subdomain that
308 I'm already connected to.
309 These two schemes are applied in sequence. */
310 target = target2 = -1;
311 for (scheme=0; scheme<2; scheme++) {
312 for (min=0; min<ncand2; min++) {
313 other = cand2[min].val;
314
315 /* pid_from is the subdomain from where the vertices will be removed.
316 pid_to is the adjacent subdomain to pid_from that defines the
317 (me, other) subdomain edge that needs to be removed */
318 if (scheme == 0) {
319 pid_from = other;
320 pid_to = me;
321 }
322 else {
323 pid_from = me;
324 pid_to = other;
325 }
326
327 /* Go and find the vertices in 'other' that are connected in 'me' */
328 for (nind=0, ii=pptr[pid_from]; ii<pptr[pid_from+1]; ii++) {
329 i = pind[ii];
330 ASSERT(where[i] == pid_from);
331 for (j=xadj[i]; j<xadj[i+1]; j++) {
332 if (where[adjncy[j]] == pid_to) {
333 ind[nind++] = i;
334 break;
335 }
336 }
337 }
338
339 /* Go and construct the otherpmat to see where these nind vertices are
340 connected to */
341 iset(ncon, 0, cpwgt);
342 for (ncand=0, ii=0; ii<nind; ii++) {
343 i = ind[ii];
344 iaxpy(ncon, 1, vwgt+i*ncon, 1, cpwgt, 1);
345
346 for (j=xadj[i]; j<xadj[i+1]; j++) {
347 if ((k = where[adjncy[j]]) == pid_from)
348 continue;
349 if (otherpmat[k] == 0)
350 cand[ncand++].val = k;
351 otherpmat[k] += (adjwgt ? adjwgt[j] : 1);
352 }
353 }
354
355 for (i=0; i<ncand; i++) {
356 cand[i].key = otherpmat[cand[i].val];
357 ASSERT(cand[i].key > 0);
358 }
359
360 ikvsortd(ncand, cand);
361
362 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
363 printf("\tMinOut: %4"PRIDX", to: %3"PRIDX", TtlWgt: %5"PRIDX"[#:%"PRIDX"]\n",
364 mypmat[other], other, isum(ncon, cpwgt, 1), nind));
365
366 /* Go through and select the first domain that is common with 'me', and does
367 not increase the nads[target] higher than nads[me], subject to the maxpwgt
368 constraint. Traversal is done from the mostly connected to the least. */
369 for (i=0; i<ncand; i++) {
370 k = cand[i].val;
371
372 if (mypmat[k] > 0) {
373 /* Check if balance will go off */
374 if (!ivecaxpylez(ncon, 1, cpwgt, pwgts+k*ncon, maxpwgt+k*ncon))
375 continue;
376
377 /* get a dense vector out of k's connectivity */
378 for (j=0; j<nads[k]; j++)
379 kpmat[adids[k][j]] = adwgts[k][j];
380
381 /* Check if the move to domain k will increase the nads of another
382 subdomain j that the set of vertices being moved are connected
383 to but domain k is not connected to. */
384 for (j=0; j<nparts; j++) {
385 if (otherpmat[j] > 0 && kpmat[j] == 0 && nads[j]+1 >= nads[me])
386 break;
387 }
388
389 /* There were no bad second level effects. See if you can find a
390 subdomain to move to. */
391 if (j == nparts) {
392 for (nadd=0, j=0; j<nparts; j++) {
393 if (otherpmat[j] > 0 && kpmat[j] == 0)
394 nadd++;
395 }
396
397 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
398 printf("\t\tto=%"PRIDX", nadd=%"PRIDX", %"PRIDX"\n", k, nadd, nads[k]));
399
400 if (nads[k]+nadd < nads[me]) {
401 if (target2 == -1 || nads[target2]+bestnadd > nads[k]+nadd ||
402 (nads[target2]+bestnadd == nads[k]+nadd && bestnadd > nadd)) {
403 target2 = k;
404 bestnadd = nadd;
405 }
406 }
407
408 if (nadd == 0)
409 target = k;
410 }
411
412 /* reset kpmat for the next iteration */
413 for (j=0; j<nads[k]; j++)
414 kpmat[adids[k][j]] = 0;
415 }
416
417 if (target != -1)
418 break;
419 }
420
421 /* reset the otherpmat for the next iteration */
422 for (i=0; i<ncand; i++)
423 otherpmat[cand[i].val] = 0;
424
425 if (target == -1 && target2 != -1)
426 target = target2;
427
428 if (target != -1) {
429 IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO,
430 printf("\t\tScheme: %"PRIDX". Moving to %"PRIDX"\n", scheme, target));
431 move = 1;
432 break;
433 }
434 }
435
436 if (target != -1)
437 break; /* A move was found. No need to try the other scheme */
438 }
439
440 /* reset the mypmat for next iteration */
441 for (i=0; i<nads[me]; i++)
442 mypmat[adids[me][i]] = 0;
443
444 /* Note that once a target is found the above loops exit right away. So the
445 following variables are valid */
446 if (target != -1) {
447 switch (ctrl->objtype) {
448 case METIS_OBJTYPE_CUT:
449 MoveGroupMinConnForCut(ctrl, graph, target, nind, ind);
450 break;
451 case METIS_OBJTYPE_VOL:
452 MoveGroupMinConnForVol(ctrl, graph, target, nind, ind, vmarker,
453 pmarker, modind);
454 break;
455 default:
456 gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);
457 }
458
459 /* Update the csr representation of the partitioning vector */
460 iarray2csr(nvtxs, nparts, where, pptr, pind);
461 }
462 }
463
464 if (move == 0)
465 break;
466 }
467
468 ipqFree(&queue);
469
470 WCOREPOP;
471 }
472
473
474 /*************************************************************************/
475 /*! This function moves a collection of vertices and updates their rinfo */
476 /*************************************************************************/
MoveGroupMinConnForCut(ctrl_t * ctrl,graph_t * graph,idx_t to,idx_t nind,idx_t * ind)477 void MoveGroupMinConnForCut(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t nind,
478 idx_t *ind)
479 {
480 idx_t i, ii, j, jj, k, l, nvtxs, nbnd, from, me;
481 idx_t *xadj, *adjncy, *adjwgt, *where, *bndptr, *bndind;
482 ckrinfo_t *myrinfo;
483 cnbr_t *mynbrs;
484
485 nvtxs = graph->nvtxs;
486 xadj = graph->xadj;
487 adjncy = graph->adjncy;
488 adjwgt = graph->adjwgt;
489
490 where = graph->where;
491 bndptr = graph->bndptr;
492 bndind = graph->bndind;
493
494 nbnd = graph->nbnd;
495
496 while (--nind>=0) {
497 i = ind[nind];
498 from = where[i];
499
500 myrinfo = graph->ckrinfo+i;
501 if (myrinfo->inbr == -1) {
502 myrinfo->inbr = cnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
503 myrinfo->nnbrs = 0;
504 }
505 mynbrs = ctrl->cnbrpool + myrinfo->inbr;
506
507 /* find the location of 'to' in myrinfo or create it if it is not there */
508 for (k=0; k<myrinfo->nnbrs; k++) {
509 if (mynbrs[k].pid == to)
510 break;
511 }
512 if (k == myrinfo->nnbrs) {
513 ASSERT(k < xadj[i+1]-xadj[i]);
514 mynbrs[k].pid = to;
515 mynbrs[k].ed = 0;
516 myrinfo->nnbrs++;
517 }
518
519 /* Update pwgts */
520 iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
521 iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
522
523 /* Update mincut */
524 graph->mincut -= mynbrs[k].ed-myrinfo->id;
525
526 /* Update subdomain connectivity graph to reflect the move of 'i' */
527 UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, NULL);
528
529 /* Update ID/ED and BND related information for the moved vertex */
530 UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd,
531 bndptr, bndind, BNDTYPE_REFINE);
532
533 /* Update the degrees of adjacent vertices */
534 for (j=xadj[i]; j<xadj[i+1]; j++) {
535 ii = adjncy[j];
536 me = where[ii];
537 myrinfo = graph->ckrinfo+ii;
538
539 UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
540 from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, BNDTYPE_REFINE);
541
542 /* Update subdomain graph to reflect the move of 'i' for domains other
543 than 'from' and 'to' */
544 if (me != from && me != to) {
545 UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], NULL);
546 UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], NULL);
547 }
548 }
549 }
550
551 ASSERT(ComputeCut(graph, where) == graph->mincut);
552
553 graph->nbnd = nbnd;
554
555 }
556
557
558 /*************************************************************************/
559 /*! This function moves a collection of vertices and updates their rinfo */
560 /*************************************************************************/
MoveGroupMinConnForVol(ctrl_t * ctrl,graph_t * graph,idx_t to,idx_t nind,idx_t * ind,idx_t * vmarker,idx_t * pmarker,idx_t * modind)561 void MoveGroupMinConnForVol(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t nind,
562 idx_t *ind, idx_t *vmarker, idx_t *pmarker, idx_t *modind)
563 {
564 idx_t i, ii, j, jj, k, l, nvtxs, from, me, other, xgain, ewgt;
565 idx_t *xadj, *vsize, *adjncy, *where;
566 vkrinfo_t *myrinfo, *orinfo;
567 vnbr_t *mynbrs, *onbrs;
568
569 nvtxs = graph->nvtxs;
570 xadj = graph->xadj;
571 vsize = graph->vsize;
572 adjncy = graph->adjncy;
573 where = graph->where;
574
575 while (--nind>=0) {
576 i = ind[nind];
577 from = where[i];
578
579 myrinfo = graph->vkrinfo+i;
580 if (myrinfo->inbr == -1) {
581 myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
582 myrinfo->nnbrs = 0;
583 }
584 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
585
586 xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? vsize[i] : 0);
587
588 //printf("Moving %"PRIDX" from %"PRIDX" to %"PRIDX" [vsize: %"PRIDX"] [xgain: %"PRIDX"]\n",
589 // i, from, to, vsize[i], xgain);
590
591 /* find the location of 'to' in myrinfo or create it if it is not there */
592 for (k=0; k<myrinfo->nnbrs; k++) {
593 if (mynbrs[k].pid == to)
594 break;
595 }
596
597 if (k == myrinfo->nnbrs) {
598 //printf("Missing neighbor\n");
599
600 if (myrinfo->nid > 0)
601 xgain -= vsize[i];
602
603 /* determine the volume gain resulting from that move */
604 for (j=xadj[i]; j<xadj[i+1]; j++) {
605 ii = adjncy[j];
606 other = where[ii];
607 orinfo = graph->vkrinfo+ii;
608 onbrs = ctrl->vnbrpool + orinfo->inbr;
609 ASSERT(other != to)
610
611 //printf(" %8d %8d %3d\n", (int)ii, (int)vsize[ii], (int)other);
612
613 if (from == other) {
614 /* Same subdomain vertex: Decrease the gain if 'to' is a new neighbor. */
615 for (l=0; l<orinfo->nnbrs; l++) {
616 if (onbrs[l].pid == to)
617 break;
618 }
619 if (l == orinfo->nnbrs)
620 xgain -= vsize[ii];
621 }
622 else {
623 /* Remote vertex: increase if 'to' is a new subdomain */
624 for (l=0; l<orinfo->nnbrs; l++) {
625 if (onbrs[l].pid == to)
626 break;
627 }
628 if (l == orinfo->nnbrs)
629 xgain -= vsize[ii];
630
631 /* Remote vertex: decrease if i is the only connection to 'from' */
632 for (l=0; l<orinfo->nnbrs; l++) {
633 if (onbrs[l].pid == from && onbrs[l].ned == 1) {
634 xgain += vsize[ii];
635 break;
636 }
637 }
638 }
639 }
640 graph->minvol -= xgain;
641 graph->mincut -= -myrinfo->nid;
642 ewgt = myrinfo->nid;
643 }
644 else {
645 graph->minvol -= (xgain + mynbrs[k].gv);
646 graph->mincut -= mynbrs[k].ned-myrinfo->nid;
647 ewgt = myrinfo->nid-mynbrs[k].ned;
648 }
649
650 /* Update where and pwgts */
651 where[i] = to;
652 iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
653 iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
654
655 /* Update subdomain connectivity graph to reflect the move of 'i' */
656 UpdateEdgeSubDomainGraph(ctrl, from, to, ewgt, NULL);
657
658 /* Update the subdomain connectivity of the adjacent vertices */
659 for (j=xadj[i]; j<xadj[i+1]; j++) {
660 me = where[adjncy[j]];
661 if (me != from && me != to) {
662 UpdateEdgeSubDomainGraph(ctrl, from, me, -1, NULL);
663 UpdateEdgeSubDomainGraph(ctrl, to, me, 1, NULL);
664 }
665 }
666
667 /* Update the id/ed/gains/bnd of potentially affected nodes */
668 KWayVolUpdate(ctrl, graph, i, from, to, NULL, NULL, NULL, NULL,
669 NULL, BNDTYPE_REFINE, vmarker, pmarker, modind);
670
671 /*CheckKWayVolPartitionParams(ctrl, graph);*/
672 }
673 ASSERT(ComputeCut(graph, where) == graph->mincut);
674 ASSERTP(ComputeVolume(graph, where) == graph->minvol,
675 ("%"PRIDX" %"PRIDX"\n", ComputeVolume(graph, where), graph->minvol));
676
677 }
678
679
680 /*************************************************************************/
681 /*! This function computes the subdomain graph. For deubuging purposes. */
682 /*************************************************************************/
PrintSubDomainGraph(graph_t * graph,idx_t nparts,idx_t * where)683 void PrintSubDomainGraph(graph_t *graph, idx_t nparts, idx_t *where)
684 {
685 idx_t i, j, k, me, nvtxs, total, max;
686 idx_t *xadj, *adjncy, *adjwgt, *pmat;
687
688 nvtxs = graph->nvtxs;
689 xadj = graph->xadj;
690 adjncy = graph->adjncy;
691 adjwgt = graph->adjwgt;
692
693 pmat = ismalloc(nparts*nparts, 0, "ComputeSubDomainGraph: pmat");
694
695 for (i=0; i<nvtxs; i++) {
696 me = where[i];
697 for (j=xadj[i]; j<xadj[i+1]; j++) {
698 k = adjncy[j];
699 if (where[k] != me)
700 pmat[me*nparts+where[k]] += adjwgt[j];
701 }
702 }
703
704 /* printf("Subdomain Info\n"); */
705 total = max = 0;
706 for (i=0; i<nparts; i++) {
707 for (k=0, j=0; j<nparts; j++) {
708 if (pmat[i*nparts+j] > 0)
709 k++;
710 }
711 total += k;
712
713 if (k > max)
714 max = k;
715 /*
716 printf("%2"PRIDX" -> %2"PRIDX" ", i, k);
717 for (j=0; j<nparts; j++) {
718 if (pmat[i*nparts+j] > 0)
719 printf("[%2"PRIDX" %4"PRIDX"] ", j, pmat[i*nparts+j]);
720 }
721 printf("\n");
722 */
723 }
724 printf("Total adjacent subdomains: %"PRIDX", Max: %"PRIDX"\n", total, max);
725
726 gk_free((void **)&pmat, LTERM);
727 }
728
729
730