Bug #1267: Integrate METIS graph partitioning library
[charm.git] / src / libs / ck-libs / metis / libmetis / kwayfm.c
blobdedfd39098c40836f60f9b6ca3895e2293c89f29
1 /*!
2 \file
3 \brief Routines for k-way refinement
5 \date Started 7/28/97
6 \author George
7 \author Copyright 1997-2009, Regents of the University of Minnesota
8 \version $Id: kwayfm.c 10567 2011-07-13 16:17:07Z karypis $
9 */
11 #include "metislib.h"
15 /*************************************************************************/
16 /* Top-level routine for k-way partitioning refinement. This routine just
17 calls the appropriate refinement routine based on the objectives and
18 constraints. */
19 /*************************************************************************/
20 void Greedy_KWayOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,
21 real_t ffactor, idx_t omode)
23 switch (ctrl->objtype) {
24 case METIS_OBJTYPE_CUT:
25 if (graph->ncon == 1)
26 Greedy_KWayCutOptimize(ctrl, graph, niter, ffactor, omode);
27 else
28 Greedy_McKWayCutOptimize(ctrl, graph, niter, ffactor, omode);
29 break;
31 case METIS_OBJTYPE_VOL:
32 if (graph->ncon == 1)
33 Greedy_KWayVolOptimize(ctrl, graph, niter, ffactor, omode);
34 else
35 Greedy_McKWayVolOptimize(ctrl, graph, niter, ffactor, omode);
36 break;
38 default:
39 gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);
44 /*************************************************************************/
45 /*! K-way partitioning optimization in which the vertices are visited in
46 decreasing ed/sqrt(nnbrs)-id order. Note this is just an
47 approximation, as the ed is often split across different subdomains
48 and the sqrt(nnbrs) is just a crude approximation.
50 \param graph is the graph that is being refined.
51 \param niter is the number of refinement iterations.
52 \param ffactor is the \em fudge-factor for allowing positive gain moves
53 to violate the max-pwgt constraint.
54 \param omode is the type of optimization that will performed among
55 OMODE_REFINE and OMODE_BALANCE
59 /**************************************************************************/
60 void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,
61 real_t ffactor, idx_t omode)
63 /* Common variables to all types of kway-refinement/balancing routines */
64 idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain;
65 idx_t from, me, to, oldcut, vwgt;
66 idx_t *xadj, *adjncy, *adjwgt;
67 idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;
68 idx_t nmoved, nupd, *vstatus, *updptr, *updind;
69 idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;
70 idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;
71 idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);
73 /* Edgecut-specific/different variables */
74 idx_t nbnd, oldnnbrs;
75 rpq_t *queue;
76 real_t rgain;
77 ckrinfo_t *myrinfo;
78 cnbr_t *mynbrs;
80 WCOREPUSH;
82 /* Link the graph fields */
83 nvtxs = graph->nvtxs;
84 xadj = graph->xadj;
85 adjncy = graph->adjncy;
86 adjwgt = graph->adjwgt;
88 bndind = graph->bndind;
89 bndptr = graph->bndptr;
91 where = graph->where;
92 pwgts = graph->pwgts;
94 nparts = ctrl->nparts;
96 /* Setup the weight intervals of the various subdomains */
97 minwgt = iwspacemalloc(ctrl, nparts);
98 maxwgt = iwspacemalloc(ctrl, nparts);
99 itpwgts = iwspacemalloc(ctrl, nparts);
101 for (i=0; i<nparts; i++) {
102 itpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0];
103 maxwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0];
104 minwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]);
107 perm = iwspacemalloc(ctrl, nvtxs);
110 /* This stores the valid target subdomains. It is used when ctrl->minconn to
111 control the subdomains to which moves are allowed to be made.
112 When ctrl->minconn is false, the default values of 2 allow all moves to
113 go through and it does not interfere with the zero-gain move selection. */
114 safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));
116 if (ctrl->minconn) {
117 ComputeSubDomainGraph(ctrl, graph);
119 nads = ctrl->nads;
120 adids = ctrl->adids;
121 adwgts = ctrl->adwgts;
122 doms = iset(nparts, 0, ctrl->pvec1);
126 /* Setup updptr, updind like boundary info to keep track of the vertices whose
127 vstatus's need to be reset at the end of the inner iteration */
128 vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));
129 updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
130 updind = iwspacemalloc(ctrl, nvtxs);
132 if (ctrl->contig) {
133 /* The arrays that will be used for limited check of articulation points */
134 bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
135 bfsind = iwspacemalloc(ctrl, nvtxs);
136 bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
139 if (ctrl->dbglvl&METIS_DBG_REFINE) {
140 printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL","
141 " Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX,
142 (omode == OMODE_REFINE ? "GRC" : "GBC"),
143 pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), minwgt[0], maxwgt[0],
144 ComputeLoadImbalance(graph, nparts, ctrl->pijbm),
145 graph->nvtxs, graph->nbnd, graph->mincut);
146 if (ctrl->minconn)
147 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
148 printf("\n");
151 queue = rpqCreate(nvtxs);
153 /*=====================================================================
154 * The top-level refinement loop
155 *======================================================================*/
156 for (pass=0; pass<niter; pass++) {
157 ASSERT(ComputeCut(graph, where) == graph->mincut);
159 if (omode == OMODE_BALANCE) {
160 /* Check to see if things are out of balance, given the tolerance */
161 for (i=0; i<nparts; i++) {
162 if (pwgts[i] > maxwgt[i])
163 break;
165 if (i == nparts) /* Things are balanced. Return right away */
166 break;
169 oldcut = graph->mincut;
170 nbnd = graph->nbnd;
171 nupd = 0;
173 if (ctrl->minconn)
174 maxndoms = imax(nparts, nads);
176 /* Insert the boundary vertices in the priority queue */
177 irandArrayPermute(nbnd, perm, nbnd/4, 1);
178 for (ii=0; ii<nbnd; ii++) {
179 i = bndind[perm[ii]];
180 rgain = (graph->ckrinfo[i].nnbrs > 0 ?
181 1.0*graph->ckrinfo[i].ed/sqrt(graph->ckrinfo[i].nnbrs) : 0.0)
182 - graph->ckrinfo[i].id;
183 rpqInsert(queue, i, rgain);
184 vstatus[i] = VPQSTATUS_PRESENT;
185 ListInsert(nupd, updind, updptr, i);
188 /* Start extracting vertices from the queue and try to move them */
189 for (nmoved=0, iii=0;;iii++) {
190 if ((i = rpqGetTop(queue)) == -1)
191 break;
192 vstatus[i] = VPQSTATUS_EXTRACTED;
194 myrinfo = graph->ckrinfo+i;
195 mynbrs = ctrl->cnbrpool + myrinfo->inbr;
197 from = where[i];
198 vwgt = graph->vwgt[i];
200 /* Prevent moves that make 'from' domain underbalanced */
201 if (omode == OMODE_REFINE) {
202 if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
203 continue;
205 else { /* OMODE_BALANCE */
206 if (pwgts[from]-vwgt < minwgt[from])
207 continue;
210 if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))
211 continue;
213 if (ctrl->minconn)
214 SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);
216 /* Find the most promising subdomain to move to */
217 if (omode == OMODE_REFINE) {
218 for (k=myrinfo->nnbrs-1; k>=0; k--) {
219 if (!safetos[to=mynbrs[k].pid])
220 continue;
221 gain = mynbrs[k].ed-myrinfo->id;
222 if (gain >= 0 && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)
223 break;
225 if (k < 0)
226 continue; /* break out if you did not find a candidate */
228 for (j=k-1; j>=0; j--) {
229 if (!safetos[to=mynbrs[j].pid])
230 continue;
231 gain = mynbrs[j].ed-myrinfo->id;
232 if ((mynbrs[j].ed > mynbrs[k].ed && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)
234 (mynbrs[j].ed == mynbrs[k].ed &&
235 itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid]))
236 k = j;
239 to = mynbrs[k].pid;
241 gain = mynbrs[k].ed-myrinfo->id;
242 if (!(gain > 0
243 || (gain == 0
244 && (pwgts[from] >= maxwgt[from]
245 || itpwgts[to]*pwgts[from] > itpwgts[from]*(pwgts[to]+vwgt)
246 || (iii%2 == 0 && safetos[to] == 2)
251 continue;
253 else { /* OMODE_BALANCE */
254 for (k=myrinfo->nnbrs-1; k>=0; k--) {
255 if (!safetos[to=mynbrs[k].pid])
256 continue;
257 if (pwgts[to]+vwgt <= maxwgt[to] ||
258 itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
259 break;
261 if (k < 0)
262 continue; /* break out if you did not find a candidate */
264 for (j=k-1; j>=0; j--) {
265 if (!safetos[to=mynbrs[j].pid])
266 continue;
267 if (itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])
268 k = j;
271 to = mynbrs[k].pid;
273 if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&
274 mynbrs[k].ed-myrinfo->id < 0)
275 continue;
280 /*=====================================================================
281 * If we got here, we can now move the vertex from 'from' to 'to'
282 *======================================================================*/
283 graph->mincut -= mynbrs[k].ed-myrinfo->id;
284 nmoved++;
286 IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
287 printf("\t\tMoving %6"PRIDX" to %3"PRIDX". Gain: %4"PRIDX". Cut: %6"PRIDX"\n",
288 i, to, mynbrs[k].ed-myrinfo->id, graph->mincut));
290 /* Update the subdomain connectivity information */
291 if (ctrl->minconn) {
292 /* take care of i's move itself */
293 UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, &maxndoms);
295 /* take care of the adjancent vertices */
296 for (j=xadj[i]; j<xadj[i+1]; j++) {
297 me = where[adjncy[j]];
298 if (me != from && me != to) {
299 UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], &maxndoms);
300 UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], &maxndoms);
305 /* Update ID/ED and BND related information for the moved vertex */
306 INC_DEC(pwgts[to], pwgts[from], vwgt);
307 UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd,
308 bndptr, bndind, bndtype);
310 /* Update the degrees of adjacent vertices */
311 for (j=xadj[i]; j<xadj[i+1]; j++) {
312 ii = adjncy[j];
313 me = where[ii];
314 myrinfo = graph->ckrinfo+ii;
316 oldnnbrs = myrinfo->nnbrs;
318 UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
319 from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype);
321 UpdateQueueInfo(queue, vstatus, ii, me, from, to, myrinfo, oldnnbrs,
322 nupd, updptr, updind, bndtype);
324 ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]);
328 graph->nbnd = nbnd;
330 /* Reset the vstatus and associated data structures */
331 for (i=0; i<nupd; i++) {
332 ASSERT(updptr[updind[i]] != -1);
333 ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);
334 vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;
335 updptr[updind[i]] = -1;
338 if (ctrl->dbglvl&METIS_DBG_REFINE) {
339 printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."
340 " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,
341 pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts),
342 ComputeLoadImbalance(graph, nparts, ctrl->pijbm),
343 graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where));
344 if (ctrl->minconn)
345 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
346 printf("\n");
349 if (nmoved == 0 || (omode == OMODE_REFINE && graph->mincut == oldcut))
350 break;
353 rpqDestroy(queue);
355 WCOREPOP;
359 /*************************************************************************/
360 /*! K-way refinement that minimizes the communication volume. This is a
361 greedy routine and the vertices are visited in decreasing gv order.
363 \param graph is the graph that is being refined.
364 \param niter is the number of refinement iterations.
365 \param ffactor is the \em fudge-factor for allowing positive gain moves
366 to violate the max-pwgt constraint.
369 /**************************************************************************/
370 void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,
371 real_t ffactor, idx_t omode)
373 /* Common variables to all types of kway-refinement/balancing routines */
374 idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain;
375 idx_t from, me, to, oldcut, vwgt;
376 idx_t *xadj, *adjncy;
377 idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;
378 idx_t nmoved, nupd, *vstatus, *updptr, *updind;
379 idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;
380 idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;
381 idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);
383 /* Volume-specific/different variables */
384 ipq_t *queue;
385 idx_t oldvol, xgain;
386 idx_t *vmarker, *pmarker, *modind;
387 vkrinfo_t *myrinfo;
388 vnbr_t *mynbrs;
390 WCOREPUSH;
392 /* Link the graph fields */
393 nvtxs = graph->nvtxs;
394 xadj = graph->xadj;
395 adjncy = graph->adjncy;
396 bndptr = graph->bndptr;
397 bndind = graph->bndind;
398 where = graph->where;
399 pwgts = graph->pwgts;
401 nparts = ctrl->nparts;
403 /* Setup the weight intervals of the various subdomains */
404 minwgt = iwspacemalloc(ctrl, nparts);
405 maxwgt = iwspacemalloc(ctrl, nparts);
406 itpwgts = iwspacemalloc(ctrl, nparts);
408 for (i=0; i<nparts; i++) {
409 itpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0];
410 maxwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0];
411 minwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]);
414 perm = iwspacemalloc(ctrl, nvtxs);
417 /* This stores the valid target subdomains. It is used when ctrl->minconn to
418 control the subdomains to which moves are allowed to be made.
419 When ctrl->minconn is false, the default values of 2 allow all moves to
420 go through and it does not interfere with the zero-gain move selection. */
421 safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));
423 if (ctrl->minconn) {
424 ComputeSubDomainGraph(ctrl, graph);
426 nads = ctrl->nads;
427 adids = ctrl->adids;
428 adwgts = ctrl->adwgts;
429 doms = iset(nparts, 0, ctrl->pvec1);
433 /* Setup updptr, updind like boundary info to keep track of the vertices whose
434 vstatus's need to be reset at the end of the inner iteration */
435 vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));
436 updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
437 updind = iwspacemalloc(ctrl, nvtxs);
439 if (ctrl->contig) {
440 /* The arrays that will be used for limited check of articulation points */
441 bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
442 bfsind = iwspacemalloc(ctrl, nvtxs);
443 bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
446 /* Vol-refinement specific working arrays */
447 modind = iwspacemalloc(ctrl, nvtxs);
448 vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
449 pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
451 if (ctrl->dbglvl&METIS_DBG_REFINE) {
452 printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL
453 ", Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %5"PRIDX", Vol: %5"PRIDX,
454 (omode == OMODE_REFINE ? "GRV" : "GBV"),
455 pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), minwgt[0], maxwgt[0],
456 ComputeLoadImbalance(graph, nparts, ctrl->pijbm),
457 graph->nvtxs, graph->nbnd, graph->mincut, graph->minvol);
458 if (ctrl->minconn)
459 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
460 printf("\n");
463 queue = ipqCreate(nvtxs);
466 /*=====================================================================
467 * The top-level refinement loop
468 *======================================================================*/
469 for (pass=0; pass<niter; pass++) {
470 ASSERT(ComputeVolume(graph, where) == graph->minvol);
472 if (omode == OMODE_BALANCE) {
473 /* Check to see if things are out of balance, given the tolerance */
474 for (i=0; i<nparts; i++) {
475 if (pwgts[i] > maxwgt[i])
476 break;
478 if (i == nparts) /* Things are balanced. Return right away */
479 break;
482 oldcut = graph->mincut;
483 oldvol = graph->minvol;
484 nupd = 0;
486 if (ctrl->minconn)
487 maxndoms = imax(nparts, nads);
489 /* Insert the boundary vertices in the priority queue */
490 irandArrayPermute(graph->nbnd, perm, graph->nbnd/4, 1);
491 for (ii=0; ii<graph->nbnd; ii++) {
492 i = bndind[perm[ii]];
493 ipqInsert(queue, i, graph->vkrinfo[i].gv);
494 vstatus[i] = VPQSTATUS_PRESENT;
495 ListInsert(nupd, updind, updptr, i);
498 /* Start extracting vertices from the queue and try to move them */
499 for (nmoved=0, iii=0;;iii++) {
500 if ((i = ipqGetTop(queue)) == -1)
501 break;
502 vstatus[i] = VPQSTATUS_EXTRACTED;
504 myrinfo = graph->vkrinfo+i;
505 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
507 from = where[i];
508 vwgt = graph->vwgt[i];
510 /* Prevent moves that make 'from' domain underbalanced */
511 if (omode == OMODE_REFINE) {
512 if (myrinfo->nid > 0 && pwgts[from]-vwgt < minwgt[from])
513 continue;
515 else { /* OMODE_BALANCE */
516 if (pwgts[from]-vwgt < minwgt[from])
517 continue;
520 if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))
521 continue;
523 if (ctrl->minconn)
524 SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);
526 xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? graph->vsize[i] : 0);
528 /* Find the most promising subdomain to move to */
529 if (omode == OMODE_REFINE) {
530 for (k=myrinfo->nnbrs-1; k>=0; k--) {
531 if (!safetos[to=mynbrs[k].pid])
532 continue;
533 gain = mynbrs[k].gv + xgain;
534 if (gain >= 0 && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)
535 break;
537 if (k < 0)
538 continue; /* break out if you did not find a candidate */
540 for (j=k-1; j>=0; j--) {
541 if (!safetos[to=mynbrs[j].pid])
542 continue;
543 gain = mynbrs[j].gv + xgain;
544 if ((mynbrs[j].gv > mynbrs[k].gv &&
545 pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)
547 (mynbrs[j].gv == mynbrs[k].gv &&
548 mynbrs[j].ned > mynbrs[k].ned &&
549 pwgts[to]+vwgt <= maxwgt[to])
551 (mynbrs[j].gv == mynbrs[k].gv &&
552 mynbrs[j].ned == mynbrs[k].ned &&
553 itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])
555 k = j;
557 to = mynbrs[k].pid;
559 ASSERT(xgain+mynbrs[k].gv >= 0);
561 j = 0;
562 if (xgain+mynbrs[k].gv > 0 || mynbrs[k].ned-myrinfo->nid > 0)
563 j = 1;
564 else if (mynbrs[k].ned-myrinfo->nid == 0) {
565 if ((iii%2 == 0 && safetos[to] == 2) ||
566 pwgts[from] >= maxwgt[from] ||
567 itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
568 j = 1;
570 if (j == 0)
571 continue;
573 else { /* OMODE_BALANCE */
574 for (k=myrinfo->nnbrs-1; k>=0; k--) {
575 if (!safetos[to=mynbrs[k].pid])
576 continue;
577 if (pwgts[to]+vwgt <= maxwgt[to] ||
578 itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
579 break;
581 if (k < 0)
582 continue; /* break out if you did not find a candidate */
584 for (j=k-1; j>=0; j--) {
585 if (!safetos[to=mynbrs[j].pid])
586 continue;
587 if (itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])
588 k = j;
590 to = mynbrs[k].pid;
592 if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&
593 (xgain+mynbrs[k].gv < 0 ||
594 (xgain+mynbrs[k].gv == 0 && mynbrs[k].ned-myrinfo->nid < 0))
596 continue;
600 /*=====================================================================
601 * If we got here, we can now move the vertex from 'from' to 'to'
602 *======================================================================*/
603 INC_DEC(pwgts[to], pwgts[from], vwgt);
604 graph->mincut -= mynbrs[k].ned-myrinfo->nid;
605 graph->minvol -= (xgain+mynbrs[k].gv);
606 where[i] = to;
607 nmoved++;
609 IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
610 printf("\t\tMoving %6"PRIDX" from %3"PRIDX" to %3"PRIDX". "
611 "Gain: [%4"PRIDX" %4"PRIDX"]. Cut: %6"PRIDX", Vol: %6"PRIDX"\n",
612 i, from, to, xgain+mynbrs[k].gv, mynbrs[k].ned-myrinfo->nid,
613 graph->mincut, graph->minvol));
615 /* Update the subdomain connectivity information */
616 if (ctrl->minconn) {
617 /* take care of i's move itself */
618 UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->nid-mynbrs[k].ned, &maxndoms);
620 /* take care of the adjancent vertices */
621 for (j=xadj[i]; j<xadj[i+1]; j++) {
622 me = where[adjncy[j]];
623 if (me != from && me != to) {
624 UpdateEdgeSubDomainGraph(ctrl, from, me, -1, &maxndoms);
625 UpdateEdgeSubDomainGraph(ctrl, to, me, 1, &maxndoms);
630 /* Update the id/ed/gains/bnd/queue of potentially affected nodes */
631 KWayVolUpdate(ctrl, graph, i, from, to, queue, vstatus, &nupd, updptr,
632 updind, bndtype, vmarker, pmarker, modind);
634 /*CheckKWayVolPartitionParams(ctrl, graph); */
638 /* Reset the vstatus and associated data structures */
639 for (i=0; i<nupd; i++) {
640 ASSERT(updptr[updind[i]] != -1);
641 ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);
642 vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;
643 updptr[updind[i]] = -1;
646 if (ctrl->dbglvl&METIS_DBG_REFINE) {
647 printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."
648 " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,
649 pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts),
650 ComputeLoadImbalance(graph, nparts, ctrl->pijbm),
651 graph->nbnd, nmoved, graph->mincut, graph->minvol);
652 if (ctrl->minconn)
653 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
654 printf("\n");
657 if (nmoved == 0 ||
658 (omode == OMODE_REFINE && graph->minvol == oldvol && graph->mincut == oldcut))
659 break;
662 ipqDestroy(queue);
664 WCOREPOP;
668 /*************************************************************************/
669 /*! K-way partitioning optimization in which the vertices are visited in
670 decreasing ed/sqrt(nnbrs)-id order. Note this is just an
671 approximation, as the ed is often split across different subdomains
672 and the sqrt(nnbrs) is just a crude approximation.
674 \param graph is the graph that is being refined.
675 \param niter is the number of refinement iterations.
676 \param ffactor is the \em fudge-factor for allowing positive gain moves
677 to violate the max-pwgt constraint.
678 \param omode is the type of optimization that will performed among
679 OMODE_REFINE and OMODE_BALANCE
683 /**************************************************************************/
684 void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,
685 real_t ffactor, idx_t omode)
687 /* Common variables to all types of kway-refinement/balancing routines */
688 idx_t i, ii, iii, j, k, l, pass, nvtxs, ncon, nparts, gain;
689 idx_t from, me, to, cto, oldcut;
690 idx_t *xadj, *vwgt, *adjncy, *adjwgt;
691 idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt;
692 idx_t nmoved, nupd, *vstatus, *updptr, *updind;
693 idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;
694 idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;
695 idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);
696 real_t *ubfactors, *pijbm;
697 real_t origbal;
699 /* Edgecut-specific/different variables */
700 idx_t nbnd, oldnnbrs;
701 rpq_t *queue;
702 real_t rgain;
703 ckrinfo_t *myrinfo;
704 cnbr_t *mynbrs;
706 WCOREPUSH;
708 /* Link the graph fields */
709 nvtxs = graph->nvtxs;
710 ncon = graph->ncon;
711 xadj = graph->xadj;
712 vwgt = graph->vwgt;
713 adjncy = graph->adjncy;
714 adjwgt = graph->adjwgt;
716 bndind = graph->bndind;
717 bndptr = graph->bndptr;
719 where = graph->where;
720 pwgts = graph->pwgts;
722 nparts = ctrl->nparts;
723 pijbm = ctrl->pijbm;
726 /* Determine the ubfactors. The method used is different based on omode.
727 When OMODE_BALANCE, the ubfactors are those supplied by the user.
728 When OMODE_REFINE, the ubfactors are the max of the current partition
729 and the user-specified ones. */
730 ubfactors = rwspacemalloc(ctrl, ncon);
731 ComputeLoadImbalanceVec(graph, nparts, pijbm, ubfactors);
732 origbal = rvecmaxdiff(ncon, ubfactors, ctrl->ubfactors);
733 if (omode == OMODE_BALANCE) {
734 rcopy(ncon, ctrl->ubfactors, ubfactors);
736 else {
737 for (i=0; i<ncon; i++)
738 ubfactors[i] = (ubfactors[i] > ctrl->ubfactors[i] ? ubfactors[i] : ctrl->ubfactors[i]);
742 /* Setup the weight intervals of the various subdomains */
743 minwgt = iwspacemalloc(ctrl, nparts*ncon);
744 maxwgt = iwspacemalloc(ctrl, nparts*ncon);
746 for (i=0; i<nparts; i++) {
747 for (j=0; j<ncon; j++) {
748 maxwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j];
749 /*minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]);*/
750 minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2;
754 perm = iwspacemalloc(ctrl, nvtxs);
757 /* This stores the valid target subdomains. It is used when ctrl->minconn to
758 control the subdomains to which moves are allowed to be made.
759 When ctrl->minconn is false, the default values of 2 allow all moves to
760 go through and it does not interfere with the zero-gain move selection. */
761 safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));
763 if (ctrl->minconn) {
764 ComputeSubDomainGraph(ctrl, graph);
766 nads = ctrl->nads;
767 adids = ctrl->adids;
768 adwgts = ctrl->adwgts;
769 doms = iset(nparts, 0, ctrl->pvec1);
773 /* Setup updptr, updind like boundary info to keep track of the vertices whose
774 vstatus's need to be reset at the end of the inner iteration */
775 vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));
776 updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
777 updind = iwspacemalloc(ctrl, nvtxs);
779 if (ctrl->contig) {
780 /* The arrays that will be used for limited check of articulation points */
781 bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
782 bfsind = iwspacemalloc(ctrl, nvtxs);
783 bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
786 if (ctrl->dbglvl&METIS_DBG_REFINE) {
787 printf("%s: [%6"PRIDX" %6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"(%.3"PRREAL"),"
788 " Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX", (%"PRIDX")",
789 (omode == OMODE_REFINE ? "GRC" : "GBC"),
790 imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), imax(nparts*ncon, maxwgt),
791 ComputeLoadImbalance(graph, nparts, pijbm), origbal,
792 graph->nvtxs, graph->nbnd, graph->mincut, niter);
793 if (ctrl->minconn)
794 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
795 printf("\n");
798 queue = rpqCreate(nvtxs);
801 /*=====================================================================
802 * The top-level refinement loop
803 *======================================================================*/
804 for (pass=0; pass<niter; pass++) {
805 ASSERT(ComputeCut(graph, where) == graph->mincut);
807 /* In balancing mode, exit as soon as balance is reached */
808 if (omode == OMODE_BALANCE && IsBalanced(ctrl, graph, 0))
809 break;
811 oldcut = graph->mincut;
812 nbnd = graph->nbnd;
813 nupd = 0;
815 if (ctrl->minconn)
816 maxndoms = imax(nparts, nads);
818 /* Insert the boundary vertices in the priority queue */
819 irandArrayPermute(nbnd, perm, nbnd/4, 1);
820 for (ii=0; ii<nbnd; ii++) {
821 i = bndind[perm[ii]];
822 rgain = (graph->ckrinfo[i].nnbrs > 0 ?
823 1.0*graph->ckrinfo[i].ed/sqrt(graph->ckrinfo[i].nnbrs) : 0.0)
824 - graph->ckrinfo[i].id;
825 rpqInsert(queue, i, rgain);
826 vstatus[i] = VPQSTATUS_PRESENT;
827 ListInsert(nupd, updind, updptr, i);
830 /* Start extracting vertices from the queue and try to move them */
831 for (nmoved=0, iii=0;;iii++) {
832 if ((i = rpqGetTop(queue)) == -1)
833 break;
834 vstatus[i] = VPQSTATUS_EXTRACTED;
836 myrinfo = graph->ckrinfo+i;
837 mynbrs = ctrl->cnbrpool + myrinfo->inbr;
839 from = where[i];
841 /* Prevent moves that make 'from' domain underbalanced */
842 if (omode == OMODE_REFINE) {
843 if (myrinfo->id > 0 &&
844 !ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))
845 continue;
847 else { /* OMODE_BALANCE */
848 if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))
849 continue;
852 if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))
853 continue;
855 if (ctrl->minconn)
856 SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);
858 /* Find the most promising subdomain to move to */
859 if (omode == OMODE_REFINE) {
860 for (k=myrinfo->nnbrs-1; k>=0; k--) {
861 if (!safetos[to=mynbrs[k].pid])
862 continue;
863 gain = mynbrs[k].ed-myrinfo->id;
864 if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))
865 break;
867 if (k < 0)
868 continue; /* break out if you did not find a candidate */
870 cto = to;
871 for (j=k-1; j>=0; j--) {
872 if (!safetos[to=mynbrs[j].pid])
873 continue;
874 if ((mynbrs[j].ed > mynbrs[k].ed &&
875 ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))
877 (mynbrs[j].ed == mynbrs[k].ed &&
878 BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
879 1, pwgts+cto*ncon, pijbm+cto*ncon,
880 1, pwgts+to*ncon, pijbm+to*ncon))) {
881 k = j;
882 cto = to;
885 to = cto;
887 gain = mynbrs[k].ed-myrinfo->id;
888 if (!(gain > 0
889 || (gain == 0
890 && (BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
891 -1, pwgts+from*ncon, pijbm+from*ncon,
892 +1, pwgts+to*ncon, pijbm+to*ncon)
893 || (iii%2 == 0 && safetos[to] == 2)
898 continue;
900 else { /* OMODE_BALANCE */
901 for (k=myrinfo->nnbrs-1; k>=0; k--) {
902 if (!safetos[to=mynbrs[k].pid])
903 continue;
904 if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon) ||
905 BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
906 -1, pwgts+from*ncon, pijbm+from*ncon,
907 +1, pwgts+to*ncon, pijbm+to*ncon))
908 break;
910 if (k < 0)
911 continue; /* break out if you did not find a candidate */
913 cto = to;
914 for (j=k-1; j>=0; j--) {
915 if (!safetos[to=mynbrs[j].pid])
916 continue;
917 if (BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
918 1, pwgts+cto*ncon, pijbm+cto*ncon,
919 1, pwgts+to*ncon, pijbm+to*ncon)) {
920 k = j;
921 cto = to;
924 to = cto;
926 if (mynbrs[k].ed-myrinfo->id < 0 &&
927 !BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
928 -1, pwgts+from*ncon, pijbm+from*ncon,
929 +1, pwgts+to*ncon, pijbm+to*ncon))
930 continue;
935 /*=====================================================================
936 * If we got here, we can now move the vertex from 'from' to 'to'
937 *======================================================================*/
938 graph->mincut -= mynbrs[k].ed-myrinfo->id;
939 nmoved++;
941 IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
942 printf("\t\tMoving %6"PRIDX" to %3"PRIDX". Gain: %4"PRIDX". Cut: %6"PRIDX"\n",
943 i, to, mynbrs[k].ed-myrinfo->id, graph->mincut));
945 /* Update the subdomain connectivity information */
946 if (ctrl->minconn) {
947 /* take care of i's move itself */
948 UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, &maxndoms);
950 /* take care of the adjancent vertices */
951 for (j=xadj[i]; j<xadj[i+1]; j++) {
952 me = where[adjncy[j]];
953 if (me != from && me != to) {
954 UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], &maxndoms);
955 UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], &maxndoms);
960 /* Update ID/ED and BND related information for the moved vertex */
961 iaxpy(ncon, 1, vwgt+i*ncon, 1, pwgts+to*ncon, 1);
962 iaxpy(ncon, -1, vwgt+i*ncon, 1, pwgts+from*ncon, 1);
963 UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where,
964 nbnd, bndptr, bndind, bndtype);
966 /* Update the degrees of adjacent vertices */
967 for (j=xadj[i]; j<xadj[i+1]; j++) {
968 ii = adjncy[j];
969 me = where[ii];
970 myrinfo = graph->ckrinfo+ii;
972 oldnnbrs = myrinfo->nnbrs;
974 UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
975 from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype);
977 UpdateQueueInfo(queue, vstatus, ii, me, from, to, myrinfo, oldnnbrs,
978 nupd, updptr, updind, bndtype);
980 ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]);
984 graph->nbnd = nbnd;
986 /* Reset the vstatus and associated data structures */
987 for (i=0; i<nupd; i++) {
988 ASSERT(updptr[updind[i]] != -1);
989 ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);
990 vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;
991 updptr[updind[i]] = -1;
994 if (ctrl->dbglvl&METIS_DBG_REFINE) {
995 printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."
996 " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,
997 imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts),
998 ComputeLoadImbalance(graph, nparts, pijbm),
999 graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where));
1000 if (ctrl->minconn)
1001 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
1002 printf("\n");
1005 if (nmoved == 0 || (omode == OMODE_REFINE && graph->mincut == oldcut))
1006 break;
1009 rpqDestroy(queue);
1011 WCOREPOP;
1015 /*************************************************************************/
1016 /*! K-way refinement that minimizes the communication volume. This is a
1017 greedy routine and the vertices are visited in decreasing gv order.
1019 \param graph is the graph that is being refined.
1020 \param niter is the number of refinement iterations.
1021 \param ffactor is the \em fudge-factor for allowing positive gain moves
1022 to violate the max-pwgt constraint.
1025 /**************************************************************************/
1026 void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,
1027 real_t ffactor, idx_t omode)
1029 /* Common variables to all types of kway-refinement/balancing routines */
1030 idx_t i, ii, iii, j, k, l, pass, nvtxs, ncon, nparts, gain;
1031 idx_t from, me, to, cto, oldcut;
1032 idx_t *xadj, *vwgt, *adjncy;
1033 idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt;
1034 idx_t nmoved, nupd, *vstatus, *updptr, *updind;
1035 idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;
1036 idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;
1037 idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);
1038 real_t *ubfactors, *pijbm;
1039 real_t origbal;
1041 /* Volume-specific/different variables */
1042 ipq_t *queue;
1043 idx_t oldvol, xgain;
1044 idx_t *vmarker, *pmarker, *modind;
1045 vkrinfo_t *myrinfo;
1046 vnbr_t *mynbrs;
1048 WCOREPUSH;
1050 /* Link the graph fields */
1051 nvtxs = graph->nvtxs;
1052 ncon = graph->ncon;
1053 xadj = graph->xadj;
1054 vwgt = graph->vwgt;
1055 adjncy = graph->adjncy;
1056 bndptr = graph->bndptr;
1057 bndind = graph->bndind;
1058 where = graph->where;
1059 pwgts = graph->pwgts;
1061 nparts = ctrl->nparts;
1062 pijbm = ctrl->pijbm;
1065 /* Determine the ubfactors. The method used is different based on omode.
1066 When OMODE_BALANCE, the ubfactors are those supplied by the user.
1067 When OMODE_REFINE, the ubfactors are the max of the current partition
1068 and the user-specified ones. */
1069 ubfactors = rwspacemalloc(ctrl, ncon);
1070 ComputeLoadImbalanceVec(graph, nparts, pijbm, ubfactors);
1071 origbal = rvecmaxdiff(ncon, ubfactors, ctrl->ubfactors);
1072 if (omode == OMODE_BALANCE) {
1073 rcopy(ncon, ctrl->ubfactors, ubfactors);
1075 else {
1076 for (i=0; i<ncon; i++)
1077 ubfactors[i] = (ubfactors[i] > ctrl->ubfactors[i] ? ubfactors[i] : ctrl->ubfactors[i]);
1081 /* Setup the weight intervals of the various subdomains */
1082 minwgt = iwspacemalloc(ctrl, nparts*ncon);
1083 maxwgt = iwspacemalloc(ctrl, nparts*ncon);
1085 for (i=0; i<nparts; i++) {
1086 for (j=0; j<ncon; j++) {
1087 maxwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j];
1088 /*minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]); */
1089 minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2;
1093 perm = iwspacemalloc(ctrl, nvtxs);
1096 /* This stores the valid target subdomains. It is used when ctrl->minconn to
1097 control the subdomains to which moves are allowed to be made.
1098 When ctrl->minconn is false, the default values of 2 allow all moves to
1099 go through and it does not interfere with the zero-gain move selection. */
1100 safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));
1102 if (ctrl->minconn) {
1103 ComputeSubDomainGraph(ctrl, graph);
1105 nads = ctrl->nads;
1106 adids = ctrl->adids;
1107 adwgts = ctrl->adwgts;
1108 doms = iset(nparts, 0, ctrl->pvec1);
1112 /* Setup updptr, updind like boundary info to keep track of the vertices whose
1113 vstatus's need to be reset at the end of the inner iteration */
1114 vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));
1115 updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
1116 updind = iwspacemalloc(ctrl, nvtxs);
1118 if (ctrl->contig) {
1119 /* The arrays that will be used for limited check of articulation points */
1120 bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
1121 bfsind = iwspacemalloc(ctrl, nvtxs);
1122 bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
1125 /* Vol-refinement specific working arrays */
1126 modind = iwspacemalloc(ctrl, nvtxs);
1127 vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
1128 pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
1130 if (ctrl->dbglvl&METIS_DBG_REFINE) {
1131 printf("%s: [%6"PRIDX" %6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"(%.3"PRREAL"),"
1132 ", Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %5"PRIDX", Vol: %5"PRIDX", (%"PRIDX")",
1133 (omode == OMODE_REFINE ? "GRV" : "GBV"),
1134 imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), imax(nparts*ncon, maxwgt),
1135 ComputeLoadImbalance(graph, nparts, pijbm), origbal,
1136 graph->nvtxs, graph->nbnd, graph->mincut, graph->minvol, niter);
1137 if (ctrl->minconn)
1138 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
1139 printf("\n");
1142 queue = ipqCreate(nvtxs);
1145 /*=====================================================================
1146 * The top-level refinement loop
1147 *======================================================================*/
1148 for (pass=0; pass<niter; pass++) {
1149 ASSERT(ComputeVolume(graph, where) == graph->minvol);
1151 /* In balancing mode, exit as soon as balance is reached */
1152 if (omode == OMODE_BALANCE && IsBalanced(ctrl, graph, 0))
1153 break;
1155 oldcut = graph->mincut;
1156 oldvol = graph->minvol;
1157 nupd = 0;
1159 if (ctrl->minconn)
1160 maxndoms = imax(nparts, nads);
1162 /* Insert the boundary vertices in the priority queue */
1163 irandArrayPermute(graph->nbnd, perm, graph->nbnd/4, 1);
1164 for (ii=0; ii<graph->nbnd; ii++) {
1165 i = bndind[perm[ii]];
1166 ipqInsert(queue, i, graph->vkrinfo[i].gv);
1167 vstatus[i] = VPQSTATUS_PRESENT;
1168 ListInsert(nupd, updind, updptr, i);
1171 /* Start extracting vertices from the queue and try to move them */
1172 for (nmoved=0, iii=0;;iii++) {
1173 if ((i = ipqGetTop(queue)) == -1)
1174 break;
1175 vstatus[i] = VPQSTATUS_EXTRACTED;
1177 myrinfo = graph->vkrinfo+i;
1178 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
1180 from = where[i];
1182 /* Prevent moves that make 'from' domain underbalanced */
1183 if (omode == OMODE_REFINE) {
1184 if (myrinfo->nid > 0 &&
1185 !ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))
1186 continue;
1188 else { /* OMODE_BALANCE */
1189 if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))
1190 continue;
1193 if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))
1194 continue;
1196 if (ctrl->minconn)
1197 SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);
1199 xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? graph->vsize[i] : 0);
1201 /* Find the most promising subdomain to move to */
1202 if (omode == OMODE_REFINE) {
1203 for (k=myrinfo->nnbrs-1; k>=0; k--) {
1204 if (!safetos[to=mynbrs[k].pid])
1205 continue;
1206 gain = mynbrs[k].gv + xgain;
1207 if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))
1208 break;
1210 if (k < 0)
1211 continue; /* break out if you did not find a candidate */
1213 cto = to;
1214 for (j=k-1; j>=0; j--) {
1215 if (!safetos[to=mynbrs[j].pid])
1216 continue;
1217 gain = mynbrs[j].gv + xgain;
1218 if ((mynbrs[j].gv > mynbrs[k].gv &&
1219 ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))
1221 (mynbrs[j].gv == mynbrs[k].gv &&
1222 mynbrs[j].ned > mynbrs[k].ned &&
1223 ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))
1225 (mynbrs[j].gv == mynbrs[k].gv &&
1226 mynbrs[j].ned == mynbrs[k].ned &&
1227 BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
1228 1, pwgts+cto*ncon, pijbm+cto*ncon,
1229 1, pwgts+to*ncon, pijbm+to*ncon))) {
1230 k = j;
1231 cto = to;
1234 to = cto;
1236 j = 0;
1237 if (xgain+mynbrs[k].gv > 0 || mynbrs[k].ned-myrinfo->nid > 0)
1238 j = 1;
1239 else if (mynbrs[k].ned-myrinfo->nid == 0) {
1240 if ((iii%2 == 0 && safetos[to] == 2) ||
1241 BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
1242 -1, pwgts+from*ncon, pijbm+from*ncon,
1243 +1, pwgts+to*ncon, pijbm+to*ncon))
1244 j = 1;
1246 if (j == 0)
1247 continue;
1249 else { /* OMODE_BALANCE */
1250 for (k=myrinfo->nnbrs-1; k>=0; k--) {
1251 if (!safetos[to=mynbrs[k].pid])
1252 continue;
1253 if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon) ||
1254 BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
1255 -1, pwgts+from*ncon, pijbm+from*ncon,
1256 +1, pwgts+to*ncon, pijbm+to*ncon))
1257 break;
1259 if (k < 0)
1260 continue; /* break out if you did not find a candidate */
1262 cto = to;
1263 for (j=k-1; j>=0; j--) {
1264 if (!safetos[to=mynbrs[j].pid])
1265 continue;
1266 if (BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
1267 1, pwgts+cto*ncon, pijbm+cto*ncon,
1268 1, pwgts+to*ncon, pijbm+to*ncon)) {
1269 k = j;
1270 cto = to;
1273 to = cto;
1275 if ((xgain+mynbrs[k].gv < 0 ||
1276 (xgain+mynbrs[k].gv == 0 && mynbrs[k].ned-myrinfo->nid < 0))
1278 !BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,
1279 -1, pwgts+from*ncon, pijbm+from*ncon,
1280 +1, pwgts+to*ncon, pijbm+to*ncon))
1281 continue;
1285 /*=====================================================================
1286 * If we got here, we can now move the vertex from 'from' to 'to'
1287 *======================================================================*/
1288 graph->mincut -= mynbrs[k].ned-myrinfo->nid;
1289 graph->minvol -= (xgain+mynbrs[k].gv);
1290 where[i] = to;
1291 nmoved++;
1293 IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
1294 printf("\t\tMoving %6"PRIDX" from %3"PRIDX" to %3"PRIDX". "
1295 "Gain: [%4"PRIDX" %4"PRIDX"]. Cut: %6"PRIDX", Vol: %6"PRIDX"\n",
1296 i, from, to, xgain+mynbrs[k].gv, mynbrs[k].ned-myrinfo->nid,
1297 graph->mincut, graph->minvol));
1299 /* Update the subdomain connectivity information */
1300 if (ctrl->minconn) {
1301 /* take care of i's move itself */
1302 UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->nid-mynbrs[k].ned, &maxndoms);
1304 /* take care of the adjancent vertices */
1305 for (j=xadj[i]; j<xadj[i+1]; j++) {
1306 me = where[adjncy[j]];
1307 if (me != from && me != to) {
1308 UpdateEdgeSubDomainGraph(ctrl, from, me, -1, &maxndoms);
1309 UpdateEdgeSubDomainGraph(ctrl, to, me, 1, &maxndoms);
1314 /* Update pwgts */
1315 iaxpy(ncon, 1, vwgt+i*ncon, 1, pwgts+to*ncon, 1);
1316 iaxpy(ncon, -1, vwgt+i*ncon, 1, pwgts+from*ncon, 1);
1318 /* Update the id/ed/gains/bnd/queue of potentially affected nodes */
1319 KWayVolUpdate(ctrl, graph, i, from, to, queue, vstatus, &nupd, updptr,
1320 updind, bndtype, vmarker, pmarker, modind);
1322 /*CheckKWayVolPartitionParams(ctrl, graph); */
1326 /* Reset the vstatus and associated data structures */
1327 for (i=0; i<nupd; i++) {
1328 ASSERT(updptr[updind[i]] != -1);
1329 ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);
1330 vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;
1331 updptr[updind[i]] = -1;
1334 if (ctrl->dbglvl&METIS_DBG_REFINE) {
1335 printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."
1336 " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,
1337 imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts),
1338 ComputeLoadImbalance(graph, nparts, pijbm),
1339 graph->nbnd, nmoved, graph->mincut, graph->minvol);
1340 if (ctrl->minconn)
1341 printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));
1342 printf("\n");
1345 if (nmoved == 0 ||
1346 (omode == OMODE_REFINE && graph->minvol == oldvol && graph->mincut == oldcut))
1347 break;
1350 ipqDestroy(queue);
1352 WCOREPOP;
1356 /*************************************************************************/
1357 /*! This function performs an approximate articulation vertex test.
1358 It assumes that the bfslvl, bfsind, and bfsmrk arrays are initialized
1359 appropriately. */
1360 /*************************************************************************/
1361 idx_t IsArticulationNode(idx_t i, idx_t *xadj, idx_t *adjncy, idx_t *where,
1362 idx_t *bfslvl, idx_t *bfsind, idx_t *bfsmrk)
1364 idx_t ii, j, k=0, head, tail, nhits, tnhits, from, BFSDEPTH=5;
1366 from = where[i];
1368 /* Determine if the vertex is safe to move from a contiguity standpoint */
1369 for (tnhits=0, j=xadj[i]; j<xadj[i+1]; j++) {
1370 if (where[adjncy[j]] == from) {
1371 ASSERT(bfsmrk[adjncy[j]] == 0);
1372 ASSERT(bfslvl[adjncy[j]] == 0);
1373 bfsmrk[k=adjncy[j]] = 1;
1374 tnhits++;
1378 /* Easy cases */
1379 if (tnhits == 0)
1380 return 0;
1381 if (tnhits == 1) {
1382 bfsmrk[k] = 0;
1383 return 0;
1386 ASSERT(bfslvl[i] == 0);
1387 bfslvl[i] = 1;
1389 bfsind[0] = k; /* That was the last one from the previous loop */
1390 bfslvl[k] = 1;
1391 bfsmrk[k] = 0;
1392 head = 0;
1393 tail = 1;
1395 /* Do a limited BFS traversal to see if you can get to all the other nodes */
1396 for (nhits=1; head<tail; ) {
1397 ii = bfsind[head++];
1398 for (j=xadj[ii]; j<xadj[ii+1]; j++) {
1399 if (where[k=adjncy[j]] == from) {
1400 if (bfsmrk[k]) {
1401 bfsmrk[k] = 0;
1402 if (++nhits == tnhits)
1403 break;
1405 if (bfslvl[k] == 0 && bfslvl[ii] < BFSDEPTH) {
1406 bfsind[tail++] = k;
1407 bfslvl[k] = bfslvl[ii]+1;
1411 if (nhits == tnhits)
1412 break;
1415 /* Reset the various BFS related arrays */
1416 bfslvl[i] = 0;
1417 for (j=0; j<tail; j++)
1418 bfslvl[bfsind[j]] = 0;
1421 /* Reset the bfsmrk array for the next vertex when has not already being cleared */
1422 if (nhits < tnhits) {
1423 for (j=xadj[i]; j<xadj[i+1]; j++)
1424 if (where[adjncy[j]] == from)
1425 bfsmrk[adjncy[j]] = 0;
1428 return (nhits != tnhits);
1432 /*************************************************************************/
1433 /*!
1434 This function updates the edge and volume gains due to a vertex movement.
1435 v from 'from' to 'to'.
1437 \param ctrl is the control structure.
1438 \param graph is the graph being partitioned.
1439 \param v is the vertex that is moving.
1440 \param from is the original partition of v.
1441 \param to is the new partition of v.
1442 \param queue is the priority queue. If the queue is NULL, no priority-queue
1443 related updates are performed.
1444 \param vstatus is an array that marks the status of the vertex in terms
1445 of the priority queue. If queue is NULL, this parameter is ignored.
1446 \param r_nqupd is the number of vertices that have been inserted/removed
1447 from the queue. If queue is NULL, this parameter is ignored.
1448 \param updptr stores the index of each vertex in updind. If queue is NULL,
1449 this parameter is ignored.
1450 \param updind is the list of vertices that have been inserted/removed from
1451 the queue. If queue is NULL, this parameter is ignored.
1452 \param vmarker is of size nvtxs and is used internally as a temporary array.
1453 On entry and return all of its entries are 0.
1454 \param pmarker is of sie nparts and is used internally as a temporary marking
1455 array. On entry and return all of its entries are -1.
1456 \param modind is an array of size nvtxs and is used to keep track of the
1457 list of vertices whose gains need to be updated.
1459 /*************************************************************************/
1460 void KWayVolUpdate(ctrl_t *ctrl, graph_t *graph, idx_t v, idx_t from,
1461 idx_t to, ipq_t *queue, idx_t *vstatus, idx_t *r_nupd, idx_t *updptr,
1462 idx_t *updind, idx_t bndtype, idx_t *vmarker, idx_t *pmarker,
1463 idx_t *modind)
1465 idx_t i, ii, iii, j, jj, k, kk, l, u, nmod, other, me, myidx;
1466 idx_t *xadj, *vsize, *adjncy, *where;
1467 vkrinfo_t *myrinfo, *orinfo;
1468 vnbr_t *mynbrs, *onbrs;
1470 xadj = graph->xadj;
1471 adjncy = graph->adjncy;
1472 vsize = graph->vsize;
1473 where = graph->where;
1475 myrinfo = graph->vkrinfo+v;
1476 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
1479 /*======================================================================
1480 * Remove the contributions on the gain made by 'v'.
1481 *=====================================================================*/
1482 for (k=0; k<myrinfo->nnbrs; k++)
1483 pmarker[mynbrs[k].pid] = k;
1484 pmarker[from] = k;
1486 myidx = pmarker[to]; /* Keep track of the index in mynbrs of the 'to' domain */
1488 for (j=xadj[v]; j<xadj[v+1]; j++) {
1489 ii = adjncy[j];
1490 other = where[ii];
1491 orinfo = graph->vkrinfo+ii;
1492 onbrs = ctrl->vnbrpool + orinfo->inbr;
1494 if (other == from) {
1495 for (k=0; k<orinfo->nnbrs; k++) {
1496 if (pmarker[onbrs[k].pid] == -1)
1497 onbrs[k].gv += vsize[v];
1500 else {
1501 ASSERT(pmarker[other] != -1);
1503 if (mynbrs[pmarker[other]].ned > 1) {
1504 for (k=0; k<orinfo->nnbrs; k++) {
1505 if (pmarker[onbrs[k].pid] == -1)
1506 onbrs[k].gv += vsize[v];
1509 else { /* There is only one connection */
1510 for (k=0; k<orinfo->nnbrs; k++) {
1511 if (pmarker[onbrs[k].pid] != -1)
1512 onbrs[k].gv -= vsize[v];
1518 for (k=0; k<myrinfo->nnbrs; k++)
1519 pmarker[mynbrs[k].pid] = -1;
1520 pmarker[from] = -1;
1523 /*======================================================================
1524 * Update the id/ed of vertex 'v'
1525 *=====================================================================*/
1526 if (myidx == -1) {
1527 myidx = myrinfo->nnbrs++;
1528 ASSERT(myidx < xadj[v+1]-xadj[v]);
1529 mynbrs[myidx].ned = 0;
1531 myrinfo->ned += myrinfo->nid-mynbrs[myidx].ned;
1532 SWAP(myrinfo->nid, mynbrs[myidx].ned, j);
1533 if (mynbrs[myidx].ned == 0)
1534 mynbrs[myidx] = mynbrs[--myrinfo->nnbrs];
1535 else
1536 mynbrs[myidx].pid = from;
1539 /*======================================================================
1540 * Update the degrees of adjacent vertices and their volume gains
1541 *=====================================================================*/
1542 vmarker[v] = 1;
1543 modind[0] = v;
1544 nmod = 1;
1545 for (j=xadj[v]; j<xadj[v+1]; j++) {
1546 ii = adjncy[j];
1547 me = where[ii];
1549 if (!vmarker[ii]) { /* The marking is done for boundary and max gv calculations */
1550 vmarker[ii] = 2;
1551 modind[nmod++] = ii;
1554 myrinfo = graph->vkrinfo+ii;
1555 if (myrinfo->inbr == -1)
1556 myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[ii+1]-xadj[ii]+1);
1557 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
1559 if (me == from) {
1560 INC_DEC(myrinfo->ned, myrinfo->nid, 1);
1562 else if (me == to) {
1563 INC_DEC(myrinfo->nid, myrinfo->ned, 1);
1566 /* Remove the edgeweight from the 'pid == from' entry of the vertex */
1567 if (me != from) {
1568 for (k=0; k<myrinfo->nnbrs; k++) {
1569 if (mynbrs[k].pid == from) {
1570 if (mynbrs[k].ned == 1) {
1571 mynbrs[k] = mynbrs[--myrinfo->nnbrs];
1572 vmarker[ii] = 1; /* You do a complete .gv calculation */
1574 /* All vertices adjacent to 'ii' need to be updated */
1575 for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
1576 u = adjncy[jj];
1577 other = where[u];
1578 orinfo = graph->vkrinfo+u;
1579 onbrs = ctrl->vnbrpool + orinfo->inbr;
1581 for (kk=0; kk<orinfo->nnbrs; kk++) {
1582 if (onbrs[kk].pid == from) {
1583 onbrs[kk].gv -= vsize[ii];
1584 if (!vmarker[u]) { /* Need to update boundary etc */
1585 vmarker[u] = 2;
1586 modind[nmod++] = u;
1588 break;
1593 else {
1594 mynbrs[k].ned--;
1596 /* Update the gv due to single 'ii' connection to 'from' */
1597 if (mynbrs[k].ned == 1) {
1598 /* find the vertex 'u' that 'ii' was connected into 'from' */
1599 for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
1600 u = adjncy[jj];
1601 other = where[u];
1603 if (other == from) {
1604 orinfo = graph->vkrinfo+u;
1605 onbrs = ctrl->vnbrpool + orinfo->inbr;
1607 /* The following is correct because domains in common
1608 between ii and u will lead to a reduction over the
1609 previous gain, whereas domains only in u but not in
1610 ii, will lead to no change as opposed to the earlier
1611 increase */
1612 for (kk=0; kk<orinfo->nnbrs; kk++)
1613 onbrs[kk].gv += vsize[ii];
1615 if (!vmarker[u]) { /* Need to update boundary etc */
1616 vmarker[u] = 2;
1617 modind[nmod++] = u;
1619 break;
1624 break;
1630 /* Add the edgeweight to the 'pid == to' entry of the vertex */
1631 if (me != to) {
1632 for (k=0; k<myrinfo->nnbrs; k++) {
1633 if (mynbrs[k].pid == to) {
1634 mynbrs[k].ned++;
1636 /* Update the gv due to non-single 'ii' connection to 'to' */
1637 if (mynbrs[k].ned == 2) {
1638 /* find the vertex 'u' that 'ii' was connected into 'to' */
1639 for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
1640 u = adjncy[jj];
1641 other = where[u];
1643 if (u != v && other == to) {
1644 orinfo = graph->vkrinfo+u;
1645 onbrs = ctrl->vnbrpool + orinfo->inbr;
1646 for (kk=0; kk<orinfo->nnbrs; kk++)
1647 onbrs[kk].gv -= vsize[ii];
1649 if (!vmarker[u]) { /* Need to update boundary etc */
1650 vmarker[u] = 2;
1651 modind[nmod++] = u;
1653 break;
1657 break;
1661 if (k == myrinfo->nnbrs) {
1662 mynbrs[myrinfo->nnbrs].pid = to;
1663 mynbrs[myrinfo->nnbrs++].ned = 1;
1664 vmarker[ii] = 1; /* You do a complete .gv calculation */
1666 /* All vertices adjacent to 'ii' need to be updated */
1667 for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
1668 u = adjncy[jj];
1669 other = where[u];
1670 orinfo = graph->vkrinfo+u;
1671 onbrs = ctrl->vnbrpool + orinfo->inbr;
1673 for (kk=0; kk<orinfo->nnbrs; kk++) {
1674 if (onbrs[kk].pid == to) {
1675 onbrs[kk].gv += vsize[ii];
1676 if (!vmarker[u]) { /* Need to update boundary etc */
1677 vmarker[u] = 2;
1678 modind[nmod++] = u;
1680 break;
1687 ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]);
1691 /*======================================================================
1692 * Add the contributions on the volume gain due to 'v'
1693 *=====================================================================*/
1694 myrinfo = graph->vkrinfo+v;
1695 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
1696 for (k=0; k<myrinfo->nnbrs; k++)
1697 pmarker[mynbrs[k].pid] = k;
1698 pmarker[to] = k;
1700 for (j=xadj[v]; j<xadj[v+1]; j++) {
1701 ii = adjncy[j];
1702 other = where[ii];
1703 orinfo = graph->vkrinfo+ii;
1704 onbrs = ctrl->vnbrpool + orinfo->inbr;
1706 if (other == to) {
1707 for (k=0; k<orinfo->nnbrs; k++) {
1708 if (pmarker[onbrs[k].pid] == -1)
1709 onbrs[k].gv -= vsize[v];
1712 else {
1713 ASSERT(pmarker[other] != -1);
1715 if (mynbrs[pmarker[other]].ned > 1) {
1716 for (k=0; k<orinfo->nnbrs; k++) {
1717 if (pmarker[onbrs[k].pid] == -1)
1718 onbrs[k].gv -= vsize[v];
1721 else { /* There is only one connection */
1722 for (k=0; k<orinfo->nnbrs; k++) {
1723 if (pmarker[onbrs[k].pid] != -1)
1724 onbrs[k].gv += vsize[v];
1729 for (k=0; k<myrinfo->nnbrs; k++)
1730 pmarker[mynbrs[k].pid] = -1;
1731 pmarker[to] = -1;
1734 /*======================================================================
1735 * Recompute the volume information of the 'hard' nodes, and update the
1736 * max volume gain for all the modified vertices and the priority queue
1737 *=====================================================================*/
1738 for (iii=0; iii<nmod; iii++) {
1739 i = modind[iii];
1740 me = where[i];
1742 myrinfo = graph->vkrinfo+i;
1743 mynbrs = ctrl->vnbrpool + myrinfo->inbr;
1745 if (vmarker[i] == 1) { /* Only complete gain updates go through */
1746 for (k=0; k<myrinfo->nnbrs; k++)
1747 mynbrs[k].gv = 0;
1749 for (j=xadj[i]; j<xadj[i+1]; j++) {
1750 ii = adjncy[j];
1751 other = where[ii];
1752 orinfo = graph->vkrinfo+ii;
1753 onbrs = ctrl->vnbrpool + orinfo->inbr;
1755 for (kk=0; kk<orinfo->nnbrs; kk++)
1756 pmarker[onbrs[kk].pid] = kk;
1757 pmarker[other] = 1;
1759 if (me == other) {
1760 /* Find which domains 'i' is connected and 'ii' is not and update their gain */
1761 for (k=0; k<myrinfo->nnbrs; k++) {
1762 if (pmarker[mynbrs[k].pid] == -1)
1763 mynbrs[k].gv -= vsize[ii];
1766 else {
1767 ASSERT(pmarker[me] != -1);
1769 /* I'm the only connection of 'ii' in 'me' */
1770 if (onbrs[pmarker[me]].ned == 1) {
1771 /* Increase the gains for all the common domains between 'i' and 'ii' */
1772 for (k=0; k<myrinfo->nnbrs; k++) {
1773 if (pmarker[mynbrs[k].pid] != -1)
1774 mynbrs[k].gv += vsize[ii];
1777 else {
1778 /* Find which domains 'i' is connected and 'ii' is not and update their gain */
1779 for (k=0; k<myrinfo->nnbrs; k++) {
1780 if (pmarker[mynbrs[k].pid] == -1)
1781 mynbrs[k].gv -= vsize[ii];
1786 for (kk=0; kk<orinfo->nnbrs; kk++)
1787 pmarker[onbrs[kk].pid] = -1;
1788 pmarker[other] = -1;
1793 /* Compute the overall gv for that node */
1794 myrinfo->gv = IDX_MIN;
1795 for (k=0; k<myrinfo->nnbrs; k++) {
1796 if (mynbrs[k].gv > myrinfo->gv)
1797 myrinfo->gv = mynbrs[k].gv;
1800 /* Add the xtra gain due to id == 0 */
1801 if (myrinfo->ned > 0 && myrinfo->nid == 0)
1802 myrinfo->gv += vsize[i];
1805 /*======================================================================
1806 * Maintain a consistent boundary
1807 *=====================================================================*/
1808 if (bndtype == BNDTYPE_REFINE) {
1809 if (myrinfo->gv >= 0 && graph->bndptr[i] == -1)
1810 BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, i);
1812 if (myrinfo->gv < 0 && graph->bndptr[i] != -1)
1813 BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, i);
1815 else {
1816 if (myrinfo->ned > 0 && graph->bndptr[i] == -1)
1817 BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, i);
1819 if (myrinfo->ned == 0 && graph->bndptr[i] != -1)
1820 BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, i);
1824 /*======================================================================
1825 * Update the priority queue appropriately (if allowed)
1826 *=====================================================================*/
1827 if (queue != NULL) {
1828 if (vstatus[i] != VPQSTATUS_EXTRACTED) {
1829 if (graph->bndptr[i] != -1) { /* In-boundary vertex */
1830 if (vstatus[i] == VPQSTATUS_PRESENT) {
1831 ipqUpdate(queue, i, myrinfo->gv);
1833 else {
1834 ipqInsert(queue, i, myrinfo->gv);
1835 vstatus[i] = VPQSTATUS_PRESENT;
1836 ListInsert(*r_nupd, updind, updptr, i);
1839 else { /* Off-boundary vertex */
1840 if (vstatus[i] == VPQSTATUS_PRESENT) {
1841 ipqDelete(queue, i);
1842 vstatus[i] = VPQSTATUS_NOTPRESENT;
1843 ListDelete(*r_nupd, updind, updptr, i);
1849 vmarker[i] = 0;