/* * Copyright 1997, Regents of the University of Minnesota * * kwayvolrefine.c * * This file contains the driving routines for multilevel k-way refinement * * Started 7/28/97 * George * * $Id: kwayvolrefine.c,v 1.2 1998/11/30 16:13:57 karypis Exp $ */ #include /************************************************************************* * This function is the entry point of refinement **************************************************************************/ void RefineVolKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor) { int i, nlevels; GraphType *ptr; IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); /* Take care any non-contiguity */ if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) { ComputeVolKWayPartitionParams(ctrl, graph, nparts); EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25); EliminateVolSubDomainEdges(ctrl, graph, nparts, tpwgts); EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25); } /* Determine how many levels are there */ for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); /* Compute the parameters of the coarsest graph */ ComputeVolKWayPartitionParams(ctrl, graph, nparts); for (i=0; ;i++) { /*PrintSubDomainGraph(graph, nparts, graph->where);*/ MALLOC_CHECK(NULL); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr)); if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) { ComputeVolKWayBalanceBoundary(ctrl, graph, nparts); switch (ctrl->RType) { case RTYPE_KWAYRANDOM: Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1); break; case RTYPE_KWAYRANDOM_MCONN: Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1); break; } ComputeVolKWayBoundary(ctrl, graph, nparts); } switch (ctrl->RType) { case RTYPE_KWAYRANDOM: Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); break; case RTYPE_KWAYRANDOM_MCONN: Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); break; } IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr)); if (graph == orggraph) break; GKfree(&graph->gdata, LTERM); /* Deallocate the graph related arrays */ graph = graph->finer; IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr)); ProjectVolKWayPartition(ctrl, graph, nparts); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr)); } if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) { ComputeVolKWayBalanceBoundary(ctrl, graph, nparts); switch (ctrl->RType) { case RTYPE_KWAYRANDOM: Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8); Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); break; case RTYPE_KWAYRANDOM_MCONN: Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8); Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0); break; } } EliminateVolComponents(ctrl, graph, nparts, tpwgts, ubfactor); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); } /************************************************************************* * This function allocates memory for k-way edge refinement **************************************************************************/ void AllocateVolKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) { int nvtxs, pad64; nvtxs = graph->nvtxs; pad64 = (3*nvtxs+nparts)%2; graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(VRInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateVolKWayPartitionMemory: rdata"); graph->pwgts = graph->rdata; graph->where = graph->rdata + nparts; graph->bndptr = graph->rdata + nvtxs + nparts; graph->bndind = graph->rdata + 2*nvtxs + nparts; graph->vrinfo = (VRInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64); } /************************************************************************* * This function computes the initial id/ed **************************************************************************/ void ComputeVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts) { int i, ii, j, k, kk, l, nvtxs, nbnd, mincut, minvol, me, other, pid; idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where; VRInfoType *rinfo, *myrinfo, *orinfo; VEDegreeType *myedegrees, *oedegrees; nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; pwgts = idxset(nparts, 0, graph->pwgts); rinfo = graph->vrinfo; /*------------------------------------------------------------ / Compute now the id/ed degrees /------------------------------------------------------------*/ ctrl->wspace.cdegree = 0; mincut = 0; for (i=0; iid = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0; myrinfo->edegrees = NULL; for (j=xadj[i]; jid += adjwgt[j]; myrinfo->nid++; } } myrinfo->ed = graph->adjwgtsum[i] - myrinfo->id; mincut += myrinfo->ed; /* Time to compute the particular external degrees */ if (myrinfo->ed > 0) { myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += xadj[i+1]-xadj[i]; for (j=xadj[i]; jndegrees; k++) { if (myedegrees[k].pid == other) { myedegrees[k].ed += adjwgt[j]; myedegrees[k].ned++; break; } } if (k == myrinfo->ndegrees) { myedegrees[myrinfo->ndegrees].gv = 0; myedegrees[myrinfo->ndegrees].pid = other; myedegrees[myrinfo->ndegrees].ed = adjwgt[j]; myedegrees[myrinfo->ndegrees++].ned = 1; } } } ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]); } } graph->mincut = mincut/2; ComputeKWayVolGains(ctrl, graph, nparts); } /************************************************************************* * This function computes the initial id/ed **************************************************************************/ void ComputeKWayVolGains(CtrlType *ctrl, GraphType *graph, int nparts) { int i, ii, j, k, kk, l, nvtxs, me, other, pid, myndegrees; idxtype *xadj, *vsize, *adjncy, *adjwgt, *where, *bndind, *bndptr, *ophtable; VRInfoType *rinfo, *myrinfo, *orinfo; VEDegreeType *myedegrees, *oedegrees; nvtxs = graph->nvtxs; xadj = graph->xadj; vsize = graph->vsize; adjncy = graph->adjncy; adjwgt = graph->adjwgt; where = graph->where; bndind = graph->bndind; bndptr = idxset(nvtxs, -1, graph->bndptr); rinfo = graph->vrinfo; ophtable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts)); /*------------------------------------------------------------ / Compute now the iv/ev degrees /------------------------------------------------------------*/ graph->minvol = graph->nbnd = 0; for (i=0; igv = -MAXIDX; if (myrinfo->ndegrees > 0) { me = where[i]; myedegrees = myrinfo->edegrees; myndegrees = myrinfo->ndegrees; graph->minvol += myndegrees*vsize[i]; for (j=xadj[i]; jedegrees; for (k=0; kndegrees; k++) ophtable[oedegrees[k].pid] = k; ophtable[other] = 1; /* this is to simplify coding */ if (me == other) { /* Find which domains 'i' is connected and 'ii' is not and update their gain */ for (k=0; kndegrees; kk++) ophtable[oedegrees[kk].pid] = -1; ophtable[other] = -1; } /* Compute the max vgain */ for (k=0; k myrinfo->gv) myrinfo->gv = myedegrees[k].gv; } } if (myrinfo->ed > 0 && myrinfo->id == 0) myrinfo->gv += vsize[i]; if (myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) BNDInsert(graph->nbnd, bndind, bndptr, i); } idxwspacefree(ctrl, nparts); } /************************************************************************* * This function projects a partition, and at the same time computes the * parameters for refinement. **************************************************************************/ void ProjectVolKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts) { int i, j, k, nvtxs, me, other, istart, iend, ndegrees; idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum; idxtype *cmap, *where; idxtype *cwhere; GraphType *cgraph; VRInfoType *crinfo, *rinfo, *myrinfo; VEDegreeType *myedegrees; idxtype *htable; cgraph = graph->coarser; cwhere = cgraph->where; crinfo = cgraph->vrinfo; nvtxs = graph->nvtxs; cmap = graph->cmap; xadj = graph->xadj; adjncy = graph->adjncy; adjwgt = graph->adjwgt; adjwgtsum = graph->adjwgtsum; AllocateVolKWayPartitionMemory(ctrl, graph, nparts); where = graph->where; rinfo = graph->vrinfo; /* Go through and project partition and compute id/ed for the nodes */ for (i=0; iwspace.cdegree = 0; for (i=0; iid = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0; myrinfo->edegrees = NULL; myrinfo->id = adjwgtsum[i]; myrinfo->nid = xadj[i+1]-xadj[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.vedegrees+ctrl->wspace.cdegree; ctrl->wspace.cdegree += iend-istart; ndegrees = 0; for (j=istart; jed += adjwgt[j]; myrinfo->nid--; if ((k = htable[other]) == -1) { htable[other] = ndegrees; myedegrees[ndegrees].gv = 0; myedegrees[ndegrees].pid = other; myedegrees[ndegrees].ed = adjwgt[j]; myedegrees[ndegrees++].ned = 1; } else { myedegrees[k].ed += adjwgt[j]; myedegrees[k].ned++; } } } 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 { myrinfo->ndegrees = ndegrees; for (j=0; jpwgts, graph->pwgts); graph->mincut = cgraph->mincut; FreeGraph(graph->coarser); graph->coarser = NULL; idxwspacefree(ctrl, nparts); } /************************************************************************* * This function computes the boundary definition for balancing **************************************************************************/ void ComputeVolKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts) { int 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; ivrinfo[i].gv >=0 || graph->vrinfo[i].ed-graph->vrinfo[i].id >= 0) BNDInsert(nbnd, bndind, bndptr, i); } graph->nbnd = nbnd; } /************************************************************************* * This function computes the boundary definition for balancing **************************************************************************/ void ComputeVolKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts) { int 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; ivrinfo[i].ed > 0) BNDInsert(nbnd, bndind, bndptr, i); } graph->nbnd = nbnd; }