/* * 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.1 1998/11/27 17:59:17 karypis Exp $ */ #include /************************************************************************* * This function is the entry point of refinement **************************************************************************/ void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor) { int i, nlevels, mustfree=0; GraphType *ptr; IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr)); /* Compute the parameters of the coarsest graph */ ComputeKWayPartitionParams(ctrl, graph, nparts); /* Take care any non-contiguity */ IFSET(ctrl->dbglvl, DBG_TIME, starttimer(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, stoptimer(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, starttimer(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, 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)); 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, stoptimer(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, starttimer(ctrl->AuxTmr2)); EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr2)); if (mustfree) GKfree(&graph->vwgt, &graph->adjwgt, LTERM); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr)); } /************************************************************************* * This function allocates memory for k-way edge refinement **************************************************************************/ void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts) { int nvtxs, pad64; nvtxs = graph->nvtxs; pad64 = (3*nvtxs+nparts)%2; graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata"); graph->pwgts = graph->rdata; graph->where = graph->rdata + nparts; graph->bndptr = graph->rdata + nvtxs + nparts; graph->bndind = graph->rdata + 2*nvtxs + nparts; graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64); /* if (ctrl->wspace.edegrees != NULL) free(ctrl->wspace.edegrees); ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateKWayPartitionMemory: edegrees"); */ } /************************************************************************* * 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; iid = myrinfo->ed = myrinfo->ndegrees = 0; myrinfo->edegrees = NULL; for (j=xadj[i]; jed += 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]; jndegrees; 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, 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; iwspace.cdegree = 0; for (nbnd=0, i=0; iid = 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; jed += 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; jpwgts, graph->pwgts); graph->mincut = cgraph->mincut; graph->nbnd = nbnd; FreeGraph(graph->coarser); graph->coarser = NULL; idxwspacefree(ctrl, nparts); ASSERT(CheckBnd2(graph)); } /************************************************************************* * This function checks if the partition weights are within the balance * contraints **************************************************************************/ int IsBalanced(idxtype *pwgts, int nparts, float *tpwgts, float ubfactor) { int i, j, tvwgt; tvwgt = idxsum(nparts, pwgts); for (i=0; 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, 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; irinfo[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, 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; irinfo[i].ed > 0) BNDInsert(nbnd, bndind, bndptr, i); } graph->nbnd = nbnd; }