/* * Copyright 1997, Regents of the University of Minnesota * * sfm.c * * This file contains code that implementes an FM-based separator refinement * * Started 8/1/97 * George * * $Id: sfm.c,v 1.1 1998/11/27 17:59:30 karypis Exp $ * */ #include /************************************************************************* * This function performs a node-based FM refinement **************************************************************************/ void FM_2WayNodeRefine(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) { int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; idxtype *mptr, *mind, *moved, *swaps, *perm; PQueueType parts[2]; NRInfoType *rinfo; int higain, oldgain, mincut, initcut, mincutorder; int pass, to, other, limit; int badmaxpwgt, mindiff, newdiff; int u[2], g[2]; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; rinfo = graph->nrinfo; i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); PQueueInit(ctrl, &parts[0], nvtxs, i); PQueueInit(ctrl, &parts[1], nvtxs, i); moved = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); mptr = idxwspacemalloc(ctrl, nvtxs+1); mind = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); for (pass=0; passmincut; nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; iioflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); /****************************************************** * Get into the FM loop *******************************************************/ mptr[0] = nmind = 0; mindiff = abs(pwgts[0]-pwgts[1]); to = (pwgts[0] < pwgts[1] ? 0 : 1); for (nswaps=0; nswaps g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */ if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) to = (to+1)%2; } else if (u[0] == -1 && u[1] == -1) { break; } else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) { to = 0; } else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) { to = 1; } else break; other = (to+1)%2; higain = PQueueGetMax(&parts[to]); if (moved[higain] == -1) /* Delete if it was in the separator originally */ PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); ASSERT(bndptr[higain] != -1); pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { mincut = pwgts[2]; mincutorder = nswaps; mindiff = newdiff; } else { if (nswaps - mincutorder > limit) { pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); break; /* No further improvement, break out */ } } BNDDelete(nbnd, bndind, bndptr, higain); pwgts[to] += vwgt[higain]; where[higain] = to; moved[higain] = nswaps; swaps[nswaps] = higain; /********************************************************** * Update the degrees of the affected nodes ***********************************************************/ for (j=xadj[higain]; jdbglvl, DBG_MOVEINFO, printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); } /**************************************************************** * Roll back computation *****************************************************************/ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; ASSERT(CheckNodePartitionParams(graph)); to = where[higain]; other = (to+1)%2; INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); where[higain] = 2; BNDInsert(nbnd, bndind, bndptr, higain); edegrees = rinfo[higain].edegrees; edegrees[0] = edegrees[1] = 0; for (j=xadj[higain]; jdbglvl, DBG_REFINE, printf("\tMinimum sep: %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+1); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); } /************************************************************************* * This function performs a node-based FM refinement **************************************************************************/ void FM_2WayNodeRefine2(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) { int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; idxtype *mptr, *mind, *moved, *swaps, *perm; PQueueType parts[2]; NRInfoType *rinfo; int higain, oldgain, mincut, initcut, mincutorder; int pass, to, other, limit; int badmaxpwgt, mindiff, newdiff; int u[2], g[2]; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; rinfo = graph->nrinfo; i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); PQueueInit(ctrl, &parts[0], nvtxs, i); PQueueInit(ctrl, &parts[1], nvtxs, i); moved = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); mptr = idxwspacemalloc(ctrl, nvtxs+1); mind = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); for (pass=0; passmincut; nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; iioflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); /****************************************************** * Get into the FM loop *******************************************************/ mptr[0] = nmind = 0; mindiff = abs(pwgts[0]-pwgts[1]); to = (pwgts[0] < pwgts[1] ? 0 : 1); for (nswaps=0; nswaps g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */ if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) to = (to+1)%2; } else if (u[0] == -1 && u[1] == -1) { break; } else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) { to = 0; } else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) { to = 1; } else break; other = (to+1)%2; higain = PQueueGetMax(&parts[to]); if (moved[higain] == -1) /* Delete if it was in the separator originally */ PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); ASSERT(bndptr[higain] != -1); pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { mincut = pwgts[2]; mincutorder = nswaps; mindiff = newdiff; } else { if (nswaps - mincutorder > limit) { pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); break; /* No further improvement, break out */ } } BNDDelete(nbnd, bndind, bndptr, higain); pwgts[to] += vwgt[higain]; where[higain] = to; moved[higain] = nswaps; swaps[nswaps] = higain; /********************************************************** * Update the degrees of the affected nodes ***********************************************************/ for (j=xadj[higain]; jdbglvl, DBG_MOVEINFO, printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); } /**************************************************************** * Roll back computation *****************************************************************/ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; ASSERT(CheckNodePartitionParams(graph)); to = where[higain]; other = (to+1)%2; INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); where[higain] = 2; BNDInsert(nbnd, bndind, bndptr, higain); edegrees = rinfo[higain].edegrees; edegrees[0] = edegrees[1] = 0; for (j=xadj[higain]; jdbglvl, DBG_REFINE, printf("\tMinimum sep: %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+1); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); } /************************************************************************* * This function performs a node-based FM refinement **************************************************************************/ void FM_2WayNodeRefineEqWgt(CtrlType *ctrl, GraphType *graph, int npasses) { int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; idxtype *mptr, *mind, *moved, *swaps, *perm; PQueueType parts[2]; NRInfoType *rinfo; int higain, oldgain, mincut, initcut, mincutorder; int pass, to, other, limit; int mindiff, newdiff; int u[2], g[2]; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; rinfo = graph->nrinfo; i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt); PQueueInit(ctrl, &parts[0], nvtxs, i); PQueueInit(ctrl, &parts[1], nvtxs, i); moved = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); mptr = idxwspacemalloc(ctrl, nvtxs+1); mind = idxwspacemalloc(ctrl, nvtxs); perm = idxwspacemalloc(ctrl, nvtxs); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); for (pass=0; passmincut; nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; iioflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); /****************************************************** * Get into the FM loop *******************************************************/ mptr[0] = nmind = 0; mindiff = abs(pwgts[0]-pwgts[1]); to = (pwgts[0] < pwgts[1] ? 0 : 1); for (nswaps=0; nswaps g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); } } other = (to+1)%2; if ((higain = PQueueGetMax(&parts[to])) == -1) break; if (moved[higain] == -1) /* Delete if it was in the separator originally */ PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]); ASSERT(bndptr[higain] != -1); pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { mincut = pwgts[2]; mincutorder = nswaps; mindiff = newdiff; } else { if (nswaps - mincutorder > limit) { pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); break; /* No further improvement, break out */ } } BNDDelete(nbnd, bndind, bndptr, higain); pwgts[to] += vwgt[higain]; where[higain] = to; moved[higain] = nswaps; swaps[nswaps] = higain; /********************************************************** * Update the degrees of the affected nodes ***********************************************************/ for (j=xadj[higain]; jdbglvl, DBG_MOVEINFO, printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2])); } /**************************************************************** * Roll back computation *****************************************************************/ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; ASSERT(CheckNodePartitionParams(graph)); to = where[higain]; other = (to+1)%2; INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); where[higain] = 2; BNDInsert(nbnd, bndind, bndptr, higain); edegrees = rinfo[higain].edegrees; edegrees[0] = edegrees[1] = 0; for (j=xadj[higain]; jdbglvl, DBG_REFINE, printf("\tMinimum sep: %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+1); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); } /************************************************************************* * This function performs a node-based FM refinement. This is the * one-way version **************************************************************************/ void FM_2WayNodeRefine_OneSided(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses) { int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind; idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; idxtype *mptr, *mind, *swaps, *perm; PQueueType parts; NRInfoType *rinfo; int higain, oldgain, mincut, initcut, mincutorder; int pass, to, other, limit; int badmaxpwgt, mindiff, newdiff; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; rinfo = graph->nrinfo; PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt)); perm = idxwspacemalloc(ctrl, nvtxs); swaps = idxwspacemalloc(ctrl, nvtxs); mptr = idxwspacemalloc(ctrl, nvtxs); mind = idxwspacemalloc(ctrl, nvtxs+1); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions-N1: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2); to = (pwgts[0] < pwgts[1] ? 1 : 0); for (pass=0; passmincut; nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; iioflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300)); /****************************************************** * Get into the FM loop *******************************************************/ mptr[0] = nmind = 0; mindiff = abs(pwgts[0]-pwgts[1]); for (nswaps=0; nswaps badmaxpwgt) break; /* No point going any further. Balance will be bad */ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { mincut = pwgts[2]; mincutorder = nswaps; mindiff = newdiff; } else { if (nswaps - mincutorder > limit) { pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); break; /* No further improvement, break out */ } } BNDDelete(nbnd, bndind, bndptr, higain); pwgts[to] += vwgt[higain]; where[higain] = to; swaps[nswaps] = higain; /********************************************************** * Update the degrees of the affected nodes ***********************************************************/ for (j=xadj[higain]; jdbglvl, DBG_MOVEINFO, printf("Moved %6d to %3d, Gain: %5d [%5d] \t[%5d %5d %5d] [%3d %2d]\n", higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit)); } /**************************************************************** * Roll back computation *****************************************************************/ for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; ASSERT(CheckNodePartitionParams(graph)); ASSERT(where[higain] == to); INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); where[higain] = 2; BNDInsert(nbnd, bndind, bndptr, higain); edegrees = rinfo[higain].edegrees; edegrees[0] = edegrees[1] = 0; for (j=xadj[higain]; jdbglvl, DBG_REFINE, printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); graph->mincut = mincut; graph->nbnd = nbnd; if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut)) break; } PQueueFree(ctrl, &parts); idxwspacefree(ctrl, nvtxs+1); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); } /************************************************************************* * This function performs a node-based FM refinement **************************************************************************/ void FM_2WayNodeBalance(CtrlType *ctrl, GraphType *graph, float ubfactor) { int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps; idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; idxtype *perm, *moved; PQueueType parts; NRInfoType *rinfo; int higain, oldgain; int pass, to, other; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; rinfo = graph->nrinfo; if (abs(pwgts[0]-pwgts[1]) < (int)((ubfactor-1.0)*(pwgts[0]+pwgts[1]))) return; if (abs(pwgts[0]-pwgts[1]) < 3*idxsum(nvtxs, vwgt)/nvtxs) return; to = (pwgts[0] < pwgts[1] ? 0 : 1); other = (to+1)%2; PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt)); perm = idxwspacemalloc(ctrl, nvtxs); moved = idxset(nvtxs, -1, idxwspacemalloc(ctrl, nvtxs)); IFSET(ctrl->dbglvl, DBG_REFINE, printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d [B]\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); nbnd = graph->nbnd; RandomPermute(nbnd, perm, 1); for (ii=0; iidbglvl, DBG_MOVEINFO, printf("Moved %6d to %3d, Gain: %3d, \t[%5d %5d %5d]\n", higain, to, vwgt[higain]-rinfo[higain].edegrees[other], pwgts[0], pwgts[1], pwgts[2])); /********************************************************** * Update the degrees of the affected nodes ***********************************************************/ for (j=xadj[higain]; j pwgts[other]) break; } IFSET(ctrl->dbglvl, DBG_REFINE, printf("\tBalanced sep: %6d at %4d, PWGTS: [%6d %6d], NBND: %6d\n", pwgts[2], nswaps, pwgts[0], pwgts[1], nbnd)); graph->mincut = pwgts[2]; graph->nbnd = nbnd; PQueueFree(ctrl, &parts); idxwspacefree(ctrl, nvtxs); idxwspacefree(ctrl, nvtxs); } /************************************************************************* * This function computes the maximum possible gain for a vertex **************************************************************************/ int ComputeMaxNodeGain(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt) { int i, j, k, max; max = 0; for (j=xadj[0]; j