void GrowBisectionNode2(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niparts) { idx_t i, j, k, nvtxs, bestcut=0, mincut, inbfs; idx_t *xadj, *where, *bndind, *bestwhere; WCOREPUSH; nvtxs = graph->nvtxs; xadj = graph->xadj; /* Allocate refinement memory. Allocate sufficient memory for both edge and node */ graph->pwgts = imalloc(3, "GrowBisectionNode: pwgts"); graph->where = imalloc(nvtxs, "GrowBisectionNode: where"); graph->bndptr = imalloc(nvtxs, "GrowBisectionNode: bndptr"); graph->bndind = imalloc(nvtxs, "GrowBisectionNode: bndind"); graph->id = imalloc(nvtxs, "GrowBisectionNode: id"); graph->ed = imalloc(nvtxs, "GrowBisectionNode: ed"); graph->nrinfo = (nrinfo_t *)gk_malloc(nvtxs*sizeof(nrinfo_t), "GrowBisectionNode: nrinfo"); bestwhere = iwspacemalloc(ctrl, nvtxs); where = graph->where; bndind = graph->bndind; for (inbfs=0; inbfs<niparts; inbfs++) { iset(nvtxs, 1, where); if (inbfs > 0) where[irandInRange(nvtxs)] = 0; Compute2WayPartitionParams(ctrl, graph); General2WayBalance(ctrl, graph, ntpwgts); FM_2WayRefine(ctrl, graph, ntpwgts, ctrl->niter); /* Construct and refine the vertex separator */ for (i=0; i<graph->nbnd; i++) { j = bndind[i]; if (xadj[j+1]-xadj[j] > 0) /* ignore islands */ where[j] = 2; } Compute2WayNodePartitionParams(ctrl, graph); FM_2WayNodeRefine2Sided(ctrl, graph, 4); /* printf("ISep: [%"PRIDX" %"PRIDX" %"PRIDX" %"PRIDX"] %"PRIDX"\n", inbfs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */ if (inbfs == 0 || bestcut > graph->mincut) { bestcut = graph->mincut; icopy(nvtxs, where, bestwhere); } } graph->mincut = bestcut; icopy(nvtxs, bestwhere, where); WCOREPOP; }
void METIS_NodeRefine(int nvtxs, idxtype *xadj, idxtype *vwgt, idxtype *adjncy, idxtype *adjwgt, idxtype *where, idxtype *hmarker, float ubfactor) { GraphType *graph; CtrlType ctrl; ctrl.dbglvl = ONMETIS_DBGLVL; ctrl.optype = OP_ONMETIS; graph = CreateGraph(); SetUpGraph(graph, OP_ONMETIS, nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3); AllocateWorkSpace(&ctrl, graph, 2); Allocate2WayNodePartitionMemory(&ctrl, graph); idxcopy(nvtxs, where, graph->where); Compute2WayNodePartitionParams(&ctrl, graph); FM_2WayNodeRefine_OneSidedP(&ctrl, graph, hmarker, ubfactor, 10); /* FM_2WayNodeRefine_TwoSidedP(&ctrl, graph, hmarker, ubfactor, 10); */ FreeWorkSpace(&ctrl, graph); idxcopy(nvtxs, graph->where, where); FreeGraph(graph); }
/************************************************************************* * This function takes a bisection and constructs a minimum weight vertex * separator out of it. It uses the node-based separator refinement for it. **************************************************************************/ void ConstructSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) { int i, j, k, nvtxs, nbnd; idxtype *xadj, *where, *bndind; nvtxs = graph->nvtxs; xadj = graph->xadj; nbnd = graph->nbnd; bndind = graph->bndind; where = idxcopy(nvtxs, graph->where, idxwspacemalloc(ctrl, nvtxs)); /* Put the nodes in the boundary into the separator */ for (i=0; i<nbnd; i++) { j = bndind[i]; if (xadj[j+1]-xadj[j] > 0) /* Ignore islands */ where[j] = 2; } GKfree(&graph->rdata, LTERM); Allocate2WayNodePartitionMemory(ctrl, graph); idxcopy(nvtxs, where, graph->where); idxwspacefree(ctrl, nvtxs); ASSERT(IsSeparable(graph)); Compute2WayNodePartitionParams(ctrl, graph); ASSERT(CheckNodePartitionParams(graph)); FM_2WayNodeRefine(ctrl, graph, ubfactor, 8); ASSERT(IsSeparable(graph)); }
void Project2WayNodePartition(ctrl_t *ctrl, graph_t *graph) { idx_t i, j, nvtxs; idx_t *cmap, *where, *cwhere; graph_t *cgraph; cgraph = graph->coarser; cwhere = cgraph->where; nvtxs = graph->nvtxs; cmap = graph->cmap; Allocate2WayNodePartitionMemory(ctrl, graph); where = graph->where; /* Project the partition */ for (i=0; i<nvtxs; i++) { where[i] = cwhere[cmap[i]]; ASSERTP(where[i] >= 0 && where[i] <= 2, ("%"PRIDX" %"PRIDX" %"PRIDX" %"PRIDX"\n", i, cmap[i], where[i], cwhere[cmap[i]])); } FreeGraph(&graph->coarser); graph->coarser = NULL; Compute2WayNodePartitionParams(ctrl, graph); }
/************************************************************************* * This function computes the initial bisection of the coarsest graph **************************************************************************/ void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) { int dbglvl; dbglvl = ctrl->dbglvl; IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE); IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); GrowBisectionNode(ctrl, graph, ubfactor); Compute2WayNodePartitionParams(ctrl, graph); IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Sep: %d\n", graph->mincut)); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); ctrl->dbglvl = dbglvl; }
void MlevelNodeBisectionMultiple(ctrl_t *ctrl, graph_t *graph) { idx_t i, mincut; idx_t *bestwhere; /* if the graph is small, just find a single vertex separator */ if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->compress ? 1000 : 2000)) { MlevelNodeBisectionL2(ctrl, graph, LARGENIPARTS); return; } WCOREPUSH; bestwhere = iwspacemalloc(ctrl, graph->nvtxs); mincut = graph->tvwgt[0]; for (i=0; i<ctrl->nseps; i++) { MlevelNodeBisectionL2(ctrl, graph, LARGENIPARTS); if (i == 0 || graph->mincut < mincut) { mincut = graph->mincut; if (i < ctrl->nseps-1) icopy(graph->nvtxs, graph->where, bestwhere); } if (mincut == 0) break; if (i < ctrl->nseps-1) FreeRData(graph); } if (mincut != graph->mincut) { icopy(graph->nvtxs, bestwhere, graph->where); Compute2WayNodePartitionParams(ctrl, graph); } WCOREPOP; }
void Refine2WayNode(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph) { IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr)); if (graph == orggraph) { Compute2WayNodePartitionParams(ctrl, graph); } else { do { graph = graph->finer; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); Project2WayNodePartition(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->RefTmr)); FM_2WayNodeBalance(ctrl, graph); ASSERT(CheckNodePartitionParams(graph)); switch (ctrl->rtype) { case METIS_RTYPE_SEP2SIDED: FM_2WayNodeRefine2Sided(ctrl, graph, ctrl->niter); break; case METIS_RTYPE_SEP1SIDED: FM_2WayNodeRefine1Sided(ctrl, graph, ctrl->niter); break; default: gk_errexit(SIGERR, "Unknown rtype of %d\n", ctrl->rtype); } IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->RefTmr)); } while (graph != orggraph); } IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr)); }
/************************************************************************* * This function takes a graph and produces a bisection by using a region * growing algorithm. The resulting partition is returned in * graph->where **************************************************************************/ void GrowBisectionNode(CtrlType *ctrl, GraphType *graph, float ubfactor) { int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], tpwgts[2], minpwgt[2], maxpwgt[2], from, bestcut, icut, mincut, me, pass, nbfs; idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *bndind; idxtype *queue, *touched, *gain, *bestwhere; nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); queue = idxmalloc(nvtxs, "BisectGraph: queue"); touched = idxmalloc(nvtxs, "BisectGraph: touched"); tpwgts[0] = idxsum(nvtxs, vwgt); tpwgts[1] = tpwgts[0]/2; tpwgts[0] -= tpwgts[1]; maxpwgt[0] = ubfactor*tpwgts[0]; maxpwgt[1] = ubfactor*tpwgts[1]; minpwgt[0] = (1.0/ubfactor)*tpwgts[0]; minpwgt[1] = (1.0/ubfactor)*tpwgts[1]; /* Allocate memory for graph->rdata. Allocate sufficient memory for both edge and node */ graph->rdata = idxmalloc(5*nvtxs+3, "GrowBisectionNode: graph->rdata"); graph->pwgts = graph->rdata; graph->where = graph->rdata + 3; graph->bndptr = graph->rdata + nvtxs + 3; graph->bndind = graph->rdata + 2*nvtxs + 3; graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3); graph->id = graph->rdata + 3*nvtxs + 3; graph->ed = graph->rdata + 4*nvtxs + 3; where = graph->where; bndind = graph->bndind; nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); bestcut = tpwgts[0]+tpwgts[1]; for (nbfs++; nbfs>0; nbfs--) { idxset(nvtxs, 0, touched); pwgts[1] = tpwgts[0]+tpwgts[1]; pwgts[0] = 0; idxset(nvtxs, 1, where); queue[0] = RandomInRange(nvtxs); touched[queue[0]] = 1; first = 0; last = 1; nleft = nvtxs-1; drain = 0; /* Start the BFS from queue to get a partition */ if (nbfs >= 1) { for (;;) { if (first == last) { /* Empty. Disconnected graph! */ if (nleft == 0 || drain) break; k = RandomInRange(nleft); for (i=0; i<nvtxs; i++) { if (touched[i] == 0) { if (k == 0) break; else k--; } } queue[0] = i; touched[i] = 1; first = 0; last = 1;; nleft--; } i = queue[first++]; if (pwgts[1]-vwgt[i] < minpwgt[1]) { drain = 1; continue; } where[i] = 0; INC_DEC(pwgts[0], pwgts[1], vwgt[i]); if (pwgts[1] <= maxpwgt[1]) break; drain = 0; for (j=xadj[i]; j<xadj[i+1]; j++) { k = adjncy[j]; if (touched[k] == 0) { queue[last++] = k; touched[k] = 1; nleft--; } } } } /************************************************************* * Do some partition refinement **************************************************************/ Compute2WayPartitionParams(ctrl, graph); Balance2Way(ctrl, graph, tpwgts, ubfactor); FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); /* Construct and refine the vertex separator */ for (i=0; i<graph->nbnd; i++) where[bndind[i]] = 2; Compute2WayNodePartitionParams(ctrl, graph); FM_2WayNodeRefine(ctrl, graph, ubfactor, 6); /* printf("ISep: [%d %d %d] %d\n", graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */ if (bestcut > graph->mincut) { bestcut = graph->mincut; idxcopy(nvtxs, where, bestwhere); } } graph->mincut = bestcut; idxcopy(nvtxs, bestwhere, where); Compute2WayNodePartitionParams(ctrl, graph); GKfree(&bestwhere, &queue, &touched, LTERM); }
/************************************************************************* * This function performs multilevel bisection. It performs multiple * bisections and selects the best. **************************************************************************/ void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor) { int i, nvtxs, cnvtxs, mincut, tmp; GraphType *cgraph; idxtype *bestwhere; if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->oflags&OFLAG_COMPRESS ? 1000 : 2000)) { MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); return; } nvtxs = graph->nvtxs; if (ctrl->oflags&OFLAG_COMPRESS) { /* Multiple separators at the original graph */ bestwhere = idxmalloc(nvtxs, "MlevelNodeBisection2: bestwhere"); mincut = nvtxs; for (i=ctrl->nseps; i>0; i--) { MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor); /* printf("%5d ", cgraph->mincut); */ if (graph->mincut < mincut) { mincut = graph->mincut; idxcopy(nvtxs, graph->where, bestwhere); } GKfree(&graph->rdata, LTERM); if (mincut == 0) break; } /* printf("[%5d]\n", mincut); */ Allocate2WayNodePartitionMemory(ctrl, graph); idxcopy(nvtxs, bestwhere, graph->where); free(bestwhere); Compute2WayNodePartitionParams(ctrl, graph); } else { /* Coarsen it a bit */ ctrl->CoarsenTo = nvtxs-1; cgraph = Coarsen2Way(ctrl, graph); cnvtxs = cgraph->nvtxs; bestwhere = idxmalloc(cnvtxs, "MlevelNodeBisection2: bestwhere"); mincut = nvtxs; for (i=ctrl->nseps; i>0; i--) { ctrl->CType += 20; /* This is a hack. Look at coarsen.c */ MlevelNodeBisection(ctrl, cgraph, tpwgts, ubfactor); /* printf("%5d ", cgraph->mincut); */ if (cgraph->mincut < mincut) { mincut = cgraph->mincut; idxcopy(cnvtxs, cgraph->where, bestwhere); } GKfree(&cgraph->rdata, LTERM); if (mincut == 0) break; } /* printf("[%5d]\n", mincut); */ Allocate2WayNodePartitionMemory(ctrl, cgraph); idxcopy(cnvtxs, bestwhere, cgraph->where); free(bestwhere); Compute2WayNodePartitionParams(ctrl, cgraph); Refine2WayNode(ctrl, graph, cgraph, ubfactor); } }
void GrowBisectionNode(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niparts) { idx_t i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], oneminpwgt, onemaxpwgt, from, me, bestcut=0, icut, mincut, inbfs; idx_t *xadj, *vwgt, *adjncy, *where, *bndind; idx_t *queue, *touched, *gain, *bestwhere; WCOREPUSH; nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; // adjwgt = graph->adjwgt; bestwhere = iwspacemalloc(ctrl, nvtxs); queue = iwspacemalloc(ctrl, nvtxs); touched = iwspacemalloc(ctrl, nvtxs); onemaxpwgt = ctrl->ubfactors[0]*graph->tvwgt[0]*0.5; oneminpwgt = (1.0/ctrl->ubfactors[0])*graph->tvwgt[0]*0.5; /* Allocate refinement memory. Allocate sufficient memory for both edge and node */ graph->pwgts = imalloc(3, "GrowBisectionNode: pwgts"); graph->where = imalloc(nvtxs, "GrowBisectionNode: where"); graph->bndptr = imalloc(nvtxs, "GrowBisectionNode: bndptr"); graph->bndind = imalloc(nvtxs, "GrowBisectionNode: bndind"); graph->id = imalloc(nvtxs, "GrowBisectionNode: id"); graph->ed = imalloc(nvtxs, "GrowBisectionNode: ed"); graph->nrinfo = (nrinfo_t *)gk_malloc(nvtxs*sizeof(nrinfo_t), "GrowBisectionNode: nrinfo"); where = graph->where; bndind = graph->bndind; for (inbfs=0; inbfs<niparts; inbfs++) { iset(nvtxs, 1, where); iset(nvtxs, 0, touched); pwgts[1] = graph->tvwgt[0]; pwgts[0] = 0; queue[0] = irandInRange(nvtxs); touched[queue[0]] = 1; first = 0; last = 1; nleft = nvtxs-1; drain = 0; /* Start the BFS from queue to get a partition */ for (;;) { if (first == last) { /* Empty. Disconnected graph! */ if (nleft == 0 || drain) break; k = irandInRange(nleft); for (i=0; i<nvtxs; i++) { /* select the kth untouched vertex */ if (touched[i] == 0) { if (k == 0) break; else k--; } } queue[0] = i; touched[i] = 1; first = 0; last = 1; nleft--; } i = queue[first++]; if (pwgts[1]-vwgt[i] < oneminpwgt) { drain = 1; continue; } where[i] = 0; INC_DEC(pwgts[0], pwgts[1], vwgt[i]); if (pwgts[1] <= onemaxpwgt) break; drain = 0; for (j=xadj[i]; j<xadj[i+1]; j++) { k = adjncy[j]; if (touched[k] == 0) { queue[last++] = k; touched[k] = 1; nleft--; } } } /************************************************************* * Do some partition refinement **************************************************************/ Compute2WayPartitionParams(ctrl, graph); Balance2Way(ctrl, graph, ntpwgts); FM_2WayRefine(ctrl, graph, ntpwgts, 4); /* Construct and refine the vertex separator */ for (i=0; i<graph->nbnd; i++) { j = bndind[i]; if (xadj[j+1]-xadj[j] > 0) /* ignore islands */ where[j] = 2; } Compute2WayNodePartitionParams(ctrl, graph); FM_2WayNodeRefine2Sided(ctrl, graph, 1); FM_2WayNodeRefine1Sided(ctrl, graph, 4); /* printf("ISep: [%"PRIDX" %"PRIDX" %"PRIDX" %"PRIDX"] %"PRIDX"\n", inbfs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */ if (inbfs == 0 || bestcut > graph->mincut) { bestcut = graph->mincut; icopy(nvtxs, where, bestwhere); } } graph->mincut = bestcut; icopy(nvtxs, bestwhere, where); WCOREPOP; }
/************************************************************************* * This function takes a bisection and constructs a minimum weight vertex * separator out of it. It uses an unweighted minimum-cover algorithm * followed by node-based separator refinement. **************************************************************************/ void ConstructMinCoverSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) { int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize; idxtype *xadj, *adjncy, *bxadj, *badjncy; idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; nbnd = graph->nbnd; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; vmap = idxwspacemalloc(ctrl, nvtxs); ivmap = idxwspacemalloc(ctrl, nbnd); cover = idxwspacemalloc(ctrl, nbnd); if (nbnd > 0) { /* Go through the boundary and determine the sizes of the bipartite graph */ bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0; for (i=0; i<nbnd; i++) { j = bndind[i]; k = where[j]; if (xadj[j+1]-xadj[j] > 0) { bnvtxs[k]++; bnedges[k] += xadj[j+1]-xadj[j]; } } bnvtxs[2] = bnvtxs[0]+bnvtxs[1]; bnvtxs[1] = bnvtxs[0]; bnvtxs[0] = 0; bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj"); badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy"); /* Construct the ivmap and vmap */ ASSERT(idxset(nvtxs, -1, vmap) == vmap); for (i=0; i<nbnd; i++) { j = bndind[i]; k = where[j]; if (xadj[j+1]-xadj[j] > 0) { vmap[j] = bnvtxs[k]; ivmap[bnvtxs[k]++] = j; } } /* OK, go through and put the vertices of each part starting from 0 */ bnvtxs[1] = bnvtxs[0]; bnvtxs[0] = 0; bxadj[0] = l = 0; for (k=0; k<2; k++) { for (ii=0; ii<nbnd; ii++) { i = bndind[ii]; if (where[i] == k && xadj[i] < xadj[i+1]) { for (j=xadj[i]; j<xadj[i+1]; j++) { jj = adjncy[j]; if (where[jj] != k) { ASSERT(bndptr[jj] != -1); ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj])); badjncy[l++] = vmap[jj]; } } bxadj[++bnvtxs[k]] = l; } } } ASSERT(l <= bnedges[0]+bnedges[1]); MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize); IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize)); for (i=0; i<csize; i++) { j = ivmap[cover[i]]; where[j] = 2; } GKfree(&bxadj, &badjncy, LTERM); } else { IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0)); } /* Prepare to refine the vertex separator */ idxcopy(nvtxs, graph->where, vmap); GKfree(&graph->rdata, LTERM); Allocate2WayNodePartitionMemory(ctrl, graph); idxcopy(nvtxs, vmap, graph->where); idxwspacefree(ctrl, nvtxs+2*graph->nbnd); Compute2WayNodePartitionParams(ctrl, graph); ASSERT(CheckNodePartitionParams(graph)); FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 6); ASSERT(IsSeparable(graph)); }