/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ void MlevelNestedDissectionCC(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx) { int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2], nsgraphs, ncmps, rnvtxs; idxtype *label, *bndind; idxtype *cptr, *cind; GraphType *sgraphs; nvtxs = graph->nvtxs; /* Determine the weights of the partitions */ tvwgt = idxsum(nvtxs, graph->vwgt); tpwgts2[0] = tvwgt/2; tpwgts2[1] = tvwgt-tpwgts2[0]; MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor); IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2])); /* Order the nodes in the separator */ nbnd = graph->nbnd; bndind = graph->bndind; label = graph->label; for (i=0; i<nbnd; i++) order[label[bndind[i]]] = --lastvtx; cptr = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cptr"); cind = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cind"); ncmps = FindComponents(ctrl, graph, cptr, cind); /* if (ncmps > 2) printf("[%5d] has %3d components\n", nvtxs, ncmps); */ sgraphs = (GraphType *)GKmalloc(ncmps*sizeof(GraphType), "MlevelNestedDissectionCC: sgraphs"); nsgraphs = SplitGraphOrderCC(ctrl, graph, sgraphs, ncmps, cptr, cind); /*GKfree(&cptr, &cind, LTERM);*/ GKfree2((void **)&cptr, (void **)&cind); /* Free the memory of the top level graph */ /*GKfree(&graph->gdata, &graph->rdata, &graph->label, LTERM);*/ GKfree3((void**)&graph->gdata, (void**)&graph->rdata, (void**)&graph->label); /* Go and process the subgraphs */ for (rnvtxs=i=0; i<nsgraphs; i++) { if (sgraphs[i].adjwgt == NULL) { MMDOrder(ctrl, sgraphs+i, order, lastvtx-rnvtxs); /*GKfree(&sgraphs[i].gdata, &sgraphs[i].label, LTERM);*/ GKfree2((void**)&sgraphs[i].gdata, (void**)&sgraphs[i].label); } else { MlevelNestedDissectionCC(ctrl, sgraphs+i, order, ubfactor, lastvtx-rnvtxs); } rnvtxs += sgraphs[i].nvtxs; } free(sgraphs); }
/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor) { int i, j, nvtxs, tvwgt, tpwgts2[2]; GraphType *cgraph; int wgtflag=3, numflag=0, options[10], edgecut; cgraph = Coarsen2Way(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr)); AllocateKWayPartitionMemory(ctrl, cgraph, nparts); options[0] = 1; options[OPTION_CTYPE] = MATCH_SHEMKWAY; options[OPTION_ITYPE] = IPART_GGPKL; options[OPTION_RTYPE] = RTYPE_FM; options[OPTION_DBGLVL] = 0; METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt, cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options, &edgecut, cgraph->where); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut)); IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); RefineKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor); idxcopy(graph->nvtxs, graph->where, part); /*GKfree(&graph->gdata, &graph->rdata, LTERM);*/ GKfree2((void **)&graph->gdata, (void **)&graph->rdata); return graph->mincut; }
/************************************************************************* * This function takes a graph and produces a bisection by using a region * growing algorithm. The resulting partition is returned in * graph->where **************************************************************************/ void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor) { int i, ii, j, k, nvtxs, ncon, from, bestcut, mincut, nbfs, qnum; idxtype *bestwhere, *where, *perm; int counts[MAXNCON]; float *nvwgt; nvtxs = graph->nvtxs; ncon = graph->ncon; nvwgt = graph->nvwgt; MocAllocate2WayPartitionMemory(ctrl, graph); where = graph->where; bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere"); nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS); bestcut = idxsum(graph->nedges, graph->adjwgt); perm = idxmalloc(nvtxs, "BisectGraph: perm"); for (; nbfs>0; nbfs--) { for (i=0; i<ncon; i++) counts[i] = 0; RandomPermute(nvtxs, perm, 1); /* Partition by spliting the queues randomly */ for (ii=0; ii<nvtxs; ii++) { i = perm[ii]; qnum = samax(ncon, nvwgt+i*ncon); where[i] = counts[qnum]; counts[qnum] = (counts[qnum]+1)%2; } MocCompute2WayPartitionParams(ctrl, graph); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); MocBalance2Way(ctrl, graph, tpwgts, 1.02); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); MocBalance2Way(ctrl, graph, tpwgts, 1.02); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6); /* printf("Edgecut: %6d, NPwgts: [", graph->mincut); for (i=0; i<graph->ncon; i++) printf("(%.3f %.3f) ", graph->npwgts[i], graph->npwgts[graph->ncon+i]); printf("]\n"); */ if (bestcut >= graph->mincut) { bestcut = graph->mincut; idxcopy(nvtxs, where, bestwhere); if (bestcut == 0) break; } } graph->mincut = bestcut; idxcopy(nvtxs, bestwhere, where); /*GKfree(&bestwhere, &perm, LTERM);*/ GKfree2((void**)&bestwhere, (void**)&perm); }
/************************************************************************* * 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); }