/************************************************************************* * This function takes a graph and produces a bisection of it **************************************************************************/ void MlevelNestedDissection(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx) { int i, j, nvtxs, nbnd, tvwgt, tpwgts2[2]; idxtype *label, *bndind; GraphType lgraph, rgraph; nvtxs = graph->nvtxs; /* Determine the weights of the partitions */ tvwgt = idxsum(nvtxs, graph->vwgt); tpwgts2[0] = tvwgt/2; tpwgts2[1] = tvwgt-tpwgts2[0]; switch (ctrl->optype) { case OP_OEMETIS: MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor); IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr)); ConstructMinCoverSeparator(ctrl, graph, ubfactor); IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr)); break; case OP_ONMETIS: 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])); break; } /* 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; SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); /* 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); if (rgraph.nvtxs > MMDSWITCH) MlevelNestedDissection(ctrl, &rgraph, order, ubfactor, lastvtx); else { MMDOrder(ctrl, &rgraph, order, lastvtx); /*GKfree(&rgraph.gdata, &rgraph.rdata, &rgraph.label, LTERM);*/ GKfree3((void**)&rgraph.gdata, (void**)&rgraph.rdata, (void**)&rgraph.label); } if (lgraph.nvtxs > MMDSWITCH) MlevelNestedDissection(ctrl, &lgraph, order, ubfactor, lastvtx-rgraph.nvtxs); else { MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs); /*GKfree(&lgraph.gdata, &lgraph.rdata, &lgraph.label, LTERM);*/ GKfree3((void**)&lgraph.gdata, (void**)&lgraph.rdata, (void**)&lgraph.label); } }
void MlevelNestedDissection(ctrl_t *ctrl, graph_t *graph, idx_t *order, idx_t lastvtx) { idx_t i, j, nvtxs, nbnd; idx_t *label, *bndind; graph_t *lgraph, *rgraph; nvtxs = graph->nvtxs; MlevelNodeBisectionMultiple(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO, printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\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; SplitGraphOrder(ctrl, graph, &lgraph, &rgraph); /* Free the memory of the top level graph */ FreeGraph(&graph); /* Recurse on lgraph first, as its lastvtx depends on rgraph->nvtxs, which will not be defined upon return from MlevelNestedDissection. */ if (lgraph->nvtxs > MMDSWITCH && lgraph->nedges > 0) MlevelNestedDissection(ctrl, lgraph, order, lastvtx-rgraph->nvtxs); else { MMDOrder(ctrl, lgraph, order, lastvtx-rgraph->nvtxs); FreeGraph(&lgraph); } if (rgraph->nvtxs > MMDSWITCH && rgraph->nedges > 0) MlevelNestedDissection(ctrl, rgraph, order, lastvtx); else { MMDOrder(ctrl, rgraph, order, lastvtx); FreeGraph(&rgraph); } }
/************************************************************************* * This function is the entry point for OEMETIS **************************************************************************/ void METIS_EdgeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm) { int i, j; GraphType graph; CtrlType ctrl; if (*numflag == 1) Change2CNumbering(*nvtxs, xadj, adjncy); SetUpGraph(&graph, OP_OEMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0); if (options[0] == 0) { /* Use the default parameters */ ctrl.CType = OEMETIS_CTYPE; ctrl.IType = OEMETIS_ITYPE; ctrl.RType = OEMETIS_RTYPE; ctrl.dbglvl = OEMETIS_DBGLVL; } else { ctrl.CType = options[OPTION_CTYPE]; ctrl.IType = options[OPTION_ITYPE]; ctrl.RType = options[OPTION_RTYPE]; ctrl.dbglvl = options[OPTION_DBGLVL]; } ctrl.oflags = 0; ctrl.pfactor = -1; ctrl.nseps = 1; ctrl.optype = OP_OEMETIS; ctrl.CoarsenTo = 20; ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo); InitRandom(-1); AllocateWorkSpace(&ctrl, &graph, 2); IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl)); IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr)); MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs); IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr)); IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl)); for (i=0; i<*nvtxs; i++) perm[iperm[i]] = i; FreeWorkSpace(&ctrl, &graph); if (*numflag == 1) Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm); }
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); }
/************************************************************************* * 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); } 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); } 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); } 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); }