552 lines
19 KiB
C
552 lines
19 KiB
C
/*
|
|
* Copyright 1997, Regents of the University of Minnesota
|
|
*
|
|
* kfmetis.c
|
|
*
|
|
* This file contains the top level routines for computing a k-way partitioning
|
|
* that also balances the fill-in.
|
|
*
|
|
* Started 8/12/02
|
|
* George
|
|
*
|
|
*/
|
|
|
|
#include <metislib.h>
|
|
|
|
|
|
/*************************************************************************
|
|
* This function is the entry point for KFMETIS
|
|
**************************************************************************/
|
|
void METIS_PartFillGraph(idxtype *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
|
|
idxtype *adjwgt, idxtype *wgtflag, idxtype *numflag, idxtype *nparts,
|
|
idxtype *options, idxtype *edgecut, idxtype *part)
|
|
{
|
|
idxtype i, j;
|
|
GraphType graph;
|
|
CtrlType ctrl;
|
|
|
|
/* Compute an initial k-way partitioning of the graph */
|
|
METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
|
|
options, edgecut, part);
|
|
|
|
/*-----------------------------------------------------------------------
|
|
* Internalize the graph and allocate memory for the workspace
|
|
*-----------------------------------------------------------------------*/
|
|
if (*numflag == 1)
|
|
Change2CNumbering(*nvtxs, xadj, adjncy);
|
|
|
|
SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag);
|
|
|
|
if (options[0] == 0) { /* Use the default parameters */
|
|
ctrl.CType = KMETIS_CTYPE;
|
|
ctrl.IType = KMETIS_ITYPE;
|
|
ctrl.RType = KMETIS_RTYPE;
|
|
ctrl.dbglvl = KMETIS_DBGLVL;
|
|
}
|
|
else {
|
|
ctrl.CType = options[OPTION_CTYPE];
|
|
ctrl.IType = options[OPTION_ITYPE];
|
|
ctrl.RType = options[OPTION_RTYPE];
|
|
ctrl.dbglvl = options[OPTION_DBGLVL];
|
|
}
|
|
ctrl.optype = OP_KMETIS;
|
|
ctrl.CoarsenTo = amax((*nvtxs)/(40*gk_log2(*nparts)), 20*(*nparts));
|
|
ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt, 1) : (*nvtxs))/ctrl.CoarsenTo);
|
|
|
|
InitRandom(-1);
|
|
|
|
AllocateWorkSpace(&ctrl, &graph, *nparts);
|
|
|
|
|
|
/*-----------------------------------------------------------------------
|
|
* Balance the fill-in
|
|
*-----------------------------------------------------------------------*/
|
|
BalanceFillIn(&ctrl, &graph, *nparts, part);
|
|
|
|
|
|
*edgecut = ComputeCut(&graph, part);
|
|
|
|
/*-----------------------------------------------------------------------
|
|
* Post-process the results
|
|
*-----------------------------------------------------------------------*/
|
|
FreeWorkSpace(&ctrl, &graph);
|
|
|
|
if (*numflag == 1)
|
|
Change2FNumbering(*nvtxs, xadj, adjncy, part);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* This function is the top-level routine of the fill-balancing code
|
|
***************************************************************************/
|
|
void BalanceFillIn(CtrlType *ctrl, GraphType *graph, idxtype nparts, idxtype *part)
|
|
{
|
|
idxtype i, j, k, nvtxs, options[10];
|
|
idxtype *fills, *subfills, *ssize, *spart, *vmap, *ppart, *vimap;
|
|
idxtype oldavg, oldmax, oldcut, oldmaxcut, newavg, newmax, newcut, newmaxcut;
|
|
idxtype *tssize;
|
|
float diff, alpha;
|
|
GraphType *pgraph;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
|
|
fills = idxsmalloc(nparts, 0, "BalanceFillIn: fills");
|
|
subfills = idxsmalloc(2*nparts, 0, "BalanceFillIn: subfills");
|
|
ssize = idxsmalloc(nparts, 0, "BalanceFillIn: ssize");
|
|
tssize = idxsmalloc(nparts, 0, "BalanceFillIn: tssize");
|
|
|
|
spart = idxmalloc(nvtxs, "BalanceFillIn: spart");
|
|
ppart = idxmalloc(nvtxs, "BalanceFillIn: ppart");
|
|
vmap = idxmalloc(nvtxs, "BalanceFillIn: vmap");
|
|
vimap = idxmalloc(nvtxs, "BalanceFillIn: vimap");
|
|
|
|
/* Go and compute a top-level vertex separator for each partition */
|
|
for (i=0; i<nparts; i++) {
|
|
pgraph = ExtractPartitionGraph(graph, part, i, vmap, vimap);
|
|
|
|
options[0] = 0;
|
|
options[7] = -1;
|
|
METIS_NodeComputeSeparator(&(pgraph->nvtxs), pgraph->xadj, pgraph->adjncy, pgraph->vwgt,
|
|
pgraph->adjwgt, options, &ssize[i], ppart);
|
|
|
|
|
|
/* Copy the separator and partition information to the global graph's spart vector */
|
|
for (j=0; j<pgraph->nvtxs; j++)
|
|
spart[vimap[j]] = ppart[j];
|
|
|
|
FreeGraph(pgraph, 1);
|
|
}
|
|
|
|
|
|
/* Go and compute the fill-ins of each partition */
|
|
for (i=0; i<nparts; i++)
|
|
ComputePartitionFillIn(ctrl, graph, nparts, part, spart, i, &fills[i], &subfills[2*i]);
|
|
|
|
oldavg = idxsum(nparts, fills, 1)/nparts;
|
|
oldmax = fills[idxargmax(nparts, fills)];
|
|
oldcut = ComputeCut(graph, part);
|
|
oldmaxcut = ComputeMaxCut(graph, nparts, part);
|
|
|
|
mprintf("AverageFill: %10D, MaxFill: %10D, LoadImbalance: %.3f, EdgeCut: %5D, MaxCut: %5D\n",
|
|
oldavg, oldmax, 1.0*oldmax/oldavg, oldcut, oldmaxcut);
|
|
|
|
/* Determine the target separator sizes of the domains that are above average */
|
|
for (i=0; i<nparts; i++) {
|
|
if (fills[i] < 1.05*oldavg) {
|
|
tssize[i] = ssize[i];
|
|
}
|
|
else {
|
|
if (oldavg - (subfills[2*i] +subfills[2*i+1])< 0) {
|
|
tssize[i] = ssize[i]/5.0;
|
|
mprintf("* %2D %7D %7D %6D %6D\n", i, fills[i], subfills[2*i]+subfills[2*i+1], ssize[i], tssize[i]);
|
|
}
|
|
else {
|
|
alpha = sqrt(fills[i] - (subfills[2*i]+subfills[2*i+1]))/ssize[i];
|
|
tssize[i] = sqrt(oldavg - (subfills[2*i]+subfills[2*i+1]))/alpha;
|
|
mprintf("< %2D %7D %7D %6D %6D\n", i, fills[i], subfills[2*i]+subfills[2*i+1], ssize[i], tssize[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Perform a simple greedy refinement */
|
|
RefineTopLevelSeparators(ctrl, graph, nparts, part, spart, fills, subfills, ssize, tssize);
|
|
|
|
/* Go and compute the fill-ins of each partition */
|
|
for (i=0; i<nparts; i++)
|
|
ComputePartitionFillIn(ctrl, graph, nparts, part, spart, i, &fills[i], &subfills[2*i]);
|
|
|
|
for (i=0; i<nparts; i++) {
|
|
if (tssize[i] < ssize[i])
|
|
mprintf("%3D %6D %6D %8D\n", i, ssize[i], tssize[i], fills[i]);
|
|
}
|
|
|
|
newavg = idxsum(nparts, fills, 1)/nparts;
|
|
newmax = fills[idxargmax(nparts, fills)];
|
|
newcut = ComputeCut(graph, part);
|
|
newmaxcut = ComputeMaxCut(graph, nparts, part);
|
|
|
|
mprintf("AverageFill: %10D, MaxFill: %10D, LoadImbalance: %.3f, EdgeCut: %5D, MaxCut: %5D\n",
|
|
newavg, newmax, 1.0*newmax/newavg, newcut, newmaxcut);
|
|
|
|
mprintf("Effective Load Imbalance: %.3f, Sum Fill/Comm Ratio: %6.2f, Max Fill/Comm Ratio: %6.2f\n",
|
|
1.0*newmax/oldavg, 1.0*(oldmax-newmax)/(newcut-oldcut), 1.0*(oldmax-newmax)/(newmaxcut-oldmaxcut));
|
|
|
|
gk_free((void **)&fills, &subfills, &ssize, &spart, &ppart, &vmap, &vimap, LTERM);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* This function computes a fill-reducing ordering for a particular
|
|
* partition, whose top-level separator is provided as input
|
|
**************************************************************************/
|
|
void ComputePartitionFillIn(CtrlType *ctrl, GraphType *graph, idxtype nparts,
|
|
idxtype *part, idxtype *spart, idxtype pid, idxtype *r_fill,
|
|
idxtype *r_subfill)
|
|
{
|
|
idxtype i, j, k, pnvtxs, options[10], numflag=0;
|
|
idxtype *vmap, *vimap, *ppart, *iperm;
|
|
idxtype *lvmap, *lvimap, *rvmap, *rvimap, *lperm, *liperm, *rperm, *riperm;
|
|
GraphType *pgraph, *lgraph, *rgraph;
|
|
|
|
/* Extract the partition graph */
|
|
vmap = idxmalloc(graph->nvtxs, "ComputePartitionFillIn: vmap");
|
|
vimap = idxmalloc(graph->nvtxs, "ComputePartitionFillIn: vimap");
|
|
|
|
pgraph = ExtractPartitionGraph(graph, part, pid, vmap, vimap);
|
|
|
|
pnvtxs = pgraph->nvtxs;
|
|
|
|
iperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: iperm");
|
|
ppart = idxmalloc(pnvtxs, "ComputePartitionFillIn: ppart");
|
|
|
|
lvmap = idxmalloc(pnvtxs, "ComputePartitionFillIn: lvmap");
|
|
lvimap = idxmalloc(pnvtxs, "ComputePartitionFillIn: lvimap");
|
|
rvmap = idxmalloc(pnvtxs, "ComputePartitionFillIn: rvmap");
|
|
rvimap = idxmalloc(pnvtxs, "ComputePartitionFillIn: rvimap");
|
|
lperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: liperm");
|
|
liperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: liperm");
|
|
rperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: riperm");
|
|
riperm = idxmalloc(pnvtxs, "ComputePartitionFillIn: riperm");
|
|
|
|
|
|
/* project down the separator-partition */
|
|
for (i=0; i<pnvtxs; i++)
|
|
ppart[i] = spart[vimap[i]];
|
|
|
|
/* Check to see if the separators are indeed separators */
|
|
for (i=0; i<pnvtxs; i++) {
|
|
for (j=pgraph->xadj[i]; j<pgraph->xadj[i+1]; j++) {
|
|
if (ppart[i] != ppart[pgraph->adjncy[j]]) {
|
|
if (!(ppart[i] == 2 || ppart[pgraph->adjncy[j]] == 2))
|
|
mprintf("Error: %D %D %D\n", i, ppart[i], ppart[pgraph->adjncy[j]]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
lgraph = ExtractPartitionGraph(pgraph, ppart, 0, lvmap, lvimap);
|
|
rgraph = ExtractPartitionGraph(pgraph, ppart, 1, rvmap, rvimap);
|
|
|
|
options[0] = 1;
|
|
options[1] = 3;
|
|
options[2] = 1;
|
|
options[3] = 1;
|
|
options[4] = 0;
|
|
options[5] = 0;
|
|
options[6] = 0;
|
|
options[7] = 4;
|
|
METIS_NodeND(&lgraph->nvtxs, lgraph->xadj, lgraph->adjncy, &numflag, options, lperm, liperm);
|
|
METIS_NodeND(&rgraph->nvtxs, rgraph->xadj, rgraph->adjncy, &numflag, options, rperm, riperm);
|
|
|
|
/* Put the ordering together */
|
|
for (i=0; i<lgraph->nvtxs; i++)
|
|
iperm[lvimap[i]] = liperm[i];
|
|
for (i=0; i<rgraph->nvtxs; i++)
|
|
iperm[rvimap[i]] = lgraph->nvtxs + riperm[i];
|
|
|
|
for (j=lgraph->nvtxs+rgraph->nvtxs, i=0; i<pnvtxs; i++) {
|
|
if (ppart[i] == 2)
|
|
iperm[i] = j++;
|
|
}
|
|
|
|
|
|
*r_fill = ComputeFillIn2(pgraph, iperm);
|
|
r_subfill[0] = ComputeFillIn2(lgraph, liperm);
|
|
r_subfill[1] = ComputeFillIn2(rgraph, riperm);
|
|
|
|
mprintf("%4D %5D %5D %5D %10D %10D %10D\n", pid, pnvtxs-lgraph->nvtxs-rgraph->nvtxs,
|
|
lgraph->nvtxs, rgraph->nvtxs, r_subfill[0], r_subfill[1], *r_fill);
|
|
|
|
FreeGraph(pgraph, 1);
|
|
FreeGraph(lgraph, 1);
|
|
FreeGraph(rgraph, 1);
|
|
|
|
gk_free((void **)&vmap, &vimap, &iperm, &ppart, &lvmap, &lvimap, &rvmap, &rvimap,
|
|
&lperm, &liperm, &rperm, &riperm, LTERM);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* This function extracts the graph of a partition and returns it.
|
|
**************************************************************************/
|
|
GraphType *ExtractPartitionGraph(GraphType *graph, idxtype *part, idxtype pid,
|
|
idxtype *vmap, idxtype *vimap)
|
|
{
|
|
idxtype i, j, k, nvtxs, pnvtxs, pnedges;
|
|
idxtype *xadj, *adjncy, *vwgt, *adjwgt;
|
|
idxtype *pxadj, *padjncy, *pvwgt, *padjwgt;
|
|
GraphType *pgraph;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
vwgt = graph->vwgt;
|
|
adjwgt = graph->adjwgt;
|
|
|
|
|
|
/* Determine the size of the partition graph */
|
|
for (pnvtxs=pnedges=0, i=0; i<nvtxs; i++) {
|
|
if (part[i] != pid)
|
|
continue;
|
|
|
|
vmap[i] = pnvtxs;
|
|
vimap[pnvtxs] = i;
|
|
pnvtxs++;
|
|
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
if (part[adjncy[j]] == pid)
|
|
pnedges++;
|
|
}
|
|
}
|
|
|
|
|
|
/* Allocate memory for the partition graph */
|
|
pgraph = CreateGraph();
|
|
pgraph->nvtxs = pnvtxs;
|
|
pgraph->nedges = pnedges;
|
|
|
|
pxadj = pgraph->xadj = idxmalloc(pnvtxs+1, "ExtractPartitionGraph: xadj");
|
|
pvwgt = pgraph->vwgt = idxmalloc(pnvtxs, "ExtractPartitionGraph: vwgt");
|
|
padjncy = pgraph->adjncy = idxmalloc(pnedges, "ExtractPartitionGraph: adjncy");
|
|
padjwgt = pgraph->adjwgt = idxmalloc(pnedges, "ExtractPartitionGraph: adjwgt");
|
|
pgraph->adjwgtsum = idxmalloc(pnvtxs, "ExtractPartitionGraph: adjwgtsum");
|
|
pgraph->cmap = idxmalloc(pnvtxs, "ExtractPartitionGraph: cmap");
|
|
|
|
|
|
/* Go and extract the partition graph */
|
|
pxadj[0] = pnvtxs = pnedges = 0;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (part[i] != pid)
|
|
continue;
|
|
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
if (part[adjncy[j]] == pid) {
|
|
padjncy[pnedges] = vmap[adjncy[j]];
|
|
padjwgt[pnedges] = adjwgt[j];
|
|
pnedges++;
|
|
}
|
|
}
|
|
pvwgt[pnvtxs] = vwgt[i];
|
|
pxadj[++pnvtxs] = pnedges;
|
|
}
|
|
|
|
return pgraph;
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* This function implements a very simple greedy k-way refinement routine
|
|
* for top level separators
|
|
**************************************************************************/
|
|
void RefineTopLevelSeparators(CtrlType *ctrl, GraphType *graph, idxtype nparts,
|
|
idxtype *part, idxtype *spart, idxtype *fills, idxtype *subfills,
|
|
idxtype *ssizes, idxtype *tssizes)
|
|
{
|
|
idxtype i, ii, j, k, from, to, nvtxs, mincut, ndegrees, pass, avgssize,
|
|
avgfill, id, maxpwgt, maxspwgt, nmoves, avgdegree, nskip[5];
|
|
idxtype *xadj, *adjncy, *vwgt, *adjwgt;
|
|
idxtype *perm, *pwgts, *pdegrees[4], *pmarker, *pids, *spwgts[3];
|
|
float *alphas[3];
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
vwgt = graph->vwgt;
|
|
adjncy = graph->adjncy;
|
|
adjwgt = graph->adjwgt;
|
|
|
|
|
|
pwgts = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pwgts");
|
|
spwgts[0] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: spwgts");
|
|
spwgts[1] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: spwgts");
|
|
spwgts[2] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: spwgts");
|
|
pdegrees[0] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees");
|
|
pdegrees[1] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees");
|
|
pdegrees[2] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees");
|
|
pdegrees[3] = idxsmalloc(nparts, 0, "RefineTopLevelSeparators: pdegrees");
|
|
pmarker = idxsmalloc(nparts, -1, "RefineTopLevelSeparators: pmarker ");
|
|
pids = idxmalloc(nparts, "RefineTopLevelSeparators: pids ");
|
|
perm = idxmalloc(nvtxs, "RefineTopLevelSeparators: perm");
|
|
alphas[0] = gk_fmalloc(nparts, "RefineTopLevelSeparators: alphas[0]");
|
|
alphas[1] = gk_fmalloc(nparts, "RefineTopLevelSeparators: alphas[1]");
|
|
alphas[2] = gk_fmalloc(nparts, "RefineTopLevelSeparators: alphas[2]");
|
|
|
|
mincut = ComputeCut(graph, part);
|
|
|
|
/* Compute partition and separator sizes */
|
|
for (i=0; i<nvtxs; i++) {
|
|
pwgts[part[i]] += vwgt[i];
|
|
spwgts[spart[i]][part[i]] += vwgt[i];
|
|
}
|
|
|
|
/* Estimate the exponents for partition-size-fill approximation */
|
|
for (i=0; i<nparts; i++) {
|
|
alphas[0][i] = log(subfills[2*i])/log(spwgts[0][i]);
|
|
alphas[1][i] = log(subfills[2*i+1])/log(spwgts[1][i]);
|
|
alphas[2][i] = log(fills[i] - (subfills[2*i]+subfills[2*i+1]))/log(ssizes[i]);
|
|
}
|
|
|
|
maxpwgt = (int)((float)((UNBALANCE_FRACTION*idxsum(nparts, pwgts, 1))/nparts));
|
|
maxspwgt = 1.10*(idxsum(nparts, pwgts, 1)-idxsum(nparts, ssizes, 1))/(2.0*nparts);
|
|
|
|
avgssize = idxsum(nparts, ssizes, 1)/nparts;
|
|
avgfill = idxsum(nparts, fills, 1)/nparts;
|
|
avgdegree = xadj[nvtxs]/(1.0*nvtxs);
|
|
|
|
|
|
mprintf("Avgssize: %D, Avgfill: %D, AvgDegree: %D\n", avgssize, avgfill, avgdegree);
|
|
|
|
/*--------------------------------------------------------------------------
|
|
* Go and do the refinement
|
|
*--------------------------------------------------------------------------*/
|
|
for (pass=0; pass<10; pass++) {
|
|
RandomPermute(nvtxs, perm, 1);
|
|
|
|
nskip[0] = nskip[1] = nskip[2] = nskip[3] = nskip[4] = 0;
|
|
for (nmoves=0, ii=0; ii<nvtxs; ii++) {
|
|
i = perm[ii];
|
|
|
|
from = part[i];
|
|
|
|
/* Determine the connectivity of this vertex */
|
|
for (ndegrees=0, j=xadj[i]; j<xadj[i+1]; j++) {
|
|
to = part[adjncy[j]];
|
|
if ((k = pmarker[to]) == -1) {
|
|
pmarker[to] = k = ndegrees++;
|
|
pids[k] = to;
|
|
pdegrees[0][k] = pdegrees[1][k] = pdegrees[2][k] = pdegrees[3][k] = 0;
|
|
}
|
|
|
|
pdegrees[spart[adjncy[j]]][k] += adjwgt[j];
|
|
pdegrees[3][k] += adjwgt[j];
|
|
}
|
|
|
|
id = (pmarker[from] != -1 ? pdegrees[3][pmarker[from]] : 0);
|
|
|
|
if (spart[i] == 2) { /* I'm on the separator */
|
|
for (to=-1, j=0; j<ndegrees; j++) {
|
|
if (pids[j] == from || pwgts[pids[j]]+vwgt[i] > maxpwgt)
|
|
continue;
|
|
|
|
if (fills[pids[j]] > amax(fills[from], avgfill)) {
|
|
nskip[0]++;
|
|
if (tssizes[from] < ssizes[from])
|
|
nskip[2]++;
|
|
continue;
|
|
}
|
|
if (pdegrees[0][j] > 0 && spwgts[0][pids[j]] > maxspwgt)
|
|
continue;
|
|
if (pdegrees[1][j] > 0 && spwgts[1][pids[j]] > maxspwgt)
|
|
continue;
|
|
|
|
if (pdegrees[0][j]*pdegrees[1][j] == 0) { /* will not increase target separator */
|
|
to = (to == -1 || pdegrees[3][to] < pdegrees[3][j] ? j : to);
|
|
}
|
|
}
|
|
|
|
if (to == -1 && tssizes[from] < ssizes[from])
|
|
nskip[1]++;
|
|
|
|
/* See if some of the moves should be skipped */
|
|
if (to != -1 && pdegrees[3][to] < id && tssizes[from] > ssizes[from])
|
|
to = -1;
|
|
|
|
if (to != -1 && pdegrees[3][to] < id && RandomInRange(3) == 0) {
|
|
nskip[3]++;
|
|
to = -1;
|
|
}
|
|
|
|
if (to != -1 && id - pdegrees[3][to] > avgdegree*(0.9+0.07*pass)) {
|
|
nskip[4]++;
|
|
to = -1;
|
|
}
|
|
}
|
|
else { /* I'm not on the separator */
|
|
for (to=-1, j=0; j<ndegrees; j++) {
|
|
if (pids[j] == from || pwgts[pids[j]]+vwgt[i] > maxpwgt)
|
|
continue;
|
|
|
|
if (tssizes[pids[j]] < ssizes[pids[j]])
|
|
continue;
|
|
|
|
if (pdegrees[0][j] > 0 && spwgts[0][pids[j]] > maxspwgt)
|
|
continue;
|
|
if (pdegrees[1][j] > 0 && spwgts[1][pids[j]] > maxspwgt)
|
|
continue;
|
|
|
|
if (pdegrees[0][j]*pdegrees[1][j] == 0) { /* will not increase target separator */
|
|
to = (to == -1 || pdegrees[3][to] < pdegrees[3][j] ? j : to);
|
|
}
|
|
}
|
|
|
|
if (to != -1) {
|
|
if (pdegrees[3][to] < id)
|
|
to = -1;
|
|
else if (pdegrees[3][to] == id && fills[from] < fills[pids[to]] /*pwgts[from] < pwgts[pids[to]]*/)
|
|
to = -1;
|
|
}
|
|
}
|
|
|
|
if (to != -1) {
|
|
/*
|
|
mprintf("%2D. Moving %6D %3D -> %3D, %2D -> %2D, Gain: %+4D, SepFrom: %4D, SepTo: %3D, Cut: %5D, %4D %4D\n",
|
|
pass, i, from, pids[to], spart[i], (pdegrees[0][to] > pdegrees[1][to] ? 0 : 1),
|
|
pdegrees[3][to] - id, ssizes[from], ssizes[pids[to]], mincut, pwgts[from], pwgts[pids[to]]);
|
|
*/
|
|
/* Update the approximations of fill of 'from' */
|
|
if (spart[i] == 2)
|
|
fills[from] -= (pow(ssizes[from], alphas[2][from]) - pow(ssizes[from]-vwgt[i], alphas[2][from]));
|
|
else
|
|
fills[from] -= (pow(spwgts[spart[i]][from], alphas[spart[i]][from]) - pow(spwgts[spart[i]][from]-vwgt[i], alphas[spart[i]][from]));
|
|
|
|
|
|
if (spart[i] == 2)
|
|
ssizes[from] -= vwgt[i];
|
|
|
|
pwgts[from] -= vwgt[i];
|
|
spwgts[spart[i]][from] -= vwgt[i];
|
|
|
|
|
|
part[i] = pids[to];
|
|
spart[i] = (pdegrees[0][to] > pdegrees[1][to] ? 0 : 1);
|
|
|
|
/* Update the approximations of fill of 'to' */
|
|
fills[to] += (pow(spwgts[spart[i]][to]+vwgt[i], alphas[spart[i]][to]) - pow(spwgts[spart[i]][to], alphas[spart[i]][to]));
|
|
|
|
pwgts[pids[to]] += vwgt[i];
|
|
spwgts[spart[i]][pids[to]] += vwgt[i];
|
|
|
|
mincut = mincut - (pdegrees[3][to] - id);
|
|
nmoves++;
|
|
}
|
|
|
|
|
|
/* reset pmarker */
|
|
for (j=xadj[i]; j<xadj[i+1]; j++)
|
|
pmarker[part[adjncy[j]]] = -1;
|
|
}
|
|
|
|
mprintf("%4D. Nmoves: %4D, Cut: %6D [%4D %4D %4D %4D %4D]\n", pass, nmoves, mincut,
|
|
nskip[0], nskip[1], nskip[2], nskip[3], nskip[4]);
|
|
|
|
if (nmoves == 0)
|
|
break;
|
|
}
|
|
|
|
for (i=0; i<nparts; i++)
|
|
mprintf("%4D %6D %8D %8D\n", i, pwgts[i], ssizes[i], fills[i]);
|
|
|
|
mprintf("%D %D %D / %D %D %D / %D %D\n", pwgts[10], spwgts[0][10], spwgts[1][10], pwgts[15], spwgts[0][15], spwgts[1][15], maxpwgt, maxspwgt);
|
|
|
|
gk_free((void **)&pwgts, &pdegrees[0], &pdegrees[1], &pdegrees[2], &pdegrees[3],
|
|
&pmarker, &pids, &perm, &spwgts[0], &spwgts[1], &spwgts[2], &alphas[0],
|
|
&alphas[1], &alphas[2], LTERM);
|
|
}
|