/************************************************************************* * This function performs an edge-based FM refinement **************************************************************************/ void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses) { int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; idxtype *moved, *swaps, *perm, *qnum; float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal; PQueueType parts[MAXNCON][2]; int higain, oldgain, mincut, initcut, newcut, mincutorder; float rtpwgts[2]; nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; nvwgt = graph->nvwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; id = graph->id; ed = graph->ed; npwgts = graph->npwgts; bndptr = graph->bndptr; bndind = graph->bndind; moved = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); qnum = idxwspacemalloc(ctrl, nvtxs); limit = amin(amax(0.01*nvtxs, 25), 150); /* Initialize the queues */ for (i=0; i<ncon; i++) { PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); } for (i=0; i<nvtxs; i++) qnum[i] = samax(ncon, nvwgt+i*ncon); origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); rtpwgts[0] = origbal*tpwgts[0]; rtpwgts[1] = origbal*tpwgts[1]; if (ctrl->dbglvl&DBG_REFINE) { printf("Parts: ["); for (l=0; l<ncon; l++) printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal); } idxset(nvtxs, -1, moved); for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ for (i=0; i<ncon; i++) { PQueueReset(&parts[i][0]); PQueueReset(&parts[i][1]); } mincutorder = -1; newcut = mincut = initcut = graph->mincut; for (i=0; i<ncon; i++) mindiff[i] = fabs(tpwgts[0]-npwgts[i]); minbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); ASSERT(ComputeCut(graph, where) == graph->mincut); ASSERT(CheckBnd(graph)); /* Insert boundary nodes in the priority queues */ nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; ii<nbnd; ii++) { i = bndind[perm[ii]]; ASSERT(ed[i] > 0 || id[i] == 0); ASSERT(bndptr[i] != -1); PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); } for (nswaps=0; nswaps<nvtxs; nswaps++) { SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts); to = (from+1)%2; if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) break; ASSERT(bndptr[higain] != -1); saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); newcut -= (ed[higain]-id[higain]); newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); if ((newcut < mincut && newbal-origbal <= .00001) || (newcut == mincut && (newbal < minbal || (newbal == minbal && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) { mincut = newcut; minbal = newbal; mincutorder = nswaps; for (i=0; i<ncon; i++) mindiff[i] = fabs(tpwgts[0]-npwgts[i]); } else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ newcut += (ed[higain]-id[higain]); saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); break; } where[higain] = to; moved[higain] = nswaps; swaps[nswaps] = higain; if (ctrl->dbglvl&DBG_MOVEINFO) { printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); for (l=0; l<ncon; l++) printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); printf(", %.3f LB: %.3f\n", minbal, newbal); } /************************************************************** * Update the id[i]/ed[i] values of the affected nodes ***************************************************************/ SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; oldgain = ed[k]-id[k]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); /* Update its boundary information and queue position */ if (bndptr[k] != -1) { /* If k was a boundary vertex */ if (ed[k] == 0) { /* Not a boundary vertex any more */ BNDDelete(nbnd, bndind, bndptr, k); if (moved[k] == -1) /* Remove it if in the queues */ PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain); } else { /* If it has not been moved, update its position in the queue */ if (moved[k] == -1) PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); } } else { if (ed[k] > 0) { /* It will now become a boundary vertex */ BNDInsert(nbnd, bndind, bndptr, k); if (moved[k] == -1) PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]); } } } } /**************************************************************** * Roll back computations *****************************************************************/ for (i=0; i<nswaps; i++) moved[swaps[i]] = -1; /* reset moved array */ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; to = where[higain] = (where[higain]+1)%2; SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); else if (ed[higain] > 0 && bndptr[higain] == -1) BNDInsert(nbnd, bndind, bndptr, higain); saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); if (bndptr[k] != -1 && ed[k] == 0) BNDDelete(nbnd, bndind, bndptr, k); if (bndptr[k] == -1 && ed[k] > 0) BNDInsert(nbnd, bndind, bndptr, k); } } if (ctrl->dbglvl&DBG_REFINE) { printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); for (l=0; l<ncon; l++) printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); } graph->mincut = mincut; graph->nbnd = nbnd; if (mincutorder == -1 || mincut == initcut) break; } for (i=0; i<ncon; i++) { PQueueFree(ctrl, &parts[i][0]); PQueueFree(ctrl, &parts[i][1]); } idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); }
/************************************************************************* * This function performs k-way refinement **************************************************************************/ void Greedy_KWayEdgeBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses) { int i, ii, iii, j, jj, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves; int from, me, to, oldcut, vwgt; idxtype *xadj, *adjncy, *adjwgt; idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts; EDegreeType *myedegrees; RInfoType *myrinfo; PQueueType queue; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; /* Setup the weight intervals of the various subdomains */ minwgt = idxwspacemalloc(ctrl, nparts); maxwgt = idxwspacemalloc(ctrl, nparts); itpwgts = idxwspacemalloc(ctrl, nparts); tvwgt = idxsum(nparts, pwgts); ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); for (i=0; i<nparts; i++) { itpwgts[i] = tpwgts[i]*tvwgt; maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); } perm = idxwspacemalloc(ctrl, nvtxs); moved = idxwspacemalloc(ctrl, nvtxs); PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n", pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, graph->mincut)); for (pass=0; pass<npasses; pass++) { ASSERT(ComputeCut(graph, where) == graph->mincut); /* Check to see if things are out of balance, given the tolerance */ for (i=0; i<nparts; i++) { if (pwgts[i] > maxwgt[i]) break; } if (i == nparts) /* Things are balanced. Return right away */ break; PQueueReset(&queue); idxset(nvtxs, -1, moved); oldcut = graph->mincut; nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; ii<nbnd; ii++) { i = bndind[perm[ii]]; PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id); moved[i] = 2; } nmoves = 0; for (;;) { if ((i = PQueueGetMax(&queue)) == -1) break; moved[i] = 1; myrinfo = graph->rinfo+i; from = where[i]; vwgt = graph->vwgt[i]; if (pwgts[from]-vwgt < minwgt[from]) continue; /* This cannot be moved! */ myedegrees = myrinfo->edegrees; myndegrees = myrinfo->ndegrees; for (k=0; k<myndegrees; k++) { to = myedegrees[k].pid; if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) break; } if (k == myndegrees) continue; /* break out if you did not find a candidate */ for (j=k+1; j<myndegrees; j++) { to = myedegrees[j].pid; if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]) k = j; } to = myedegrees[k].pid; if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0) continue; /*===================================================================== * If we got here, we can now move the vertex from 'from' to 'to' *======================================================================*/ graph->mincut -= myedegrees[k].ed-myrinfo->id; IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); /* Update where, weight, and ID/ED information of the vertex you moved */ where[i] = to; INC_DEC(pwgts[to], pwgts[from], vwgt); myrinfo->ed += myrinfo->id-myedegrees[k].ed; SWAP(myrinfo->id, myedegrees[k].ed, j); if (myedegrees[k].ed == 0) myedegrees[k] = myedegrees[--myrinfo->ndegrees]; else myedegrees[k].pid = from; if (myrinfo->ed == 0) BNDDelete(nbnd, bndind, bndptr, i); /* Update the degrees of adjacent vertices */ for (j=xadj[i]; j<xadj[i+1]; j++) { ii = adjncy[j]; me = where[ii]; myrinfo = graph->rinfo+ii; if (myrinfo->edegrees == NULL) { myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; } myedegrees = myrinfo->edegrees; ASSERT(CheckRInfo(myrinfo)); oldgain = (myrinfo->ed-myrinfo->id); if (me == from) { INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); if (myrinfo->ed > 0 && bndptr[ii] == -1) BNDInsert(nbnd, bndind, bndptr, ii); } else if (me == to) { INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); if (myrinfo->ed == 0 && bndptr[ii] != -1) BNDDelete(nbnd, bndind, bndptr, ii); } /* Remove contribution from the .ed of 'from' */ if (me != from) { for (k=0; k<myrinfo->ndegrees; k++) { if (myedegrees[k].pid == from) { if (myedegrees[k].ed == adjwgt[j]) myedegrees[k] = myedegrees[--myrinfo->ndegrees]; else myedegrees[k].ed -= adjwgt[j]; break; } } } /* Add contribution to the .ed of 'to' */ if (me != to) { for (k=0; k<myrinfo->ndegrees; k++) { if (myedegrees[k].pid == to) { myedegrees[k].ed += adjwgt[j]; break; } } if (k == myrinfo->ndegrees) { myedegrees[myrinfo->ndegrees].pid = to; myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; } } /* Update the queue */ if (me == to || me == from) { gain = myrinfo->ed-myrinfo->id; if (moved[ii] == 2) { if (myrinfo->ed > 0) PQueueUpdate(&queue, ii, oldgain, gain); else { PQueueDelete(&queue, ii, oldgain); moved[ii] = -1; } } else if (moved[ii] == -1 && myrinfo->ed > 0) { PQueueInsert(&queue, ii, gain); moved[ii] = 2; } } ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); ASSERT(CheckRInfo(myrinfo)); } nmoves++; } graph->nbnd = nbnd; IFSET(ctrl->dbglvl, DBG_REFINE, printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d\n", pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut)); } PQueueFree(ctrl, &queue); idxwspacefree(ctrl, nparts); idxwspacefree(ctrl, nparts); idxwspacefree(ctrl, nparts); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); }
/************************************************************************* * This function performs an edge-based FM refinement **************************************************************************/ void MocGeneral2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor) { int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, me, limit, tmp, cnum; idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind; idxtype *moved, *swaps, *perm, *qnum; float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal; PQueueType parts[MAXNCON][2]; int higain, oldgain, mincut, newcut, mincutorder; int qsizes[MAXNCON][2]; nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; nvwgt = graph->nvwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; id = graph->id; ed = graph->ed; npwgts = graph->npwgts; bndptr = graph->bndptr; bndind = graph->bndind; moved = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); qnum = idxwspacemalloc(ctrl, nvtxs); limit = amin(amax(0.01*nvtxs, 15), 100); /* Initialize the queues */ for (i=0; i<ncon; i++) { PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1); PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1); qsizes[i][0] = qsizes[i][1] = 0; } for (i=0; i<nvtxs; i++) { qnum[i] = samax(ncon, nvwgt+i*ncon); qsizes[qnum[i]][where[i]]++; } /* printf("Weight Distribution: \t"); for (i=0; i<ncon; i++) printf(" [%d %d]", qsizes[i][0], qsizes[i][1]); printf("\n"); */ for (from=0; from<2; from++) { for (j=0; j<ncon; j++) { if (qsizes[j][from] == 0) { for (i=0; i<nvtxs; i++) { if (where[i] != from) continue; k = samax2(ncon, nvwgt+i*ncon); if (k == j && qsizes[qnum[i]][from] > qsizes[j][from] && nvwgt[i*ncon+qnum[i]] < 1.3*nvwgt[i*ncon+j]) { qsizes[qnum[i]][from]--; qsizes[j][from]++; qnum[i] = j; } } } } } /* printf("Weight Distribution (after):\t "); for (i=0; i<ncon; i++) printf(" [%d %d]", qsizes[i][0], qsizes[i][1]); printf("\n"); */ for (i=0; i<ncon; i++) mindiff[i] = fabs(tpwgts[0]-npwgts[i]); minbal = origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); newcut = mincut = graph->mincut; mincutorder = -1; if (ctrl->dbglvl&DBG_REFINE) { printf("Parts: ["); for (l=0; l<ncon; l++) printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal); } idxset(nvtxs, -1, moved); ASSERT(ComputeCut(graph, where) == graph->mincut); ASSERT(CheckBnd(graph)); /* Insert all nodes in the priority queues */ nbnd = graph->nbnd; RandomPermute(nvtxs, perm, 1); for (ii=0; ii<nvtxs; ii++) { i = perm[ii]; PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]); } for (nswaps=0; nswaps<nvtxs; nswaps++) { if (minbal < lbfactor) break; SelectQueue(ncon, npwgts, tpwgts, &from, &cnum, parts); to = (from+1)%2; if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1) break; saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); newcut -= (ed[higain]-id[higain]); newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts); if (newbal < minbal || (newbal == minbal && (newcut < mincut || (newcut == mincut && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) { mincut = newcut; minbal = newbal; mincutorder = nswaps; for (i=0; i<ncon; i++) mindiff[i] = fabs(tpwgts[0]-npwgts[i]); } else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ newcut += (ed[higain]-id[higain]); saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1); saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); break; } where[higain] = to; moved[higain] = nswaps; swaps[nswaps] = higain; if (ctrl->dbglvl&DBG_MOVEINFO) { printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut); for (l=0; l<ncon; l++) printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); printf(", %.3f LB: %.3f\n", minbal, newbal); } /************************************************************** * Update the id[i]/ed[i] values of the affected nodes ***************************************************************/ SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); if (ed[higain] > 0 && bndptr[higain] == -1) BNDInsert(nbnd, bndind, bndptr, higain); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; oldgain = ed[k]-id[k]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); /* Update the queue position */ if (moved[k] == -1) PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]); /* Update its boundary information */ if (ed[k] == 0 && bndptr[k] != -1) BNDDelete(nbnd, bndind, bndptr, k); else if (ed[k] > 0 && bndptr[k] == -1) BNDInsert(nbnd, bndind, bndptr, k); } } /**************************************************************** * Roll back computations *****************************************************************/ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; to = where[higain] = (where[higain]+1)%2; SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); else if (ed[higain] > 0 && bndptr[higain] == -1) BNDInsert(nbnd, bndind, bndptr, higain); saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1); saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); if (bndptr[k] != -1 && ed[k] == 0) BNDDelete(nbnd, bndind, bndptr, k); if (bndptr[k] == -1 && ed[k] > 0) BNDInsert(nbnd, bndind, bndptr, k); } } if (ctrl->dbglvl&DBG_REFINE) { printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd); for (l=0; l<ncon; l++) printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]); printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts)); } graph->mincut = mincut; graph->nbnd = nbnd; for (i=0; i<ncon; i++) { PQueueFree(ctrl, &parts[i][0]); PQueueFree(ctrl, &parts[i][1]); } idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); }
/************************************************************************* * This function performs an edge-based FM refinement **************************************************************************/ void FM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, int *tpwgts, int npasses) { int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, limit, tmp; idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; idxtype *moved, *swaps, *perm; PQueueType parts[2]; int higain, oldgain, mincut, mindiff, origdiff, initcut, newcut, mincutorder, avgvwgt; nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; id = graph->id; ed = graph->ed; pwgts = graph->pwgts; bndptr = graph->bndptr; bndind = graph->bndind; moved = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); limit = amin(amax(0.01*nvtxs, 15), 100); avgvwgt = amin((pwgts[0]+pwgts[1])/20, 2*(pwgts[0]+pwgts[1])/nvtxs); tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; PQueueInit(ctrl, &parts[0], nvtxs, tmp); PQueueInit(ctrl, &parts[1], nvtxs, tmp); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d\n", pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); origdiff = abs(tpwgts[0]-pwgts[0]); idxset(nvtxs, -1, moved); for (pass=0; pass<npasses; pass++) { /* Do a number of passes */ PQueueReset(&parts[0]); PQueueReset(&parts[1]); mincutorder = -1; newcut = mincut = initcut = graph->mincut; mindiff = abs(tpwgts[0]-pwgts[0]); ASSERT(ComputeCut(graph, where) == graph->mincut); ASSERT(CheckBnd(graph)); /* Insert boundary nodes in the priority queues */ nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; ii<nbnd; ii++) { i = perm[ii]; ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0); ASSERT(bndptr[bndind[i]] != -1); PQueueInsert(&parts[where[bndind[i]]], bndind[i], ed[bndind[i]]-id[bndind[i]]); } for (nswaps=0; nswaps<nvtxs; nswaps++) { from = (tpwgts[0]-pwgts[0] < tpwgts[1]-pwgts[1] ? 0 : 1); to = (from+1)%2; if ((higain = PQueueGetMax(&parts[from])) == -1) break; ASSERT(bndptr[higain] != -1); newcut -= (ed[higain]-id[higain]); INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); if ((newcut < mincut && abs(tpwgts[0]-pwgts[0]) <= origdiff+avgvwgt) || (newcut == mincut && abs(tpwgts[0]-pwgts[0]) < mindiff)) { mincut = newcut; mindiff = abs(tpwgts[0]-pwgts[0]); mincutorder = nswaps; } else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */ newcut += (ed[higain]-id[higain]); INC_DEC(pwgts[from], pwgts[to], vwgt[higain]); break; } where[higain] = to; moved[higain] = nswaps; swaps[nswaps] = higain; IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], newcut, pwgts[0], pwgts[1])); /************************************************************** * Update the id[i]/ed[i] values of the affected nodes ***************************************************************/ SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; oldgain = ed[k]-id[k]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); /* Update its boundary information and queue position */ if (bndptr[k] != -1) { /* If k was a boundary vertex */ if (ed[k] == 0) { /* Not a boundary vertex any more */ BNDDelete(nbnd, bndind, bndptr, k); if (moved[k] == -1) /* Remove it if in the queues */ PQueueDelete(&parts[where[k]], k, oldgain); } else { /* If it has not been moved, update its position in the queue */ if (moved[k] == -1) PQueueUpdate(&parts[where[k]], k, oldgain, ed[k]-id[k]); } } else { if (ed[k] > 0) { /* It will now become a boundary vertex */ BNDInsert(nbnd, bndind, bndptr, k); if (moved[k] == -1) PQueueInsert(&parts[where[k]], k, ed[k]-id[k]); } } } } /**************************************************************** * Roll back computations *****************************************************************/ for (i=0; i<nswaps; i++) moved[swaps[i]] = -1; /* reset moved array */ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; to = where[higain] = (where[higain]+1)%2; SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); else if (ed[higain] > 0 && bndptr[higain] == -1) BNDInsert(nbnd, bndind, bndptr, higain); INC_DEC(pwgts[to], pwgts[(to+1)%2], vwgt[higain]); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); if (bndptr[k] != -1 && ed[k] == 0) BNDDelete(nbnd, bndind, bndptr, k); if (bndptr[k] == -1 && ed[k] > 0) BNDInsert(nbnd, bndind, bndptr, k); } } IFSET(ctrl->dbglvl, DBG_REFINE, printf("\tMinimum cut: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); graph->mincut = mincut; graph->nbnd = nbnd; if (mincutorder == -1 || mincut == initcut) break; } PQueueFree(ctrl, &parts[0]); PQueueFree(ctrl, &parts[1]); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); }
/************************************************************************* * This function performs k-way refinement **************************************************************************/ void Random_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor) { int i, ii, iii, j, jj, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees; int from, me, to, oldcut, vwgt, gain; idxtype *xadj, *adjncy, *adjwgt; idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; EDegreeType *myedegrees; RInfoType *myrinfo; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; bndptr = graph->bndptr; bndind = graph->bndind; where = graph->where; pwgts = graph->pwgts; /* Setup the weight intervals of the various subdomains */ minwgt = idxwspacemalloc(ctrl, nparts); maxwgt = idxwspacemalloc(ctrl, nparts); itpwgts = idxwspacemalloc(ctrl, nparts); tvwgt = idxsum(nparts, pwgts); ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt)); for (i=0; i<nparts; i++) { itpwgts[i] = tpwgts[i]*tvwgt; maxwgt[i] = tpwgts[i]*tvwgt*ubfactor; minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor); } perm = idxwspacemalloc(ctrl, nvtxs); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n", pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0], 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd, graph->mincut)); for (pass=0; pass<npasses; pass++) { ASSERT(ComputeCut(graph, where) == graph->mincut); oldcut = graph->mincut; nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (nmoves=iii=0; iii<graph->nbnd; iii++) { ii = perm[iii]; if (ii >= nbnd) continue; i = bndind[ii]; myrinfo = graph->rinfo+i; if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */ from = where[i]; vwgt = graph->vwgt[i]; if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) continue; /* This cannot be moved! */ myedegrees = myrinfo->edegrees; myndegrees = myrinfo->ndegrees; j = myrinfo->id; for (k=0; k<myndegrees; k++) { to = myedegrees[k].pid; gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */ if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0) break; } if (k == myndegrees) continue; /* break out if you did not find a candidate */ for (j=k+1; j<myndegrees; j++) { to = myedegrees[j].pid; if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) || (myedegrees[j].ed == myedegrees[k].ed && itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])) k = j; } to = myedegrees[k].pid; j = 0; if (myedegrees[k].ed-myrinfo->id > 0) j = 1; else if (myedegrees[k].ed-myrinfo->id == 0) { if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) j = 1; } if (j == 0) continue; /*===================================================================== * If we got here, we can now move the vertex from 'from' to 'to' *======================================================================*/ graph->mincut -= myedegrees[k].ed-myrinfo->id; IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut)); /* Update where, weight, and ID/ED information of the vertex you moved */ where[i] = to; INC_DEC(pwgts[to], pwgts[from], vwgt); myrinfo->ed += myrinfo->id-myedegrees[k].ed; SWAP(myrinfo->id, myedegrees[k].ed, j); if (myedegrees[k].ed == 0) myedegrees[k] = myedegrees[--myrinfo->ndegrees]; else myedegrees[k].pid = from; if (myrinfo->ed-myrinfo->id < 0) BNDDelete(nbnd, bndind, bndptr, i); /* Update the degrees of adjacent vertices */ for (j=xadj[i]; j<xadj[i+1]; j++) { ii = adjncy[j]; me = where[ii]; myrinfo = graph->rinfo+ii; if (myrinfo->edegrees == NULL) { myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii]; } myedegrees = myrinfo->edegrees; ASSERT(CheckRInfo(myrinfo)); if (me == from) { INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]); if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1) BNDInsert(nbnd, bndind, bndptr, ii); } else if (me == to) { INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]); if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1) BNDDelete(nbnd, bndind, bndptr, ii); } /* Remove contribution from the .ed of 'from' */ if (me != from) { for (k=0; k<myrinfo->ndegrees; k++) { if (myedegrees[k].pid == from) { if (myedegrees[k].ed == adjwgt[j]) myedegrees[k] = myedegrees[--myrinfo->ndegrees]; else myedegrees[k].ed -= adjwgt[j]; break; } } } /* Add contribution to the .ed of 'to' */ if (me != to) { for (k=0; k<myrinfo->ndegrees; k++) { if (myedegrees[k].pid == to) { myedegrees[k].ed += adjwgt[j]; break; } } if (k == myrinfo->ndegrees) { myedegrees[myrinfo->ndegrees].pid = to; myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; } } ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]); ASSERT(CheckRInfo(myrinfo)); } nmoves++; } } graph->nbnd = nbnd; IFSET(ctrl->dbglvl, DBG_REFINE, printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n", pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], 1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, ComputeVolume(graph, where))); if (graph->mincut == oldcut) break; } idxwspacefree(ctrl, nparts); idxwspacefree(ctrl, nparts); idxwspacefree(ctrl, nparts); idxwspacefree(ctrl, nvtxs); }
/************************************************************************* * This function projects a partition, and at the same time computes the * parameters for refinement. **************************************************************************/ void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) { int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees; idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; idxtype *cmap, *where, *bndptr, *bndind; idxtype *cwhere; GraphType *cgraph; RInfoType *crinfo, *rinfo, *myrinfo; EDegreeType *myedegrees; idxtype *htable; cgraph = graph->coarser; cwhere = cgraph->where; crinfo = cgraph->rinfo; nvtxs = graph->nvtxs; cmap = graph->cmap; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; adjwgtsum = graph->adjwgtsum; AllocateKWayPartitionMemory(ctrl, graph, nparts); where = graph->where; rinfo = graph->rinfo; bndind = graph->bndind; bndptr = idxset(nvtxs, -1, graph->bndptr); /* Go through and project partition and compute id/ed for the nodes */ for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; cmap[i] = crinfo[k].ed; /* For optimization */ } htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); ctrl->wspace.cdegree = 0; for (nbnd=0, i=0; i<nvtxs; i++) { me = where[i]; myrinfo = rinfo+i; myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; myrinfo->edegrees = NULL; myrinfo->id = adjwgtsum[i]; if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */ istart = xadj[i]; iend = xadj[i+1]; myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += iend-istart; ndegrees = 0; for (j=istart; j<iend; j++) { other = where[adjncy[j]]; if (me != other) { myrinfo->ed += adjwgt[j]; if ((k = htable[other]) == -1) { htable[other] = ndegrees; myedegrees[ndegrees].pid = other; myedegrees[ndegrees++].ed = adjwgt[j]; } else { myedegrees[k].ed += adjwgt[j]; } } } myrinfo->id -= myrinfo->ed; /* Remove space for edegrees if it was interior */ if (myrinfo->ed == 0) { myrinfo->edegrees = NULL; ctrl->wspace.cdegree -= iend-istart; } else { if (myrinfo->ed-myrinfo->id >= 0) BNDInsert(nbnd, bndind, bndptr, i); myrinfo->ndegrees = ndegrees; for (j=0; j<ndegrees; j++) htable[myedegrees[j].pid] = -1; } } } idxcopy(nparts, cgraph->pwgts, graph->pwgts); graph->mincut = cgraph->mincut; graph->nbnd = nbnd; FreeGraph(graph->coarser); graph->coarser = NULL; idxwspacefree(ctrl, nparts); ASSERT(CheckBnd2(graph)); }
/************************************************************************* * This function computes the initial id/ed **************************************************************************/ void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) { int i, j, k, l, nvtxs, nbnd, mincut, me, other; idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr; RInfoType *rinfo, *myrinfo; EDegreeType *myedegrees; nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; pwgts = idxset(nparts, 0, graph->pwgts); bndind = graph->bndind; bndptr = idxset(nvtxs, -1, graph->bndptr); rinfo = graph->rinfo; /*------------------------------------------------------------ / Compute now the id/ed degrees /------------------------------------------------------------*/ ctrl->wspace.cdegree = 0; nbnd = mincut = 0; for (i=0; i<nvtxs; i++) { me = where[i]; pwgts[me] += vwgt[i]; myrinfo = rinfo+i; myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0; myrinfo->edegrees = NULL; for (j=xadj[i]; j<xadj[i+1]; j++) { if (me != where[adjncy[j]]) myrinfo->ed += adjwgt[j]; } myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed; if (myrinfo->ed > 0) mincut += myrinfo->ed; if (myrinfo->ed-myrinfo->id >= 0) BNDInsert(nbnd, bndind, bndptr, i); /* Time to compute the particular external degrees */ if (myrinfo->ed > 0) { myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; for (j=xadj[i]; j<xadj[i+1]; j++) { other = where[adjncy[j]]; if (me != other) { for (k=0; k<myrinfo->ndegrees; k++) { if (myedegrees[k].pid == other) { myedegrees[k].ed += adjwgt[j]; break; } } if (k == myrinfo->ndegrees) { myedegrees[myrinfo->ndegrees].pid = other; myedegrees[myrinfo->ndegrees++].ed = adjwgt[j]; } } } ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); } } graph->mincut = mincut/2; graph->nbnd = nbnd; }
void Compute2WayPartitionParams(ctrl_t *ctrl, graph_t *graph) { idx_t i, j, nvtxs, ncon, nbnd, mincut, istart, iend, tid, ted, me; idx_t *xadj, *vwgt, *adjncy, *adjwgt, *pwgts; idx_t *where, *bndptr, *bndind, *id, *ed; nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; id = graph->id; ed = graph->ed; pwgts = iset(2*ncon, 0, graph->pwgts); bndptr = iset(nvtxs, -1, graph->bndptr); bndind = graph->bndind; /* Compute pwgts */ if (ncon == 1) { for (i=0; i<nvtxs; i++) { ASSERT(where[i] >= 0 && where[i] <= 1); pwgts[where[i]] += vwgt[i]; } ASSERT(pwgts[0]+pwgts[1] == graph->tvwgt[0]); } else { for (i=0; i<nvtxs; i++) { me = where[i]; for (j=0; j<ncon; j++) pwgts[me*ncon+j] += vwgt[i*ncon+j]; } } /* Compute the required info for refinement */ for (nbnd=0, mincut=0, i=0; i<nvtxs; i++) { istart = xadj[i]; iend = xadj[i+1]; me = where[i]; tid = ted = 0; for (j=istart; j<iend; j++) { if (me == where[adjncy[j]]) tid += adjwgt[j]; else ted += adjwgt[j]; } id[i] = tid; ed[i] = ted; if (ted > 0 || istart == iend) { BNDInsert(nbnd, bndind, bndptr, i); mincut += ted; } } graph->mincut = mincut/2; graph->nbnd = nbnd; }
void Project2WayPartition(ctrl_t *ctrl, graph_t *graph) { idx_t i, j, istart, iend, nvtxs, nbnd, me, tid, ted; idx_t *xadj, *adjncy, *adjwgt; idx_t *cmap, *where, *bndptr, *bndind; idx_t *cwhere, *cbndptr; idx_t *id, *ed; graph_t *cgraph; Allocate2WayPartitionMemory(ctrl, graph); cgraph = graph->coarser; cwhere = cgraph->where; cbndptr = cgraph->bndptr; nvtxs = graph->nvtxs; cmap = graph->cmap; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; id = graph->id; ed = graph->ed; bndptr = iset(nvtxs, -1, graph->bndptr); bndind = graph->bndind; /* Project the partition and record which of these nodes came from the coarser boundary */ for (i=0; i<nvtxs; i++) { j = cmap[i]; where[i] = cwhere[j]; cmap[i] = cbndptr[j]; } /* Compute the refinement information of the nodes */ for (nbnd=0, i=0; i<nvtxs; i++) { istart = xadj[i]; iend = xadj[i+1]; tid = ted = 0; if (cmap[i] == -1) { /* Interior node. Note that cmap[i] = cbndptr[cmap[i]] */ for (j=istart; j<iend; j++) tid += adjwgt[j]; } else { /* Potentially an interface node */ me = where[i]; for (j=istart; j<iend; j++) { if (me == where[adjncy[j]]) tid += adjwgt[j]; else ted += adjwgt[j]; } } id[i] = tid; ed[i] = ted; if (ted > 0 || istart == iend) BNDInsert(nbnd, bndind, bndptr, i); } graph->mincut = cgraph->mincut; graph->nbnd = nbnd; /* copy pwgts */ icopy(2*graph->ncon, cgraph->pwgts, graph->pwgts); FreeGraph(&graph->coarser); graph->coarser = NULL; }
/************************************************************************* * This function balances two partitions by moving boundary nodes * from the domain that is overweight to the one that is underweight. **************************************************************************/ void Bnd2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts) { int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, tmp; idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts; idxtype *moved, *perm; PQueueType parts; int higain, oldgain, mincut, mindiff; nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; id = graph->id; ed = graph->ed; pwgts = graph->pwgts; bndptr = graph->bndptr; bndind = graph->bndind; moved = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); /* Determine from which domain you will be moving data */ mindiff = abs(tpwgts[0]-pwgts[0]); from = (pwgts[0] < tpwgts[0] ? 1 : 0); to = (from+1)%2; IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n", pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]; PQueueInit(ctrl, &parts, nvtxs, tmp); idxset(nvtxs, -1, moved); ASSERT(ComputeCut(graph, where) == graph->mincut); ASSERT(CheckBnd(graph)); /* Insert the boundary nodes of the proper partition whose size is OK in the priority queue */ nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; ii<nbnd; ii++) { i = perm[ii]; ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0); ASSERT(bndptr[bndind[i]] != -1); if (where[bndind[i]] == from && vwgt[bndind[i]] <= mindiff) PQueueInsert(&parts, bndind[i], ed[bndind[i]]-id[bndind[i]]); } mincut = graph->mincut; for (nswaps=0; nswaps<nvtxs; nswaps++) { if ((higain = PQueueGetMax(&parts)) == -1) break; ASSERT(bndptr[higain] != -1); if (pwgts[to]+vwgt[higain] > tpwgts[to]) break; mincut -= (ed[higain]-id[higain]); INC_DEC(pwgts[to], pwgts[from], vwgt[higain]); where[higain] = to; moved[higain] = nswaps; IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1])); /************************************************************** * Update the id[i]/ed[i] values of the affected nodes ***************************************************************/ SWAP(id[higain], ed[higain], tmp); if (ed[higain] == 0 && xadj[higain] < xadj[higain+1]) BNDDelete(nbnd, bndind, bndptr, higain); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; oldgain = ed[k]-id[k]; kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]); INC_DEC(id[k], ed[k], kwgt); /* Update its boundary information and queue position */ if (bndptr[k] != -1) { /* If k was a boundary vertex */ if (ed[k] == 0) { /* Not a boundary vertex any more */ BNDDelete(nbnd, bndind, bndptr, k); if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) /* Remove it if in the queues */ PQueueDelete(&parts, k, oldgain); } else { /* If it has not been moved, update its position in the queue */ if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]); } } else { if (ed[k] > 0) { /* It will now become a boundary vertex */ BNDInsert(nbnd, bndind, bndptr, k); if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) PQueueInsert(&parts, k, ed[k]-id[k]); } } } } IFSET(ctrl->dbglvl, DBG_REFINE, printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd)); graph->mincut = mincut; graph->nbnd = nbnd; PQueueFree(ctrl, &parts); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); }