/************************************************************************* * This function takes a graph and produces a bisection by using a region * growing algorithm. The resulting partition is returned in * graph->where **************************************************************************/ void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) { int i, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs; idxtype *bestwhere, *where; nvtxs = graph->nvtxs; MocAllocate2WayPartitionMemory(ctrl, graph); where = graph->where; bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); bestcut = idxsum(graph->nedges, graph->adjwgt); for (; nbfs>0; nbfs--) { idxset(nvtxs, 1, where); where[RandomInRange(nvtxs)] = 0; MocCompute2WayPartitionParams(ctrl, graph); MocInit2WayBalance(ctrl, graph, tpwgts); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); MocBalance2Way(ctrl, graph, tpwgts, 1.02); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4); if (bestcut >= graph->mincut) { bestcut = graph->mincut; idxcopy(nvtxs, where, bestwhere); if (bestcut == 0) break; } } graph->mincut = bestcut; idxcopy(nvtxs, bestwhere, where); /*GKfree(&bestwhere, LTERM);*/ GKfree1((void**)&bestwhere); }
/************************************************************************* * 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);*/ GKfree1((void**)&graph->rdata); 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);*/ GKfree1((void **)&cgraph->rdata); 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); } }
/************************************************************************* * This function is the entry point for ONCMETIS **************************************************************************/ void METIS_NodeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) { int i, ii, j, l, wflag, nflag; GraphType graph; CtrlType ctrl; idxtype *cptr, *cind, *piperm; if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = ONMETIS_CTYPE; ctrl.IType = ONMETIS_ITYPE; ctrl.RType = ONMETIS_RTYPE; ctrl.dbglvl = ONMETIS_DBGLVL; ctrl.oflags = ONMETIS_OFLAGS; ctrl.pfactor = ONMETIS_PFACTOR; ctrl.nseps = ONMETIS_NSEPS; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; ctrl.oflags = options[OPTION_OFLAGS]; ctrl.pfactor = options[OPTION_PFACTOR]; ctrl.nseps = options[OPTION_NSEPS]; } if (ctrl.nseps < 1) ctrl.nseps = 1; ctrl.optype = OP_ONMETIS; ctrl.CoarsenTo = 100; IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); InitRandom(-1); if (ctrl.pfactor > 0) { /*============================================================ * Prune the dense columns ==============================================================*/ piperm = idxmalloc(*nvtxs, "ONMETIS: piperm"); PruneGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, piperm, (float)(0.1*ctrl.pfactor)); } else if (ctrl.oflags&OFLAG_COMPRESS) { /*============================================================ * Compress the graph ==============================================================*/ cptr = idxmalloc(*nvtxs+1, "ONMETIS: cptr"); cind = idxmalloc(*nvtxs, "ONMETIS: cind"); CompressGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, cptr, cind); if (graph.nvtxs >= COMPRESSION_FRACTION*(*nvtxs)) { ctrl.oflags--; /* We actually performed no compression */ /*GKfree(&cptr, &cind, LTERM);*/ GKfree2((void **)&cptr, (void **)&cind); } else if (2*graph.nvtxs < *nvtxs && ctrl.nseps == 1) ctrl.nseps = 2; } else { SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0); } /*============================================================= * Do the nested dissection ordering --=============================================================*/ ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo); AllocateWorkSpace(&ctrl, &graph, 2); if (ctrl.oflags&OFLAG_CCMP) MlevelNestedDissectionCC(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs); else MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs); FreeWorkSpace(&ctrl, &graph); if (ctrl.pfactor > 0) { /* Order any prunned vertices */ if (graph.nvtxs < *nvtxs) { idxcopy(graph.nvtxs, iperm, perm); /* Use perm as an auxiliary array */ for (i=0; i<graph.nvtxs; i++) iperm[piperm[i]] = perm[i]; for (i=graph.nvtxs; i<*nvtxs; i++) iperm[piperm[i]] = i; } /*GKfree(&piperm, LTERM); */ GKfree1((void **)&piperm); } else if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */ if (graph.nvtxs < COMPRESSION_FRACTION*(*nvtxs)) { /* construct perm from iperm */ for (i=0; i<graph.nvtxs; i++) perm[iperm[i]] = i; for (l=ii=0; ii<graph.nvtxs; ii++) { i = perm[ii]; for (j=cptr[i]; j<cptr[i+1]; j++) iperm[cind[j]] = l++; } } /*GKfree(&cptr, &cind, LTERM);*/ GKfree2((void **)&cptr, (void **)&cind); } for (i=0; i<*nvtxs; i++) perm[iperm[i]] = i; IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); if (*numflag == 1) Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); }
/************************************************************************* * 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 */ GKfree1((void**)&graph->gdata); /* 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)); }