481 lines
15 KiB
C
481 lines
15 KiB
C
/*
|
|
* Copyright 1997, Regents of the University of Minnesota
|
|
*
|
|
* kwayrefine.c
|
|
*
|
|
* This file contains the driving routines for multilevel k-way refinement
|
|
*
|
|
* Started 7/28/97
|
|
* George
|
|
*
|
|
* $Id: kwayrefine.c,v 1.5 2003/04/01 05:09:37 karypis Exp $
|
|
*/
|
|
|
|
#include <metislib.h>
|
|
|
|
|
|
/*************************************************************************
|
|
* This function is the entry point of refinement
|
|
**************************************************************************/
|
|
void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, idxtype nparts, float *tpwgts, float ubfactor)
|
|
{
|
|
idxtype i, nlevels, mustfree=0;
|
|
GraphType *ptr;
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr));
|
|
|
|
/* Compute the parameters of the coarsest graph */
|
|
ComputeKWayPartitionParams(ctrl, graph, nparts);
|
|
|
|
|
|
/* Take care any non-contiguity */
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->AuxTmr1));
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
|
|
EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
|
|
EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
|
|
EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
|
|
}
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->AuxTmr1));
|
|
|
|
/* Determine how many levels are there */
|
|
for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);
|
|
|
|
for (i=0; ;i++) {
|
|
/* PrintSubDomainGraph(graph, nparts, graph->where); */
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN && (i == nlevels/2 || i == nlevels/2+1))
|
|
EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->RefTmr));
|
|
|
|
if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) {
|
|
ComputeKWayBalanceBoundary(ctrl, graph, nparts);
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN)
|
|
Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1);
|
|
else
|
|
Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1);
|
|
ComputeKWayBoundary(ctrl, graph, nparts);
|
|
}
|
|
|
|
switch (ctrl->RType) {
|
|
case RTYPE_KWAYRANDOM:
|
|
Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
|
|
break;
|
|
case RTYPE_KWAYGREEDY:
|
|
Greedy_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10);
|
|
break;
|
|
case RTYPE_KWAYRANDOM_MCONN:
|
|
Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
|
|
break;
|
|
}
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->RefTmr));
|
|
|
|
if (graph == orggraph)
|
|
break;
|
|
|
|
graph = graph->finer;
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->ProjectTmr));
|
|
if (graph->vwgt == NULL) {
|
|
graph->vwgt = idxsmalloc(graph->nvtxs, 1, "RefineKWay: graph->vwgt");
|
|
graph->adjwgt = idxsmalloc(graph->nedges, 1, "RefineKWay: graph->adjwgt");
|
|
mustfree = 1;
|
|
}
|
|
ProjectKWayPartition(ctrl, graph, nparts);
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr));
|
|
}
|
|
|
|
if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) {
|
|
ComputeKWayBalanceBoundary(ctrl, graph, nparts);
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
|
|
Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8);
|
|
Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
|
|
}
|
|
else {
|
|
Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8);
|
|
Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
|
|
}
|
|
}
|
|
|
|
/* Take care any trivial non-contiguity */
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->AuxTmr2));
|
|
EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor);
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->AuxTmr2));
|
|
|
|
if (mustfree)
|
|
gk_free((void **)&graph->vwgt, &graph->adjwgt, LTERM);
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr));
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* This function is the entry point of refinement
|
|
**************************************************************************/
|
|
void RefineKWayRefinement(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, idxtype nparts, float *tpwgts, float ubfactor)
|
|
{
|
|
idxtype i, nlevels, mustfree=0;
|
|
GraphType *ptr;
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr));
|
|
|
|
/* Compute the parameters of the coarsest graph */
|
|
ComputeKWayPartitionParams(ctrl, graph, nparts);
|
|
|
|
|
|
#ifdef XXXX
|
|
/* Take care any non-contiguity */
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->AuxTmr1));
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
|
|
EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
|
|
EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
|
|
EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
|
|
}
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->AuxTmr1));
|
|
#endif
|
|
|
|
/* Determine how many levels are there */
|
|
for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);
|
|
|
|
for (i=0; ;i++) {
|
|
#ifdef XXXX
|
|
/* PrintSubDomainGraph(graph, nparts, graph->where); */
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN && (i == nlevels/2 || i == nlevels/2+1))
|
|
EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->RefTmr));
|
|
#endif
|
|
|
|
if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) {
|
|
ComputeKWayBalanceBoundary(ctrl, graph, nparts);
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN)
|
|
Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1);
|
|
else
|
|
Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1);
|
|
ComputeKWayBoundary(ctrl, graph, nparts);
|
|
}
|
|
|
|
switch (ctrl->RType) {
|
|
case RTYPE_KWAYRANDOM:
|
|
Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
|
|
break;
|
|
case RTYPE_KWAYGREEDY:
|
|
Greedy_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10);
|
|
break;
|
|
case RTYPE_KWAYRANDOM_MCONN:
|
|
Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
|
|
break;
|
|
}
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->RefTmr));
|
|
|
|
if (graph == orggraph)
|
|
break;
|
|
|
|
graph = graph->finer;
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->ProjectTmr));
|
|
if (graph->vwgt == NULL) {
|
|
graph->vwgt = idxsmalloc(graph->nvtxs, 1, "RefineKWay: graph->vwgt");
|
|
graph->adjwgt = idxsmalloc(graph->nedges, 1, "RefineKWay: graph->adjwgt");
|
|
mustfree = 1;
|
|
}
|
|
ProjectKWayPartition(ctrl, graph, nparts);
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr));
|
|
}
|
|
|
|
if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) {
|
|
ComputeKWayBalanceBoundary(ctrl, graph, nparts);
|
|
if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
|
|
Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8);
|
|
Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
|
|
}
|
|
else {
|
|
Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8);
|
|
Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
|
|
}
|
|
}
|
|
|
|
/* Take care any trivial non-contiguity */
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->AuxTmr2));
|
|
EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor);
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->AuxTmr2));
|
|
|
|
if (mustfree)
|
|
gk_free((void **)&graph->vwgt, &graph->adjwgt, LTERM);
|
|
|
|
IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr));
|
|
}
|
|
|
|
/*************************************************************************
|
|
* This function allocates memory for k-way edge refinement
|
|
**************************************************************************/
|
|
void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, idxtype nparts)
|
|
{
|
|
idxtype nvtxs;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
|
|
graph->pwgts = idxmalloc(nparts, "AllocateKWayPartitionMemory: pwgts");
|
|
graph->where = idxmalloc(nvtxs, "AllocateKWayPartitionMemory: pwgts");
|
|
graph->bndptr = idxmalloc(nvtxs, "AllocateKWayPartitionMemory: pwgts");
|
|
graph->bndind = idxmalloc(nvtxs, "AllocateKWayPartitionMemory: pwgts");
|
|
graph->rinfo = (RInfoType *)gk_malloc(nvtxs*sizeof(RInfoType), "AllocateKWayPartitionMemory: rinfo");
|
|
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* This function computes the initial id/ed
|
|
**************************************************************************/
|
|
void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, idxtype nparts)
|
|
{
|
|
idxtype 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* This function projects a partition, and at the same time computes the
|
|
* parameters for refinement.
|
|
**************************************************************************/
|
|
void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, idxtype nparts)
|
|
{
|
|
idxtype 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, 1);
|
|
graph->coarser = NULL;
|
|
|
|
idxwspacefree(ctrl, nparts);
|
|
|
|
ASSERT(CheckBnd2(graph));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* This function checks if the partition weights are within the balance
|
|
* contraints
|
|
**************************************************************************/
|
|
idxtype IsBalanced(idxtype *pwgts, idxtype nparts, float *tpwgts, float ubfactor)
|
|
{
|
|
idxtype i, j, tvwgt;
|
|
|
|
tvwgt = idxsum(nparts, pwgts, 1);
|
|
for (i=0; i<nparts; i++) {
|
|
if (pwgts[i] > tpwgts[i]*tvwgt*(ubfactor+0.005))
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* This function computes the boundary definition for balancing
|
|
**************************************************************************/
|
|
void ComputeKWayBoundary(CtrlType *ctrl, GraphType *graph, idxtype nparts)
|
|
{
|
|
idxtype i, nvtxs, nbnd;
|
|
idxtype *bndind, *bndptr;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
bndind = graph->bndind;
|
|
bndptr = idxset(nvtxs, -1, graph->bndptr);
|
|
|
|
|
|
/*------------------------------------------------------------
|
|
/ Compute the new boundary
|
|
/------------------------------------------------------------*/
|
|
nbnd = 0;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (graph->rinfo[i].ed-graph->rinfo[i].id >= 0)
|
|
BNDInsert(nbnd, bndind, bndptr, i);
|
|
}
|
|
|
|
graph->nbnd = nbnd;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* This function computes the boundary definition for balancing
|
|
**************************************************************************/
|
|
void ComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, idxtype nparts)
|
|
{
|
|
idxtype i, nvtxs, nbnd;
|
|
idxtype *bndind, *bndptr;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
bndind = graph->bndind;
|
|
bndptr = idxset(nvtxs, -1, graph->bndptr);
|
|
|
|
|
|
/*------------------------------------------------------------
|
|
/ Compute the new boundary
|
|
/------------------------------------------------------------*/
|
|
nbnd = 0;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (graph->rinfo[i].ed > 0)
|
|
BNDInsert(nbnd, bndind, bndptr, i);
|
|
}
|
|
|
|
graph->nbnd = nbnd;
|
|
}
|
|
|