void Refine2Way(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph, real_t *tpwgts) { IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr)); /* Compute the parameters of the coarsest graph */ Compute2WayPartitionParams(ctrl, graph); for (;;) { ASSERT(CheckBnd(graph)); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->RefTmr)); Balance2Way(ctrl, graph, tpwgts); FM_2WayRefine(ctrl, graph, tpwgts, ctrl->niter); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->RefTmr)); if (graph == orggraph) break; graph = graph->finer; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); Project2WayPartition(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); } IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr)); }
void BDFReportResults(params_t *params, bigraph_t *bigraph) { gk_startcputimer(params->reporttimer); gk_stopcputimer(params->reporttimer); printf("\nTiming Information ----------------------------------------------------------\n"); printf(" I/O: \t\t %7.3"PRREAL" sec\n", gk_getcputimer(params->iotimer)); printf(" Ordering: \t\t %7.3"PRREAL" sec (METIS time)\n", gk_getcputimer(params->parttimer)); printf(" Reporting: \t\t %7.3"PRREAL" sec\n", gk_getcputimer(params->reporttimer)); printf(" Partitioning: \t\t %7.3"PRREAL" sec\n", gk_getcputimer(_parttimer)); printf(" NZStating: \t\t %7.3"PRREAL" sec\n", gk_getcputimer(_nztimer)); printf("\nMemory Information ----------------------------------------------------------\n"); printf(" Max memory used:\t\t %7.3"PRREAL" MB\n", (real_t)(params->maxmemory/(1024.0*1024.0))); printf("\nHeuristic Information -------------------------------------------------------\n"); printf(" TotalCheck: \t\t %"PRIDX"\n", _totalcheck); printf(" FirstHit: \t\t %"PRIDX"\n", _firsthit); printf(" FirstHitRate: \t\t %7.3"PRREAL"\n", (_totalcheck == 0 ? 1 : (real_t)1.0*_firsthit/_totalcheck)); printf(" MaxArea: \t\t %"PRIDX"\n", _maxarea); printf(" MaxNonZeros: \t\t %"PRIDX"\n", _maxnz); printf(" MinArea: \t\t %"PRIDX"\n", _minarea); printf(" MinNonZeors: \t\t %"PRIDX"\n", _minnz); printf(" AvgArea: \t\t %7.3"PRREAL"\n", _avgarea); printf(" AvgNz: \t\t %7.3"PRREAL"\n", _avgnz); printf(" MaxDense: \t\t %7.6"PRREAL"\n", _maxdense); printf(" MinDense: \t\t %7.6"PRREAL"\n", _mindense); printf("******************************************************************************\n"); }
/************************************************************************* * This function computes the initial bisection of the coarsest graph **************************************************************************/ void MocInit2WayPartition2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec) { idxtype 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, gk_startcputimer(ctrl->InitPartTmr)); switch (ctrl->IType) { case ITYPE_GGPKL: case ITYPE_RANDOM: MocGrowBisection2(ctrl, graph, tpwgts, ubvec); break; case 3: MocGrowBisectionNew2(ctrl, graph, tpwgts, ubvec); break; default: errexit("Unknown initial partition type: %d\n", ctrl->IType); } IFSET(ctrl->dbglvl, DBG_IPART, mprintf("Initial Cut: %D\n", graph->mincut)); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); ctrl->dbglvl = dbglvl; }
/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ idxtype MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, idxtype nparts, idxtype *part, float *tpwgts, float ubfactor) { idxtype i, j, nvtxs, tvwgt, tpwgts2[2]; GraphType *cgraph; idxtype wgtflag=3, numflag=0, options[10], edgecut; cgraph = Coarsen2Way(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); AllocateKWayPartitionMemory(ctrl, cgraph, nparts); options[0] = 1; options[OPTION_CTYPE] = MTYPE_SHEMKWAY; options[OPTION_ITYPE] = ITYPE_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, gk_stopcputimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, DBG_IPART, mprintf("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); FreeGraph(graph, 0); return graph->mincut; }
/************************************************************************* * This function computes the initial bisection of the coarsest graph **************************************************************************/ void Init2WayPartition(CtrlType *ctrl, GraphType *graph, idxtype *tpwgts, float ubfactor) { idxtype 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, gk_startcputimer(ctrl->InitPartTmr)); switch (ctrl->IType) { case ITYPE_GGPKL: if (graph->nedges == 0) RandomBisection(ctrl, graph, tpwgts, ubfactor); else GrowBisection(ctrl, graph, tpwgts, ubfactor); break; case ITYPE_RANDOM: RandomBisection(ctrl, graph, tpwgts, ubfactor); break; default: errexit("Unknown initial partition type: %d\n", ctrl->IType); } IFSET(ctrl->dbglvl, DBG_IPART, mprintf("Initial Cut: %D\n", graph->mincut)); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); ctrl->dbglvl = dbglvl; /* IsConnectedSubdomain(ctrl, graph, 0); IsConnectedSubdomain(ctrl, graph, 1); */ }
/************************************************************************* * This function is the entry point of refinement **************************************************************************/ void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor) { idxtype i; float tubvec[MAXNCON]; for (i=0; i<graph->ncon; i++) tubvec[i] = 1.0; IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr)); /* Compute the parameters of the coarsest graph */ MocCompute2WayPartitionParams(ctrl, graph); for (;;) { ASSERT(CheckBnd(graph)); IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->RefTmr)); switch (ctrl->RType) { case RTYPE_FM: MocBalance2Way(ctrl, graph, tpwgts, 1.03); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); break; case 2: MocBalance2Way(ctrl, graph, tpwgts, 1.03); MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, tubvec, 8); break; default: errexit("Unknown refinement type: %d\n", ctrl->RType); } IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->RefTmr)); if (graph == orggraph) break; graph = graph->finer; IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); MocProject2WayPartition(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); } MocBalance2Way(ctrl, graph, tpwgts, 1.01); MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr)); }
/************************************************************************* * This function is the entry point for PWMETIS that accepts exact weights * for the target partitions **************************************************************************/ void METIS_WPartGraphRecursive(idxtype *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, idxtype *wgtflag, idxtype *numflag, idxtype *nparts, float *tpwgts, idxtype *options, idxtype *edgecut, idxtype *part) { idxtype i, j; GraphType graph; CtrlType ctrl; float *mytpwgts; if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); SetUpGraph(&graph, OP_PMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = PMETIS_CTYPE; ctrl.IType = PMETIS_ITYPE; ctrl.RType = PMETIS_RTYPE; ctrl.dbglvl = PMETIS_DBGLVL; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; } ctrl.optype = OP_PMETIS; ctrl.CoarsenTo = 20; ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt, 1)/ctrl.CoarsenTo); mytpwgts = gk_fmalloc(*nparts, "PWMETIS: mytpwgts"); for (i=0; i<*nparts; i++) mytpwgts[i] = tpwgts[i]; InitRandom(-1); AllocateWorkSpace(&ctrl, &graph, *nparts); IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, gk_startcputimer(ctrl.TotalTmr)); *edgecut = MlevelRecursiveBisection(&ctrl, &graph, *nparts, part, mytpwgts, 1.000, 0); IFSET(ctrl.dbglvl, DBG_TIME, gk_stopcputimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); FreeWorkSpace(&ctrl, &graph); gk_free((void **)&mytpwgts, LTERM); if (*numflag == 1) Change2FNumbering(*nvtxs, xadj, adjncy, part); }
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 is the entry point for KWMETIS **************************************************************************/ void METIS_mCPartGraphKway(idxtype *nvtxs, idxtype *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, idxtype *wgtflag, idxtype *numflag, idxtype *nparts, float *rubvec, idxtype *options, idxtype *edgecut, idxtype *part) { idxtype i, j; GraphType graph; CtrlType ctrl; if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); SetUpGraph(&graph, OP_KMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = McKMETIS_CTYPE; ctrl.IType = McKMETIS_ITYPE; ctrl.RType = McKMETIS_RTYPE; ctrl.dbglvl = McKMETIS_DBGLVL; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; } ctrl.optype = OP_KMETIS; ctrl.CoarsenTo = amax((*nvtxs)/(20*gk_log2(*nparts)), 30*(*nparts)); ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo); InitRandom(-1); AllocateWorkSpace(&ctrl, &graph, *nparts); IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, gk_startcputimer(ctrl.TotalTmr)); *edgecut = MCMlevelKWayPartitioning(&ctrl, &graph, *nparts, part, rubvec); IFSET(ctrl.dbglvl, DBG_TIME, gk_stopcputimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); FreeWorkSpace(&ctrl, &graph); if (*numflag == 1) Change2FNumbering(*nvtxs, xadj, adjncy, part); }
/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ idxtype MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, idxtype nparts, idxtype *part, float *rubvec) { idxtype i, j, nvtxs; GraphType *cgraph; idxtype options[10], edgecut; cgraph = MCCoarsen2Way(ctrl, graph); IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); MocAllocateKWayPartitionMemory(ctrl, cgraph, nparts); options[0] = 1; options[OPTION_CTYPE] = MTYPE_SBHEM_INFNORM; options[OPTION_ITYPE] = ITYPE_RANDOM; options[OPTION_RTYPE] = RTYPE_FM; options[OPTION_DBGLVL] = 0; /* Determine what you will use as the initial partitioner, based on tolerances */ for (i=0; i<graph->ncon; i++) { if (rubvec[i] > 1.2) break; } if (i == graph->ncon) METIS_mCPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, options, &edgecut, cgraph->where); else METIS_mCHPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon, cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts, rubvec, options, &edgecut, cgraph->where); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); IFSET(ctrl->dbglvl, DBG_IPART, mprintf("Initial %D-way partitioning cut: %D\n", nparts, edgecut)); IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where)); MocRefineKWayHorizontal(ctrl, graph, cgraph, nparts, rubvec); idxcopy(graph->nvtxs, graph->where, part); FreeGraph(graph, 0); return graph->mincut; }
/************************************************************************* * This function is the entry point for KWMETIS with seed specification * in options[7] **************************************************************************/ void METIS_WPartGraphKway2(idxtype *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, idxtype *wgtflag, idxtype *numflag, idxtype *nparts, float *tpwgts, idxtype *options, idxtype *edgecut, idxtype *part) { idxtype i, j; GraphType graph; CtrlType ctrl; if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = KMETIS_CTYPE; ctrl.IType = KMETIS_ITYPE; ctrl.RType = KMETIS_RTYPE; ctrl.dbglvl = KMETIS_DBGLVL; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; } ctrl.optype = OP_KMETIS; ctrl.CoarsenTo = 20*(*nparts); ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt, 1) : (*nvtxs))/ctrl.CoarsenTo); InitRandom(options[7]); AllocateWorkSpace(&ctrl, &graph, *nparts); IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, gk_startcputimer(ctrl.TotalTmr)); *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03); IFSET(ctrl.dbglvl, DBG_TIME, gk_stopcputimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); FreeWorkSpace(&ctrl, &graph); if (*numflag == 1) Change2FNumbering(*nvtxs, xadj, adjncy, part); }
/************************************************************************* * This function computes the initial bisection of the coarsest graph **************************************************************************/ void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor) { idxtype 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, gk_startcputimer(ctrl->InitPartTmr)); GrowBisectionNode(ctrl, graph, ubfactor); Compute2WayNodePartitionParams(ctrl, graph); IFSET(ctrl->dbglvl, DBG_IPART, mprintf("Initial Sep: %D\n", graph->mincut)); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); ctrl->dbglvl = dbglvl; }
void Init2WayPartition(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niparts) { mdbglvl_et dbglvl; ASSERT(graph->tvwgt[0] >= 0); dbglvl = ctrl->dbglvl; IFSET(ctrl->dbglvl, METIS_DBG_REFINE, ctrl->dbglvl -= METIS_DBG_REFINE); IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, ctrl->dbglvl -= METIS_DBG_MOVEINFO); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); switch (ctrl->iptype) { case METIS_IPTYPE_RANDOM: if (graph->ncon == 1) RandomBisection(ctrl, graph, ntpwgts, niparts); else McRandomBisection(ctrl, graph, ntpwgts, niparts); break; case METIS_IPTYPE_GROW: if (graph->nedges == 0) if (graph->ncon == 1) RandomBisection(ctrl, graph, ntpwgts, niparts); else McRandomBisection(ctrl, graph, ntpwgts, niparts); else if (graph->ncon == 1) GrowBisection(ctrl, graph, ntpwgts, niparts); else McGrowBisection(ctrl, graph, ntpwgts, niparts); break; default: gk_errexit(SIGERR, "Unknown initial partition type: %d\n", ctrl->iptype); } IFSET(ctrl->dbglvl, METIS_DBG_IPART, printf("Initial Cut: %"PRIDX"\n", graph->mincut)); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); ctrl->dbglvl = dbglvl; }
void GPReportResults(params_t *params, graph_t *graph, idx_t *part, idx_t objval) { gk_startcputimer(params->reporttimer); ComputePartitionInfo(params, graph, part); gk_stopcputimer(params->reporttimer); FILE *fp; fp = fopen( "metis.log", "a" ); fprintf( fp,"\nTiming Information ----------------------------------------------------------\n"); fprintf( fp," I/O: \t\t %7.3"PRREAL" sec\n", gk_getcputimer(params->iotimer)); fprintf( fp," Partitioning: \t\t %7.3"PRREAL" sec (METIS time)\n", gk_getcputimer(params->parttimer)); fprintf( fp," Reporting: \t\t %7.3"PRREAL" sec\n", gk_getcputimer(params->reporttimer)); fprintf( fp,"\nMemory Information ----------------------------------------------------------\n"); fprintf( fp," Max memory used:\t\t %7.3"PRREAL" MB\n", (real_t)(params->maxmemory/(1024.0*1024.0))); fprintf( fp,"******************************************************************************\n"); fclose( fp ); }
void InitSeparator(ctrl_t *ctrl, graph_t *graph, idx_t niparts) { real_t ntpwgts[2] = {0.5, 0.5}; mdbglvl_et dbglvl; dbglvl = ctrl->dbglvl; IFSET(ctrl->dbglvl, METIS_DBG_REFINE, ctrl->dbglvl -= METIS_DBG_REFINE); IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, ctrl->dbglvl -= METIS_DBG_MOVEINFO); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); /* this is required for the cut-based part of the refinement */ Setup2WayBalMultipliers(ctrl, graph, ntpwgts); switch (ctrl->iptype) { case METIS_IPTYPE_EDGE: if (graph->nedges == 0) RandomBisection(ctrl, graph, ntpwgts, niparts); else GrowBisection(ctrl, graph, ntpwgts, niparts); Compute2WayPartitionParams(ctrl, graph); ConstructSeparator(ctrl, graph); break; case METIS_IPTYPE_NODE: GrowBisectionNode(ctrl, graph, ntpwgts, niparts); break; default: gk_errexit(SIGERR, "Unkown iptype of %"PRIDX"\n", ctrl->iptype); } IFSET(ctrl->dbglvl, METIS_DBG_IPART, printf("Initial Sep: %"PRIDX"\n", graph->mincut)); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); ctrl->dbglvl = dbglvl; }
void SplitGraphOrder(ctrl_t *ctrl, graph_t *graph, graph_t **r_lgraph, graph_t **r_rgraph) { idx_t i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3]; idx_t *xadj, *vwgt, *adjncy, *adjwgt, *label, *where, *bndptr, *bndind; idx_t *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *slabel[2]; idx_t *rename; idx_t *auxadjncy; graph_t *lgraph, *rgraph; WCOREPUSH; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->SplitTmr)); nvtxs = graph->nvtxs; xadj = graph->xadj; vwgt = graph->vwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; label = graph->label; where = graph->where; bndptr = graph->bndptr; bndind = graph->bndind; ASSERT(bndptr != NULL); rename = iwspacemalloc(ctrl, nvtxs); snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0; for (i=0; i<nvtxs; i++) { k = where[i]; rename[i] = snvtxs[k]++; snedges[k] += xadj[i+1]-xadj[i]; } lgraph = SetupSplitGraph(graph, snvtxs[0], snedges[0]); sxadj[0] = lgraph->xadj; svwgt[0] = lgraph->vwgt; sadjncy[0] = lgraph->adjncy; sadjwgt[0] = lgraph->adjwgt; slabel[0] = lgraph->label; rgraph = SetupSplitGraph(graph, snvtxs[1], snedges[1]); sxadj[1] = rgraph->xadj; svwgt[1] = rgraph->vwgt; sadjncy[1] = rgraph->adjncy; sadjwgt[1] = rgraph->adjwgt; slabel[1] = rgraph->label; /* Go and use bndptr to also mark the boundary nodes in the two partitions */ for (ii=0; ii<graph->nbnd; ii++) { i = bndind[ii]; for (j=xadj[i]; j<xadj[i+1]; j++) bndptr[adjncy[j]] = 1; } snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; sxadj[0][0] = sxadj[1][0] = 0; for (i=0; i<nvtxs; i++) { if ((mypart = where[i]) == 2) continue; istart = xadj[i]; iend = xadj[i+1]; if (bndptr[i] == -1) { /* This is an interior vertex */ auxadjncy = sadjncy[mypart] + snedges[mypart] - istart; for(j=istart; j<iend; j++) auxadjncy[j] = adjncy[j]; snedges[mypart] += iend-istart; } else { auxadjncy = sadjncy[mypart]; l = snedges[mypart]; for (j=istart; j<iend; j++) { k = adjncy[j]; if (where[k] == mypart) auxadjncy[l++] = k; } snedges[mypart] = l; } svwgt[mypart][snvtxs[mypart]] = vwgt[i]; slabel[mypart][snvtxs[mypart]] = label[i]; sxadj[mypart][++snvtxs[mypart]] = snedges[mypart]; } for (mypart=0; mypart<2; mypart++) { iend = snedges[mypart]; iset(iend, 1, sadjwgt[mypart]); auxadjncy = sadjncy[mypart]; for (i=0; i<iend; i++) auxadjncy[i] = rename[auxadjncy[i]]; } lgraph->nvtxs = snvtxs[0]; lgraph->nedges = snedges[0]; rgraph->nvtxs = snvtxs[1]; rgraph->nedges = snedges[1]; SetupGraph_tvwgt(lgraph); SetupGraph_tvwgt(rgraph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->SplitTmr)); *r_lgraph = lgraph; *r_rgraph = rgraph; WCOREPOP; }
/************************************************************************* * Let the game begin **************************************************************************/ int main(int argc, char *argv[]) { idxtype i, options[10]; idxtype *perm, *iperm; GraphType graph; char filename[256]; idxtype numflag = 0, wgtflag; double TOTALTmr, METISTmr, IOTmr, SMBTmr; if (argc != 2) { mprintf("Usage: %s <GraphFile>\n",argv[0]); exit(0); } strcpy(filename, argv[1]); gk_clearcputimer(TOTALTmr); gk_clearcputimer(METISTmr); gk_clearcputimer(IOTmr); gk_clearcputimer(SMBTmr); gk_startcputimer(TOTALTmr); gk_startcputimer(IOTmr); ReadGraph(&graph, filename, &wgtflag); if (graph.nvtxs <= 0) { mprintf("Empty graph. Nothing to do.\n"); exit(0); } if (graph.ncon != 1) { mprintf("Ordering can only be applied to graphs with one constraint.\n"); exit(0); } gk_stopcputimer(IOTmr); /* Ordering does not use weights! */ gk_free((void **)&graph.vwgt, &graph.adjwgt, LTERM); mprintf("**********************************************************************\n"); mprintf("%s", METISTITLE); mprintf("Graph Information ---------------------------------------------------\n"); mprintf(" Name: %s, #Vertices: %D, #Edges: %D\n\n", filename, graph.nvtxs, graph.nedges/2); mprintf("Node-Based Ordering... ----------------------------------------------\n"); perm = idxmalloc(graph.nvtxs, "main: perm"); iperm = idxmalloc(graph.nvtxs, "main: iperm"); options[0] = 0; gk_startcputimer(METISTmr); METIS_NodeND(&graph.nvtxs, graph.xadj, graph.adjncy, &numflag, options, perm, iperm); gk_stopcputimer(METISTmr); gk_startcputimer(IOTmr); WritePermutation(filename, iperm, graph.nvtxs); gk_stopcputimer(IOTmr); gk_startcputimer(SMBTmr); ComputeFillIn(&graph, iperm); gk_stopcputimer(SMBTmr); gk_stopcputimer(TOTALTmr); mprintf("\nTiming Information --------------------------------------------------\n"); mprintf(" I/O: \t %7.3f\n", gk_getcputimer(IOTmr)); mprintf(" Ordering: \t %7.3f (ONMETIS time)\n", gk_getcputimer(METISTmr)); mprintf(" Symbolic Factorization: \t %7.3f\n", gk_getcputimer(SMBTmr)); mprintf(" Total: \t %7.3f\n", gk_getcputimer(TOTALTmr)); mprintf("**********************************************************************\n"); gk_free((void **)&graph.xadj, &graph.adjncy, &perm, &iperm, LTERM); }
/************************************************************************* * This function takes a graph and creates a sequence of coarser graphs **************************************************************************/ GraphType *MCCoarsen2Way(CtrlType *ctrl, GraphType *graph) { idxtype i, clevel; GraphType *cgraph; IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->CoarsenTmr)); cgraph = graph; clevel = 0; do { if (ctrl->dbglvl&DBG_COARSEN) { mprintf("%6D %7D %10D [%D] [%6.4f", cgraph->nvtxs, cgraph->nedges, idxsum(cgraph->nvtxs, cgraph->adjwgtsum, 1), ctrl->CoarsenTo, ctrl->nmaxvwgt); for (i=0; i<graph->ncon; i++) mprintf(" %5.3f", gk_fsum(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon)); mprintf("]\n"); } if (cgraph->nedges == 0) { MCMatch_RM(ctrl, cgraph); } else { switch (ctrl->CType) { case MTYPE_RM: MCMatch_RM(ctrl, cgraph); break; case MTYPE_HEM: if (clevel < 1) MCMatch_RM(ctrl, cgraph); else MCMatch_HEM(ctrl, cgraph); break; case MTYPE_SHEM: if (clevel < 1) MCMatch_RM(ctrl, cgraph); else MCMatch_SHEM(ctrl, cgraph); break; case MTYPE_SHEMKWAY: MCMatch_SHEM(ctrl, cgraph); break; case MTYPE_SHEBM_ONENORM: MCMatch_SHEBM(ctrl, cgraph, 1); break; case MTYPE_SHEBM_INFNORM: MCMatch_SHEBM(ctrl, cgraph, -1); break; case MTYPE_SBHEM_ONENORM: MCMatch_SBHEM(ctrl, cgraph, 1); break; case MTYPE_SBHEM_INFNORM: MCMatch_SBHEM(ctrl, cgraph, -1); break; default: errexit("Unknown CType: %d\n", ctrl->CType); } } cgraph = cgraph->coarser; clevel++; } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2); if (ctrl->dbglvl&DBG_COARSEN) { mprintf("%6D %7D %10D [%D] [%6.4f", cgraph->nvtxs, cgraph->nedges, idxsum(cgraph->nvtxs, cgraph->adjwgtsum, 1), ctrl->CoarsenTo, ctrl->nmaxvwgt); for (i=0; i<graph->ncon; i++) mprintf(" %5.3f", gk_fsum(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon)); mprintf("]\n"); } IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->CoarsenTmr)); return cgraph; }
/************************************************************************* * Let the game begin **************************************************************************/ int main(int argc, char *argv[]) { idxtype i, j, ne, nn, etype, mtype, numflag=0, nparts, edgecut; idxtype *elmnts, *epart, *npart, *metype, *weights; double IOTmr, DUALTmr; char etypestr[5][5] = {"TRI", "TET", "HEX", "QUAD", "LINE"}; GraphType graph; if (argc != 3) { mprintf("Usage: %s <meshfile> <nparts>\n",argv[0]); exit(0); } nparts = atoi(argv[2]); if (nparts < 2) { mprintf("nparts must be greater than one.\n"); exit(0); } gk_clearcputimer(IOTmr); gk_clearcputimer(DUALTmr); mtype=MeshType(argv[1]); ne=MixedElements(argv[1]); metype = idxmalloc(ne, "main: metype"); weights = idxmalloc(ne, "main: weights"); gk_startcputimer(IOTmr); if(mtype==1) elmnts = ReadMesh(argv[1], &ne, &nn, &etype); else if(mtype==3) elmnts = ReadMeshWgt(argv[1], &ne, &nn, &etype, weights); else if(mtype==0) elmnts = ReadMixedMesh(argv[1], &ne, &nn, metype); else elmnts = ReadMixedMeshWgt(argv[1], &ne, &nn, metype, weights); gk_stopcputimer(IOTmr); epart = idxmalloc(ne, "main: epart"); npart = idxmalloc(nn, "main: npart"); mprintf("**********************************************************************\n"); mprintf("%s", METISTITLE); mprintf("Mesh Information ----------------------------------------------------\n"); if (mtype==1) mprintf(" Name: %s, #Elements: %D, #Nodes: %D, Etype: %s\n\n", argv[1], ne, nn, etypestr[etype-1]); else mprintf(" Name: %s, #Elements: %D, #Nodes: %D, Etype: %s\n\n", argv[1], ne, nn, "Mixed"); mprintf("Partitioning Nodal Graph... -----------------------------------------\n"); gk_startcputimer(DUALTmr); if (mtype==1 || mtype==3) METIS_PartMeshNodal(&ne, &nn, elmnts, &etype, &numflag, &nparts, &edgecut, epart, npart); else METIS_PartMixedMeshNodal(&ne, &nn, elmnts, metype, &numflag, &nparts, &edgecut, epart, npart); gk_stopcputimer(DUALTmr); mprintf(" %D-way Edge-Cut: %7D, Balance: %5.2f\n", nparts, edgecut, ComputeElementBalance(ne, nparts, epart)); gk_startcputimer(IOTmr); WriteMeshPartition(argv[1], nparts, ne, epart, nn, npart); gk_stopcputimer(IOTmr); mprintf("\nTiming Information --------------------------------------------------\n"); mprintf(" I/O: \t\t %7.3f\n", gk_getcputimer(IOTmr)); mprintf(" Partitioning: \t\t %7.3f\n", gk_getcputimer(DUALTmr)); mprintf("**********************************************************************\n"); /* graph.nvtxs = ne; graph.xadj = idxmalloc(ne+1, "xadj"); graph.vwgt = idxsmalloc(ne, 1, "vwgt"); graph.adjncy = idxmalloc(10*ne, "adjncy"); graph.adjwgt = idxsmalloc(10*ne, 1, "adjncy"); METIS_MeshToDual(&ne, &nn, elmnts, &etype, &numflag, graph.xadj, graph.adjncy); ComputePartitionInfo(&graph, nparts, epart); gk_free((void **)&graph.xadj, &graph.adjncy, &graph.vwgt, &graph.adjwgt, LTERM); */ gk_free((void **)&elmnts, &epart, &npart, &metype, &weights, LTERM); }
idx_t* gpmetis( int argc, char **argv ) /*************************************************************************/ /*! Let the game begin! */ /*************************************************************************/ //int main(int argc, char *argv[]) { idx_t i; char *curptr, *newptr; idx_t options[METIS_NOPTIONS]; graph_t *graph; idx_t *part; idx_t objval; params_t *params; int status=0; gk_optind = 0; //printf( "argc: %d\n", argc ); //printf( "gk_optind %d\n", gk_optind ); fflush( stdout ); for( i = 0; i < argc; i++ ) { //printf( "%s*\n", argv[ i ] ); } params = parse_cmdline(argc, argv); //printf( "gk_optind %d\n", gk_optind ); //fflush( stdout ); //return NULL; gk_startcputimer(params->iotimer); graph = ReadGraph(params); ReadTPwgts(params, graph->ncon); gk_stopcputimer(params->iotimer); /* Check if the graph is contiguous */ if (params->contig && !IsConnected(graph, 0)) { printf("***The input graph is not contiguous.\n" "***The specified -contig option will be ignored.\n"); params->contig = 0; } /* Get ubvec if supplied */ if (params->ubvecstr) { params->ubvec = rmalloc(graph->ncon, "main"); curptr = params->ubvecstr; for (i=0; i<graph->ncon; i++) { params->ubvec[i] = strtoreal(curptr, &newptr); if (curptr == newptr) errexit("Error parsing entry #%"PRIDX" of ubvec [%s] (possibly missing).\n", i, params->ubvecstr); curptr = newptr; } } /* Setup iptype */ if (params->iptype == -1) { if (params->ptype == METIS_PTYPE_RB) { if (graph->ncon == 1) params->iptype = METIS_IPTYPE_GROW; else params->iptype = METIS_IPTYPE_RANDOM; } } GPPrintInfo(params, graph); part = imalloc(graph->nvtxs, "main: part"); METIS_SetDefaultOptions(options); options[METIS_OPTION_OBJTYPE] = params->objtype; options[METIS_OPTION_CTYPE] = params->ctype; options[METIS_OPTION_IPTYPE] = params->iptype; options[METIS_OPTION_RTYPE] = params->rtype; options[METIS_OPTION_MINCONN] = params->minconn; options[METIS_OPTION_CONTIG] = params->contig; options[METIS_OPTION_SEED] = params->seed; options[METIS_OPTION_NITER] = params->niter; options[METIS_OPTION_NCUTS] = params->ncuts; options[METIS_OPTION_UFACTOR] = params->ufactor; options[METIS_OPTION_DBGLVL] = params->dbglvl; gk_malloc_init(); gk_startcputimer(params->parttimer); switch (params->ptype) { case METIS_PTYPE_RB: status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, graph->adjwgt, ¶ms->nparts, params->tpwgts, params->ubvec, options, &objval, part); break; case METIS_PTYPE_KWAY: status = METIS_PartGraphKway(&graph->nvtxs, &graph->ncon, graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, graph->adjwgt, ¶ms->nparts, params->tpwgts, params->ubvec, options, &objval, part); break; } gk_stopcputimer(params->parttimer); if (gk_GetCurMemoryUsed() != 0) printf("***It seems that Metis did not free all of its memory! Report this.\n"); params->maxmemory = gk_GetMaxMemoryUsed(); gk_malloc_cleanup(0); if (status != METIS_OK) { printf("\n***Metis returned with an error.\n"); } else { if (!params->nooutput) { /* Write the solution */ gk_startcputimer(params->iotimer); WritePartition(params->filename, part, graph->nvtxs, params->nparts); gk_stopcputimer(params->iotimer); } GPReportResults(params, graph, part, objval); } idx_t *r_part = ( idx_t* ) calloc( graph->nvtxs, sizeof( idx_t ) ); for( i = 0; i < graph->nvtxs; i++ ) { r_part[ i ] = part[ i ]; } FreeGraph(&graph); gk_free((void **)&part, LTERM); gk_free((void **)¶ms->filename, ¶ms->tpwgtsfile, ¶ms->tpwgts, ¶ms->ubvecstr, ¶ms->ubvec, ¶ms, LTERM); return r_part; }
int main(int argc, char *argv[]) { idx_t options[METIS_NOPTIONS]; bigraph_t *bigraph; idx_t *perm, *iperm; params_t *params; int status, i, j; /* rdiags[i][0] and cdiags[i][0] saves the length of each array * excluding the first value */ idx_t **rdiags, **cdiags; idx_t ndiags; params = parse_cmdline(argc, argv); gk_startcputimer(params->iotimer); bigraph = ReadBiGraph(params); gk_stopcputimer(params->iotimer); if(bigraph == NULL){ printf("Input Error : nrows + ncols != nvtxs\n"); printf("\n***Metis returned with an error.\n"); return -1; } BDFPrintInfo(params, bigraph); METIS_SetDefaultOptions(options); /*User specific parameters*/ options[METIS_OPTION_CTYPE] = params->ctype; options[METIS_OPTION_IPTYPE] = params->iptype; options[METIS_OPTION_RTYPE] = params->rtype; options[METIS_OPTION_CCORDER] = params->ccorder; options[METIS_OPTION_SEED] = params->seed; options[METIS_OPTION_DBGLVL] = params->dbglvl; options[METIS_OPTION_DENSITY] = params->density * DIVIDER; options[METIS_OPTION_NROWS] = params->nrows; options[METIS_OPTION_NCOLS] = params->ncols; options[METIS_OPTION_KAPPA] = params->kappa; options[METIS_OPTION_NDIAGS] = params->ndiags; /*Inner parameters*/ options[METIS_OPTION_COMPRESS] = params->compress; options[METIS_OPTION_UFACTOR] = params->ufactor; options[METIS_OPTION_PFACTOR] = params->pfactor; options[METIS_OPTION_NCUTS] = params->ncuts; options[METIS_OPTION_NSEPS] = params->nseps; options[METIS_OPTION_NITER] = params->niter; options[METIS_OPTION_OBJTYPE] = params->objtype; perm = imalloc(bigraph->super->nvtxs, "main: perm"); iperm = imalloc(bigraph->super->nvtxs, "main: iperm"); gk_malloc_init(); gk_startcputimer(params->parttimer); /* Initialize my global paramters */ gk_clearcputimer(_parttimer); gk_clearcputimer(_nztimer); _totalcheck = 0; _firsthit = 0; _maxarea = -1; _maxnz = -1; _minarea = 700000000000; _minnz = 300000000; _avgarea = 0; _avgnz = 0; _maxdense = 0; _mindense = 0; /* All the memory that is not allocated in this file should be allocated after * gk_malloc_init() and be freed before gk_GetCurMemoryUsed(). * Memory that is allocated in this file should be free in the end of main()*/ status = METIS_NodeBDF(&bigraph->super->nvtxs, bigraph->super->xadj, bigraph->super->adjncy, bigraph->super->vwgt, bigraph->nrows, bigraph->ncols, options, bigraph->rlabel->label, bigraph->rlabel->ref, bigraph->clabel->label, bigraph->clabel->ref, &rdiags, &cdiags, &ndiags, perm, iperm); gk_stopcputimer(params->parttimer); if (gk_GetCurMemoryUsed() != 0) printf("***It seems that Metis did not free all of its memory!\n"); params->maxmemory = gk_GetMaxMemoryUsed(); gk_malloc_cleanup(0); if (status != METIS_OK) { printf("\n***Metis returned with an error.\n"); } else { if (! params->nooutput) { /* Write the permutation */ gk_startcputimer(params->iotimer); WritePermutation(params->filename, iperm, bigraph->super->nvtxs); WriteDiags(params->filename, rdiags, cdiags, ndiags); gk_stopcputimer(params->iotimer); } BDFReportResults(params, bigraph); } /* free inner function memory */ for (i = 0; i < ndiags; i++) { free((void*)rdiags[i]); free((void*)cdiags[i]); } free((void*)rdiags); free((void*)cdiags); /* free memroy allocated in this function */ FreeBiGraph((ctrl_t*)NULL, &bigraph); gk_free((void **)&perm, &iperm, LTERM); gk_free((void **)¶ms->filename, ¶ms->tpwgtsfile, ¶ms->tpwgts, ¶ms->ubvec, ¶ms, LTERM); return status; }
/************************************************************************* * This function is the entry point for the node ND code for ParMETIS **************************************************************************/ void METIS_NodeNDP(idxtype nvtxs, idxtype *xadj, idxtype *adjncy, idxtype npes, idxtype *options, idxtype *perm, idxtype *iperm, idxtype *sizes) { idxtype i, ii, j, l, wflag, nflag; GraphType graph; CtrlType ctrl; idxtype *cptr, *cind; 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, gk_startcputimer(ctrl.TotalTmr)); InitRandom(-1); 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 */ gk_free((void **)&cptr, &cind, LTERM); } 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, 1)/ctrl.CoarsenTo); AllocateWorkSpace(&ctrl, &graph, 2); idxset(2*npes-1, 0, sizes); MlevelNestedDissectionP(&ctrl, &graph, iperm, graph.nvtxs, npes, 0, sizes); FreeWorkSpace(&ctrl, &graph); 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++; } } gk_free((void **)&cptr, &cind, LTERM); } for (i=0; i<nvtxs; i++) perm[iperm[i]] = i; IFSET(ctrl.dbglvl, DBG_TIME, gk_stopcputimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); }
/************************************************************************* * This function takes a graph and a bisection and splits it into two graphs. **************************************************************************/ void SplitGraphPart(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph) { idxtype i, j, k, kk, l, istart, iend, mypart, nvtxs, ncon, snvtxs[2], snedges[2], sum; idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr; idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2]; idxtype *rename; idxtype *auxadjncy, *auxadjwgt; float *nvwgt, *snvwgt[2], *npwgts; IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->SplitTmr)); nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; vwgt = graph->vwgt; nvwgt = graph->nvwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; adjwgtsum = graph->adjwgtsum; label = graph->label; where = graph->where; bndptr = graph->bndptr; npwgts = graph->npwgts; ASSERT(bndptr != NULL); rename = idxwspacemalloc(ctrl, nvtxs); snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; for (i=0; i<nvtxs; i++) { k = where[i]; rename[i] = snvtxs[k]++; snedges[k] += xadj[i+1]-xadj[i]; } SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]); sxadj[0] = lgraph->xadj; svwgt[0] = lgraph->vwgt; snvwgt[0] = lgraph->nvwgt; sadjwgtsum[0] = lgraph->adjwgtsum; sadjncy[0] = lgraph->adjncy; sadjwgt[0] = lgraph->adjwgt; slabel[0] = lgraph->label; SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]); sxadj[1] = rgraph->xadj; svwgt[1] = rgraph->vwgt; snvwgt[1] = rgraph->nvwgt; sadjwgtsum[1] = rgraph->adjwgtsum; sadjncy[1] = rgraph->adjncy; sadjwgt[1] = rgraph->adjwgt; slabel[1] = rgraph->label; snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0; sxadj[0][0] = sxadj[1][0] = 0; for (i=0; i<nvtxs; i++) { mypart = where[i]; sum = adjwgtsum[i]; istart = xadj[i]; iend = xadj[i+1]; if (bndptr[i] == -1) { /* This is an interior vertex */ auxadjncy = sadjncy[mypart] + snedges[mypart] - istart; auxadjwgt = sadjwgt[mypart] + snedges[mypart] - istart; for(j=istart; j<iend; j++) { auxadjncy[j] = adjncy[j]; auxadjwgt[j] = adjwgt[j]; } snedges[mypart] += iend-istart; } else { auxadjncy = sadjncy[mypart]; auxadjwgt = sadjwgt[mypart]; l = snedges[mypart]; for (j=istart; j<iend; j++) { k = adjncy[j]; if (where[k] == mypart) { auxadjncy[l] = k; auxadjwgt[l++] = adjwgt[j]; } else { sum -= adjwgt[j]; } } snedges[mypart] = l; } if (ncon == 1) svwgt[mypart][snvtxs[mypart]] = vwgt[i]; else { for (kk=0; kk<ncon; kk++) snvwgt[mypart][snvtxs[mypart]*ncon+kk] = nvwgt[i*ncon+kk]/npwgts[mypart*ncon+kk]; } sadjwgtsum[mypart][snvtxs[mypart]] = sum; slabel[mypart][snvtxs[mypart]] = label[i]; sxadj[mypart][++snvtxs[mypart]] = snedges[mypart]; } for (mypart=0; mypart<2; mypart++) { iend = sxadj[mypart][snvtxs[mypart]]; auxadjncy = sadjncy[mypart]; for (i=0; i<iend; i++) auxadjncy[i] = rename[auxadjncy[i]]; } lgraph->nedges = snedges[0]; rgraph->nedges = snedges[1]; IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->SplitTmr)); idxwspacefree(ctrl, nvtxs); }
/************************************************************************* * This function creates the coarser graph **************************************************************************/ void CreateCoarseGraph_NVW(CtrlType *ctrl, GraphType *graph, idxtype cnvtxs, idxtype *match, idxtype *perm) { idxtype i, j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask; idxtype *xadj, *adjncy, *adjwgtsum, *auxadj; idxtype *cmap, *htable; idxtype *cxadj, *cvwgt, *cadjncy, *cadjwgt, *cadjwgtsum; float *nvwgt, *cnvwgt; GraphType *cgraph; IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->ContractTmr)); nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; nvwgt = graph->nvwgt; adjncy = graph->adjncy; adjwgtsum = graph->adjwgtsum; cmap = graph->cmap; /* Initialize the coarser graph */ cgraph = SetUpCoarseGraph(graph, cnvtxs, 0); cxadj = cgraph->xadj; cvwgt = cgraph->vwgt; cnvwgt = cgraph->nvwgt; cadjwgtsum = cgraph->adjwgtsum; cadjncy = cgraph->adjncy; cadjwgt = cgraph->adjwgt; iend = xadj[nvtxs]; auxadj = ctrl->wspace.auxcore; memcpy(auxadj, adjncy, iend*sizeof(idxtype)); for (i=0; i<iend; i++) auxadj[i] = cmap[auxadj[i]]; mask = HTLENGTH; htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1)); cxadj[0] = cnvtxs = cnedges = 0; for (i=0; i<nvtxs; i++) { v = perm[i]; if (cmap[v] != cnvtxs) continue; u = match[v]; cvwgt[cnvtxs] = 1; cadjwgtsum[cnvtxs] = adjwgtsum[v]; nedges = 0; istart = xadj[v]; iend = xadj[v+1]; for (j=istart; j<iend; j++) { k = auxadj[j]; kk = k&mask; if ((m = htable[kk]) == -1) { cadjncy[nedges] = k; cadjwgt[nedges] = 1; htable[kk] = nedges++; } else if (cadjncy[m] == k) { cadjwgt[m]++; } else { for (jj=0; jj<nedges; jj++) { if (cadjncy[jj] == k) { cadjwgt[jj]++; break; } } if (jj == nedges) { cadjncy[nedges] = k; cadjwgt[nedges++] = 1; } } } if (v != u) { cvwgt[cnvtxs]++; cadjwgtsum[cnvtxs] += adjwgtsum[u]; istart = xadj[u]; iend = xadj[u+1]; for (j=istart; j<iend; j++) { k = auxadj[j]; kk = k&mask; if ((m = htable[kk]) == -1) { cadjncy[nedges] = k; cadjwgt[nedges] = 1; htable[kk] = nedges++; } else if (cadjncy[m] == k) { cadjwgt[m]++; } else { for (jj=0; jj<nedges; jj++) { if (cadjncy[jj] == k) { cadjwgt[jj]++; break; } } if (jj == nedges) { cadjncy[nedges] = k; cadjwgt[nedges++] = 1; } } } /* Remove the contracted adjacency weight */ jj = htable[cnvtxs&mask]; if (jj >= 0 && cadjncy[jj] != cnvtxs) { for (jj=0; jj<nedges; jj++) { if (cadjncy[jj] == cnvtxs) break; } } if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */ cadjwgtsum[cnvtxs] -= cadjwgt[jj]; cadjncy[jj] = cadjncy[--nedges]; cadjwgt[jj] = cadjwgt[nedges]; } } ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v])); for (j=0; j<nedges; j++) htable[cadjncy[j]&mask] = -1; /* Zero out the htable */ htable[cnvtxs&mask] = -1; cnedges += nedges; cxadj[++cnvtxs] = cnedges; cadjncy += nedges; cadjwgt += nedges; } cgraph->nedges = cnedges; ReAdjustMemory(graph, cgraph, 0); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->ContractTmr)); idxwspacefree(ctrl, mask+1); }
/************************************************************************* * This function takes a graph and creates a sequence of coarser graphs **************************************************************************/ GraphType *Coarsen2Way(CtrlType *ctrl, GraphType *graph) { idxtype clevel; GraphType *cgraph; IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->CoarsenTmr)); cgraph = graph; /* The following is ahack to allow the multiple bisections to go through with correct coarsening */ if (ctrl->CType > 20) { clevel = 1; ctrl->CType -= 20; } else clevel = 0; do { IFSET(ctrl->dbglvl, DBG_COARSEN, mprintf("%6D %7D %7D [%D] [%D %D]\n", cgraph->nvtxs, cgraph->nedges/2, idxsum(cgraph->nvtxs, cgraph->adjwgtsum, 1)/2, ctrl->CoarsenTo, ctrl->maxvwgt, (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt, 1) : cgraph->nvtxs))); if (cgraph->adjwgt) { switch (ctrl->CType) { case MTYPE_RM: Match_RM(ctrl, cgraph); break; case MTYPE_HEM: if (clevel < 1 || cgraph->nedges == 0) Match_RM(ctrl, cgraph); else Match_HEM(ctrl, cgraph); break; case MTYPE_SHEM: if (clevel < 1 || cgraph->nedges == 0) Match_RM(ctrl, cgraph); else Match_SHEM(ctrl, cgraph); break; case MTYPE_SHEMKWAY: if (cgraph->nedges == 0) Match_RM(ctrl, cgraph); else Match_SHEM(ctrl, cgraph); break; default: errexit("Unknown CType: %d\n", ctrl->CType); } } else { Match_RM_NVW(ctrl, cgraph); } cgraph = cgraph->coarser; clevel++; } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2); IFSET(ctrl->dbglvl, DBG_COARSEN, mprintf("%6D %7D %7D [%D] [%D %D]\n", cgraph->nvtxs, cgraph->nedges/2, idxsum(cgraph->nvtxs, cgraph->adjwgtsum, 1)/2, ctrl->CoarsenTo, ctrl->maxvwgt, (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt, 1) : cgraph->nvtxs))); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->CoarsenTmr)); return cgraph; }
int METIS_NodeND(idx_t *nvtxs, idx_t *xadj, idx_t *adjncy, idx_t *vwgt, idx_t *options, idx_t *perm, idx_t *iperm) { int sigrval=0, renumber=0; idx_t i, ii, j, l, nnvtxs=0; graph_t *graph=NULL; ctrl_t *ctrl; idx_t *cptr, *cind, *piperm; int numflag = 0; /* set up malloc cleaning code and signal catchers */ if (!gk_malloc_init()) return METIS_ERROR_MEMORY; gk_sigtrap(); if ((sigrval = gk_sigcatch()) != 0) goto SIGTHROW; /* set up the run time parameters */ ctrl = SetupCtrl(METIS_OP_OMETIS, options, 1, 3, NULL, NULL); if (!ctrl) { gk_siguntrap(); return METIS_ERROR_INPUT; } /* if required, change the numbering to 0 */ if (ctrl->numflag == 1) { Change2CNumbering(*nvtxs, xadj, adjncy); renumber = 1; } IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl)); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr)); /* prune the dense columns */ if (ctrl->pfactor > 0.0) { piperm = imalloc(*nvtxs, "OMETIS: piperm"); graph = PruneGraph(ctrl, *nvtxs, xadj, adjncy, vwgt, piperm, ctrl->pfactor); if (graph == NULL) { /* if there was no prunning, cleanup the pfactor */ gk_free((void **)&piperm, LTERM); ctrl->pfactor = 0.0; } else { nnvtxs = graph->nvtxs; ctrl->compress = 0; /* disable compression if prunning took place */ } } /* compress the graph; note that compression only happens if not prunning has taken place. */ if (ctrl->compress) { cptr = imalloc(*nvtxs+1, "OMETIS: cptr"); cind = imalloc(*nvtxs, "OMETIS: cind"); graph = CompressGraph(ctrl, *nvtxs, xadj, adjncy, vwgt, cptr, cind); if (graph == NULL) { /* if there was no compression, cleanup the compress flag */ gk_free((void **)&cptr, &cind, LTERM); ctrl->compress = 0; } else { nnvtxs = graph->nvtxs; ctrl->cfactor = 1.0*(*nvtxs)/nnvtxs; if (ctrl->cfactor > 1.5 && ctrl->nseps == 1) ctrl->nseps = 2; //ctrl->nseps = (idx_t)(ctrl->cfactor*ctrl->nseps); } } /* if no prunning and no compression, setup the graph in the normal way. */ if (ctrl->pfactor == 0.0 && ctrl->compress == 0) graph = SetupGraph(ctrl, *nvtxs, 1, xadj, adjncy, vwgt, NULL, NULL); ASSERT(CheckGraph(graph, ctrl->numflag, 1)); /* allocate workspace memory */ AllocateWorkSpace(ctrl, graph); /* do the nested dissection ordering */ if (ctrl->ccorder) MlevelNestedDissectionCC(ctrl, graph, iperm, graph->nvtxs); else MlevelNestedDissection(ctrl, graph, iperm, graph->nvtxs); if (ctrl->pfactor > 0.0) { /* Order any prunned vertices */ icopy(nnvtxs, iperm, perm); /* Use perm as an auxiliary array */ for (i=0; i<nnvtxs; i++) iperm[piperm[i]] = perm[i]; for (i=nnvtxs; i<*nvtxs; i++) iperm[piperm[i]] = i; gk_free((void **)&piperm, LTERM); } else if (ctrl->compress) { /* Uncompress the ordering */ /* construct perm from iperm */ for (i=0; i<nnvtxs; i++) perm[iperm[i]] = i; for (l=ii=0; ii<nnvtxs; ii++) { i = perm[ii]; for (j=cptr[i]; j<cptr[i+1]; j++) iperm[cind[j]] = l++; } gk_free((void **)&cptr, &cind, LTERM); } for (i=0; i<*nvtxs; i++) perm[iperm[i]] = i; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr)); IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl)); /* clean up */ FreeCtrl(&ctrl); SIGTHROW: /* if required, change the numbering back to 1 */ if (renumber) Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); gk_siguntrap(); gk_malloc_cleanup(0); return metis_rcode(sigrval); }
void FM_2WayNodeRefine1Sided(ctrl_t *ctrl, graph_t *graph, idx_t niter) { idx_t i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind, iend; idx_t *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr; idx_t *mptr, *mind, *swaps; rpq_t *queue; nrinfo_t *rinfo; idx_t higain, mincut, initcut, mincutorder; idx_t pass, to, other, limit; idx_t badmaxpwgt, mindiff, newdiff; real_t mult; WCOREPUSH; nvtxs = graph->nvtxs; xadj = graph->xadj; adjncy = graph->adjncy; vwgt = graph->vwgt; bndind = graph->bndind; bndptr = graph->bndptr; where = graph->where; pwgts = graph->pwgts; rinfo = graph->nrinfo; queue = rpqCreate(nvtxs); swaps = iwspacemalloc(ctrl, nvtxs); mptr = iwspacemalloc(ctrl, nvtxs+1); mind = iwspacemalloc(ctrl, 2*nvtxs); mult = 0.5*ctrl->ubfactors[0]; badmaxpwgt = (idx_t)(mult*(pwgts[0]+pwgts[1]+pwgts[2])); IFSET(ctrl->dbglvl, METIS_DBG_REFINE, printf("Partitions-N1: [%6"PRIDX" %6"PRIDX"] Nv-Nb[%6"PRIDX" %6"PRIDX"]. ISep: %6"PRIDX"\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut)); to = (pwgts[0] < pwgts[1] ? 1 : 0); for (pass=0; pass<2*niter; pass++) { /* the 2*niter is for the two sides */ other = to; to = (to+1)%2; rpqReset(queue); mincutorder = -1; initcut = mincut = graph->mincut; nbnd = graph->nbnd; /* use the swaps array in place of the traditional perm array to save memory */ irandArrayPermute(nbnd, swaps, nbnd, 1); for (ii=0; ii<nbnd; ii++) { i = bndind[swaps[ii]]; ASSERT(where[i] == 2); rpqInsert(queue, i, vwgt[i]-rinfo[i].edegrees[other]); } ASSERT(CheckNodeBnd(graph, nbnd)); ASSERT(CheckNodePartitionParams(graph)); limit = (ctrl->compress ? gk_min(5*nbnd, 500) : gk_min(3*nbnd, 300)); /****************************************************** * Get into the FM loop *******************************************************/ IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->Aux3Tmr)); mptr[0] = nmind = 0; mindiff = iabs(pwgts[0]-pwgts[1]); for (nswaps=0; nswaps<nvtxs; nswaps++) { if ((higain = rpqGetTop(queue)) == -1) break; ASSERT(bndptr[higain] != -1); /* The following check is to ensure we break out if there is a posibility of over-running the mind array. */ if (nmind + xadj[higain+1]-xadj[higain] >= 2*nvtxs-1) break; if (pwgts[to]+vwgt[higain] > badmaxpwgt) break; /* No point going any further. Balance will be bad */ pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]); newdiff = iabs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other])); if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) { mincut = pwgts[2]; mincutorder = nswaps; mindiff = newdiff; } else { if (nswaps - mincutorder > 3*limit || (nswaps - mincutorder > limit && pwgts[2] > 1.10*mincut)) { pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]); break; /* No further improvement, break out */ } } BNDDelete(nbnd, bndind, bndptr, higain); pwgts[to] += vwgt[higain]; where[higain] = to; swaps[nswaps] = higain; /********************************************************** * Update the degrees of the affected nodes ***********************************************************/ IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->Aux1Tmr)); for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */ rinfo[k].edegrees[to] += vwgt[higain]; } else if (where[k] == other) { /* This vertex is pulled into the separator */ ASSERTP(bndptr[k] == -1, ("%"PRIDX" %"PRIDX" %"PRIDX"\n", k, bndptr[k], where[k])); BNDInsert(nbnd, bndind, bndptr, k); mind[nmind++] = k; /* Keep track for rollback */ where[k] = 2; pwgts[other] -= vwgt[k]; edegrees = rinfo[k].edegrees; edegrees[0] = edegrees[1] = 0; for (jj=xadj[k], iend=xadj[k+1]; jj<iend; jj++) { kk = adjncy[jj]; if (where[kk] != 2) edegrees[where[kk]] += vwgt[kk]; else { rinfo[kk].edegrees[other] -= vwgt[k]; /* Since the moves are one-sided this vertex has not been moved yet */ rpqUpdate(queue, kk, vwgt[kk]-rinfo[kk].edegrees[other]); } } /* Insert the new vertex into the priority queue. Safe due to one-sided moves */ rpqInsert(queue, k, vwgt[k]-edegrees[other]); } } mptr[nswaps+1] = nmind; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux1Tmr)); IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, printf("Moved %6"PRIDX" to %3"PRIDX", Gain: %5"PRIDX" [%5"PRIDX"] \t[%5"PRIDX" %5"PRIDX" %5"PRIDX"] [%3"PRIDX" %2"PRIDX"]\n", higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit)); } IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux3Tmr)); /**************************************************************** * Roll back computation *****************************************************************/ IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->Aux2Tmr)); for (nswaps--; nswaps>mincutorder; nswaps--) { higain = swaps[nswaps]; ASSERT(CheckNodePartitionParams(graph)); ASSERT(where[higain] == to); INC_DEC(pwgts[2], pwgts[to], vwgt[higain]); where[higain] = 2; BNDInsert(nbnd, bndind, bndptr, higain); edegrees = rinfo[higain].edegrees; edegrees[0] = edegrees[1] = 0; for (j=xadj[higain]; j<xadj[higain+1]; j++) { k = adjncy[j]; if (where[k] == 2) rinfo[k].edegrees[to] -= vwgt[higain]; else edegrees[where[k]] += vwgt[k]; } /* Push nodes out of the separator */ for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) { k = mind[j]; ASSERT(where[k] == 2); where[k] = other; INC_DEC(pwgts[other], pwgts[2], vwgt[k]); BNDDelete(nbnd, bndind, bndptr, k); for (jj=xadj[k], iend=xadj[k+1]; jj<iend; jj++) { kk = adjncy[jj]; if (where[kk] == 2) rinfo[kk].edegrees[other] += vwgt[k]; } } } IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux2Tmr)); ASSERT(mincut == pwgts[2]); IFSET(ctrl->dbglvl, METIS_DBG_REFINE, printf("\tMinimum sep: %6"PRIDX" at %5"PRIDX", PWGTS: [%6"PRIDX" %6"PRIDX"], NBND: %6"PRIDX"\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd)); graph->mincut = mincut; graph->nbnd = nbnd; if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut)) break; } rpqDestroy(queue); WCOREPOP; }
void RefineKWay(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph) { idx_t i, nlevels, contig=ctrl->contig; graph_t *ptr; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr)); /* Determine how many levels are there */ for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++); /* Compute the parameters of the coarsest graph */ ComputeKWayPartitionParams(ctrl, graph); /* Try to minimize the sub-domain connectivity */ if (ctrl->minconn) EliminateSubDomainEdges(ctrl, graph); /* Deal with contiguity constraints at the beginning */ if (contig && FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) { EliminateComponents(ctrl, graph); ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 5, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE); ctrl->contig = 0; } /* Refine each successively finer graph */ for (i=0; ;i++) { if (ctrl->minconn && i == nlevels/2) EliminateSubDomainEdges(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->RefTmr)); if (2*i >= nlevels && !IsBalanced(ctrl, graph, .02)) { ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 1, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); } Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 5.0, OMODE_REFINE); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->RefTmr)); /* Deal with contiguity constraints in the middle */ if (contig && i == nlevels/2) { if (FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) { EliminateComponents(ctrl, graph); if (!IsBalanced(ctrl, graph, .02)) { ctrl->contig = 1; ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 5, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE); ctrl->contig = 0; } } } if (graph == orggraph) break; graph = graph->finer; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); ASSERT(graph->vwgt != NULL); ProjectKWayPartition(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); } /* Deal with contiguity requirement at the end */ ctrl->contig = contig; if (contig && FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) EliminateComponents(ctrl, graph); if (!IsBalanced(ctrl, graph, 0.0)) { ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); Greedy_KWayOptimize(ctrl, graph, 10, 0, OMODE_BALANCE); ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE); } if (ctrl->contig) ASSERT(FindPartitionInducedComponents(graph, graph->where, NULL, NULL) == ctrl->nparts); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr)); }
/************************************************************************* * This function creates the coarser graph **************************************************************************/ void CreateCoarseGraphNoMask(CtrlType *ctrl, GraphType *graph, idxtype cnvtxs, idxtype *match, idxtype *perm) { idxtype i, j, k, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, dovsize; idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj; idxtype *cmap, *htable; idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum; float *nvwgt, *cnvwgt; GraphType *cgraph; dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0); IFSET(ctrl->dbglvl, DBG_TIME, gk_startcputimer(ctrl->ContractTmr)); nvtxs = graph->nvtxs; ncon = graph->ncon; xadj = graph->xadj; vwgt = graph->vwgt; vsize = graph->vsize; nvwgt = graph->nvwgt; adjncy = graph->adjncy; adjwgt = graph->adjwgt; adjwgtsum = graph->adjwgtsum; cmap = graph->cmap; /* Initialize the coarser graph */ cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize); cxadj = cgraph->xadj; cvwgt = cgraph->vwgt; cvsize = cgraph->vsize; cnvwgt = cgraph->nvwgt; cadjwgtsum = cgraph->adjwgtsum; cadjncy = cgraph->adjncy; cadjwgt = cgraph->adjwgt; htable = idxset(cnvtxs, -1, idxwspacemalloc(ctrl, cnvtxs)); iend = xadj[nvtxs]; auxadj = ctrl->wspace.auxcore; memcpy(auxadj, adjncy, iend*sizeof(idxtype)); for (i=0; i<iend; i++) auxadj[i] = cmap[auxadj[i]]; cxadj[0] = cnvtxs = cnedges = 0; for (i=0; i<nvtxs; i++) { v = perm[i]; if (cmap[v] != cnvtxs) continue; u = match[v]; if (ncon == 1) cvwgt[cnvtxs] = vwgt[v]; else gk_fcopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon); if (dovsize) cvsize[cnvtxs] = vsize[v]; cadjwgtsum[cnvtxs] = adjwgtsum[v]; nedges = 0; istart = xadj[v]; iend = xadj[v+1]; for (j=istart; j<iend; j++) { k = auxadj[j]; if ((m = htable[k]) == -1) { cadjncy[nedges] = k; cadjwgt[nedges] = adjwgt[j]; htable[k] = nedges++; } else { cadjwgt[m] += adjwgt[j]; } } if (v != u) { if (ncon == 1) cvwgt[cnvtxs] += vwgt[u]; else gk_faxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1); if (dovsize) cvsize[cnvtxs] += vsize[u]; cadjwgtsum[cnvtxs] += adjwgtsum[u]; istart = xadj[u]; iend = xadj[u+1]; for (j=istart; j<iend; j++) { k = auxadj[j]; if ((m = htable[k]) == -1) { cadjncy[nedges] = k; cadjwgt[nedges] = adjwgt[j]; htable[k] = nedges++; } else { cadjwgt[m] += adjwgt[j]; } } /* Remove the contracted adjacency weight */ if ((j = htable[cnvtxs]) != -1) { ASSERT(cadjncy[j] == cnvtxs); cadjwgtsum[cnvtxs] -= cadjwgt[j]; cadjncy[j] = cadjncy[--nedges]; cadjwgt[j] = cadjwgt[nedges]; htable[cnvtxs] = -1; } } ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d\n", cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt))); for (j=0; j<nedges; j++) htable[cadjncy[j]] = -1; /* Zero out the htable */ cnedges += nedges; cxadj[++cnvtxs] = cnedges; cadjncy += nedges; cadjwgt += nedges; } cgraph->nedges = cnedges; ReAdjustMemory(graph, cgraph, dovsize); IFSET(ctrl->dbglvl, DBG_TIME, gk_stopcputimer(ctrl->ContractTmr)); idxwspacefree(ctrl, cnvtxs); }