/* * Copyright 1997, Regents of the University of Minnesota * * node_refine.c * * This file contains code that performs the k-way refinement * * Started 3/1/96 * George * * $Id: node_refine.c,v 1.2 2003/07/21 17:18:50 karypis Exp $ */ #include #define PackWeightWhereInfo(a, b) (((a)<<10) + (b)) #define SelectWhere(a) ((a)%1024) #define SelectWeight(a) (((a)>>10)) /************************************************************************* * This function computes the initial id/ed **************************************************************************/ void ComputeNodePartitionParams(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace) { int i, j, nparts, nvtxs, nsep, firstvtx, lastvtx; idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *vwgt, *lpwgts, *gpwgts, *sepind; idxtype *where, *swhere, *rwhere; NRInfoType *rinfo, *myrinfo; int me, other, otherwgt; IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayInitTmr)); nvtxs = graph->nvtxs; nparts = ctrl->nparts; vtxdist = graph->vtxdist; xadj = graph->xadj; ladjncy = graph->adjncy; adjwgt = graph->adjwgt; vwgt = graph->vwgt; where = graph->where; rinfo = graph->nrinfo = (NRInfoType *)GKmalloc(sizeof(NRInfoType)*nvtxs, "ComputeNodePartitionParams: rinfo"); lpwgts = graph->lpwgts = idxsmalloc(2*nparts, 0, "ComputePartitionParams: lpwgts"); gpwgts = graph->gpwgts = idxmalloc(2*nparts, "ComputePartitionParams: gpwgts"); sepind = graph->sepind = idxmalloc(nvtxs, "ComputePartitionParams: sepind"); firstvtx = vtxdist[ctrl->mype]; lastvtx = vtxdist[ctrl->mype+1]; /*------------------------------------------------------------ / Send/Receive the where information of interface vertices. / Also use this to also encode the vwgt information of this / vertex. This is a hack, but it should work for now! /------------------------------------------------------------*/ swhere = wspace->indices; rwhere = where + nvtxs; for (i=0; i= 0 && where[i] < 2*nparts, (ctrl, "%d\n", where[i]) ); where[i] = PackWeightWhereInfo(vwgt[i], where[i]); } CommInterfaceData(ctrl, graph, where, swhere, rwhere); /*------------------------------------------------------------ / Compute now the degrees /------------------------------------------------------------*/ for (nsep=i=0; i= 0 && me < 2*nparts); lpwgts[me] += vwgt[i]; if (me >= nparts) { /* If it is a separator vertex */ sepind[nsep++] = i; lpwgts[2*nparts-1] += vwgt[i]; myrinfo = rinfo+i; myrinfo->edegrees[0] = myrinfo->edegrees[1] = 0; for (j=xadj[i]; jedegrees[other%2] += otherwgt; } } } graph->nsep = nsep; /* Finally, sum-up the partition weights */ MPI_Allreduce((void *)lpwgts, (void *)gpwgts, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm); graph->mincut = gpwgts[2*nparts-1]; #ifdef XX /* Print Weight information */ if (ctrl->mype == 0) { for (i=0; idbglvl, DBG_TIME, stoptimer(ctrl->KWayInitTmr)); } /************************************************************************* * This function performs k-way refinement **************************************************************************/ void KWayNodeRefine(CtrlType *ctrl, GraphType *graph, WorkSpaceType *wspace, int npasses, float ubfraction) { int i, ii, j, k, pass, nvtxs, firstvtx, lastvtx, otherlastvtx, c, nmoves, nlupd, nsupd, nnbrs, nchanged, nsep; int npes = ctrl->npes, mype = ctrl->mype, nparts = ctrl->nparts; idxtype *xadj, *ladjncy, *adjwgt, *vtxdist, *vwgt; idxtype *where, *lpwgts, *gpwgts, *sepind; idxtype *peind, *recvptr, *sendptr; idxtype *update, *supdate, *rupdate, *pe_updates, *htable, *changed; idxtype *badminpwgt, *badmaxpwgt; KeyValueType *swchanges, *rwchanges; int *nupds_pe; NRInfoType *rinfo, *myrinfo; int from, me, other, otherwgt, oldcut; IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->KWayTmr)); nvtxs = graph->nvtxs; vtxdist = graph->vtxdist; xadj = graph->xadj; ladjncy = graph->adjncy; adjwgt = graph->adjwgt; vwgt = graph->vwgt; firstvtx = vtxdist[mype]; lastvtx = vtxdist[mype+1]; where = graph->where; rinfo = graph->nrinfo; lpwgts = graph->lpwgts; gpwgts = graph->gpwgts; nsep = graph->nsep; sepind = graph->sepind; nnbrs = graph->nnbrs; peind = graph->peind; recvptr = graph->recvptr; sendptr = graph->sendptr; changed = idxmalloc(nvtxs, "KWayRefine: changed"); rwchanges = wspace->pairs; swchanges = rwchanges + recvptr[nnbrs]; update = idxmalloc(nvtxs, "KWayRefine: update"); supdate = wspace->indices; rupdate = supdate + recvptr[nnbrs]; nupds_pe = imalloc(npes, "KWayRefine: nupds_pe"); htable = idxsmalloc(nvtxs+graph->nrecv, 0, "KWayRefine: lhtable"); badminpwgt = wspace->pv1; badmaxpwgt = wspace->pv2; for (i=0; idbglvl, DBG_REFINEINFO, PrintNodeBalanceInfo(ctrl, nparts, gpwgts, badminpwgt, badmaxpwgt, 1)); for (pass=0; passmincut; for (c=0; c<2; c++) { for (i=0; i= nparts); /* Go through the loop if gain is possible for the separator vertex */ if (rinfo[i].edegrees[(c+1)%2] <= vwgt[i]) { other = from%nparts+c; /* It is one-sided move so we know where it goes */ if (gpwgts[other]+vwgt[i] > badmaxpwgt[other]) { /* printf("Skip because of weight! %d\n", vwgt[i]-rinfo[i].edegrees[(c+1)%2]); */ continue; /* We cannot move it there because it gets too heavy */ } /* Update where, weight, and ID/ED information of the vertex you moved */ where[i] = PackWeightWhereInfo(vwgt[i], other); /* Remove this vertex from the sepind. Note the trick for looking at the sepind[ii] again */ sepind[ii--] = sepind[--nsep]; /* myprintf(ctrl, "Vertex %d [%d %d] is moving to %d from %d [%d]\n", i+firstvtx, vwgt[i], rinfo[i].edegrees[(c+1)%2], other, from, SelectWhere(where[i])); */ lpwgts[from] -= vwgt[i]; lpwgts[2*nparts-1] -= vwgt[i]; lpwgts[other] += vwgt[i]; gpwgts[other] += vwgt[i]; /* * Put the vertices adjacent to i that belong to either the separator or * the (c+1)%2 partition into the update array */ for (j=xadj[i]; jpexadj[i+1]-graph->pexadj[i] > 0) changed[nchanged++] = i; } } /* myprintf(ctrl, "nmoves: %d, nlupd: %d, nsupd: %d\n", nmoves, nlupd, nsupd); */ /* Tell everybody interested what the new where[] info is for the interface vertices */ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where, swchanges, rwchanges, wspace->pv4); IFSET(ctrl->dbglvl, DBG_RMOVEINFO, rprintf(ctrl, "\t[%d %d], [%d %d %d]\n", pass, c, GlobalSESum(ctrl, nmoves), GlobalSESum(ctrl, nsupd), GlobalSESum(ctrl, nlupd))); /*------------------------------------------------------------- / Time to communicate with processors to send the vertices / whose degrees need to be update. /-------------------------------------------------------------*/ /* Issue the receives first */ for (i=0; icomm, ctrl->rreq+i); } /* Issue the sends next. This needs some preporcessing */ for (i=0; iimap[supdate[i]]; } iidxsort(nsupd, supdate); for (j=i=0; icomm, ctrl->sreq+i); j = k; } /* OK, now get into the loop waiting for the send/recv operations to finish */ MPI_Waitall(nnbrs, ctrl->rreq, ctrl->statuses); for (i=0; istatuses+i, IDX_DATATYPE, nupds_pe+i); MPI_Waitall(nnbrs, ctrl->sreq, ctrl->statuses); /*------------------------------------------------------------- / Place the received to-be updated vertices into update[] /-------------------------------------------------------------*/ for (i=0; ipexadj[i+1]-graph->pexadj[i] > 0) changed[nchanged++] = i; lpwgts[SelectWhere(where[i])] += vwgt[i]; lpwgts[2*nparts-1] += vwgt[i]; /* myprintf(ctrl, "Vertex %d moves into the separator from %d to %d\n", i+firstvtx, me, SelectWhere(where[i])); */ } } /* Tell everybody interested what the new where[] info is for the interface vertices */ CommChangedInterfaceData(ctrl, graph, nchanged, changed, where, swchanges, rwchanges, wspace->pv4); /*------------------------------------------------------------- / Update the rinfo of the vertices in the update[] array /-------------------------------------------------------------*/ for (ii=0; ii= nparts) { /* If it is a separator vertex */ /* myprintf(ctrl, "Updating %d %d\n", i+firstvtx, me); */ myrinfo = rinfo+i; myrinfo->edegrees[0] = myrinfo->edegrees[1] = 0; for (j=xadj[i]; jedegrees[other%2] += otherwgt; } } } /* Finally, sum-up the partition weights */ MPI_Allreduce((void *)lpwgts, (void *)gpwgts, 2*nparts, IDX_DATATYPE, MPI_SUM, ctrl->comm); graph->mincut = gpwgts[2*nparts-1]; IFSET(ctrl->dbglvl, DBG_REFINEINFO, PrintNodeBalanceInfo(ctrl, nparts, gpwgts, badminpwgt, badmaxpwgt, 0)); } if (graph->mincut == oldcut) break; } /* Go and clear-up the where array */ for (i=0; inrecv; i++) where[i] = SelectWhere(where[i]); GKfree((void **)&update, (void **)&nupds_pe, (void **)&htable, (void **)&changed, LTERM); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->KWayTmr)); } /************************************************************************* * This function prints balance information for the parallel k-section * refinement algorithm **************************************************************************/ void PrintNodeBalanceInfo(CtrlType *ctrl, int nparts, idxtype *gpwgts, idxtype *badminpwgt, idxtype *badmaxpwgt, int title) { int i; if (ctrl->mype == 0) { if (title) printf("K-way sep-refinement: TotalSep: %d, ", gpwgts[2*nparts-1]); else printf("\tTotalSep: %d, ", gpwgts[2*nparts-1]); for (i=0; icomm); }