Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/ometis.c
3206 views
/*1* Copyright 1997, Regents of the University of Minnesota2*3* ometis.c4*5* This file contains the top level routines for the multilevel recursive6* bisection algorithm PMETIS.7*8* Started 7/24/979* George10*11* $Id: ometis.c 10513 2011-07-07 22:06:03Z karypis $12*13*/1415#include "metislib.h"161718/*************************************************************************/19/*! This function is the entry point for the multilevel nested dissection20ordering code. At each bisection, a node-separator is computed using21a node-based refinement approach.2223\param nvtxs is the number of vertices in the graph.24\param xadj is of length nvtxs+1 marking the start of the adjancy25list of each vertex in adjncy.26\param adjncy stores the adjacency lists of the vertices. The adjnacy27list of a vertex should not contain the vertex itself.28\param vwgt is an array of size nvtxs storing the weight of each29vertex. If vwgt is NULL, then the vertices are considered30to have unit weight.31\param numflag is either 0 or 1 indicating that the numbering of32the vertices starts from 0 or 1, respectively.33\param options is an array of size METIS_NOPTIONS used to pass34various options impacting the of the algorithm. A NULL35value indicates use of default options.36\param perm is an array of size nvtxs such that if A and A' are37the original and permuted matrices, then A'[i] = A[perm[i]].38\param iperm is an array of size nvtxs such that if A and A' are39the original and permuted matrices, then A[i] = A'[iperm[i]].40*/41/*************************************************************************/42int METIS_NodeND(idx_t *nvtxs, idx_t *xadj, idx_t *adjncy, idx_t *vwgt,43idx_t *options, idx_t *perm, idx_t *iperm)44{45int sigrval=0, renumber=0;46idx_t i, ii, j, l, nnvtxs=0;47graph_t *graph=NULL;48ctrl_t *ctrl;49idx_t *cptr, *cind, *piperm;50int numflag = 0;5152/* set up malloc cleaning code and signal catchers */53if (!gk_malloc_init())54return METIS_ERROR_MEMORY;5556gk_sigtrap();5758if ((sigrval = gk_sigcatch()) != 0)59goto SIGTHROW;606162/* set up the run time parameters */63ctrl = SetupCtrl(METIS_OP_OMETIS, options, 1, 3, NULL, NULL);64if (!ctrl) {65gk_siguntrap();66return METIS_ERROR_INPUT;67}6869/* if required, change the numbering to 0 */70if (ctrl->numflag == 1) {71Change2CNumbering(*nvtxs, xadj, adjncy);72renumber = 1;73}7475IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl));76IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr));7778/* prune the dense columns */79if (ctrl->pfactor > 0.0) {80piperm = imalloc(*nvtxs, "OMETIS: piperm");8182graph = PruneGraph(ctrl, *nvtxs, xadj, adjncy, vwgt, piperm, ctrl->pfactor);83if (graph == NULL) {84/* if there was no prunning, cleanup the pfactor */85gk_free((void **)&piperm, LTERM);86ctrl->pfactor = 0.0;87}88else {89nnvtxs = graph->nvtxs;90ctrl->compress = 0; /* disable compression if prunning took place */91}92}9394/* compress the graph; note that compression only happens if not prunning95has taken place. */96if (ctrl->compress) {97cptr = imalloc(*nvtxs+1, "OMETIS: cptr");98cind = imalloc(*nvtxs, "OMETIS: cind");99100graph = CompressGraph(ctrl, *nvtxs, xadj, adjncy, vwgt, cptr, cind);101if (graph == NULL) {102/* if there was no compression, cleanup the compress flag */103gk_free((void **)&cptr, &cind, LTERM);104ctrl->compress = 0;105}106else {107nnvtxs = graph->nvtxs;108ctrl->cfactor = 1.0*(*nvtxs)/nnvtxs;109if (ctrl->cfactor > 1.5 && ctrl->nseps == 1)110ctrl->nseps = 2;111//ctrl->nseps = (idx_t)(ctrl->cfactor*ctrl->nseps);112}113}114115/* if no prunning and no compression, setup the graph in the normal way. */116if (ctrl->pfactor == 0.0 && ctrl->compress == 0)117graph = SetupGraph(ctrl, *nvtxs, 1, xadj, adjncy, vwgt, NULL, NULL);118119ASSERT(CheckGraph(graph, ctrl->numflag, 1));120121/* allocate workspace memory */122AllocateWorkSpace(ctrl, graph);123124/* do the nested dissection ordering */125if (ctrl->ccorder)126MlevelNestedDissectionCC(ctrl, graph, iperm, graph->nvtxs);127else128MlevelNestedDissection(ctrl, graph, iperm, graph->nvtxs);129130131if (ctrl->pfactor > 0.0) { /* Order any prunned vertices */132icopy(nnvtxs, iperm, perm); /* Use perm as an auxiliary array */133for (i=0; i<nnvtxs; i++)134iperm[piperm[i]] = perm[i];135for (i=nnvtxs; i<*nvtxs; i++)136iperm[piperm[i]] = i;137138gk_free((void **)&piperm, LTERM);139}140else if (ctrl->compress) { /* Uncompress the ordering */141/* construct perm from iperm */142for (i=0; i<nnvtxs; i++)143perm[iperm[i]] = i;144for (l=ii=0; ii<nnvtxs; ii++) {145i = perm[ii];146for (j=cptr[i]; j<cptr[i+1]; j++)147iperm[cind[j]] = l++;148}149150gk_free((void **)&cptr, &cind, LTERM);151}152153for (i=0; i<*nvtxs; i++)154perm[iperm[i]] = i;155156IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr));157IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl));158159/* clean up */160FreeCtrl(&ctrl);161162SIGTHROW:163/* if required, change the numbering back to 1 */164if (renumber)165Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);166167gk_siguntrap();168gk_malloc_cleanup(0);169170return metis_rcode(sigrval);171}172173174/*************************************************************************/175/*! This is the driver for the recursive tri-section of a graph into the176left, separator, and right partitions. The graphs correspond to the177left and right parts are further tri-sected in a recursive fashion.178The nodes in the separator are ordered at the end of the left & right179nodes.180*/181/*************************************************************************/182void MlevelNestedDissection(ctrl_t *ctrl, graph_t *graph, idx_t *order,183idx_t lastvtx)184{185idx_t i, j, nvtxs, nbnd;186idx_t *label, *bndind;187graph_t *lgraph, *rgraph;188189nvtxs = graph->nvtxs;190191MlevelNodeBisectionMultiple(ctrl, graph);192193IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO,194printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n",195graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));196197198/* Order the nodes in the separator */199nbnd = graph->nbnd;200bndind = graph->bndind;201label = graph->label;202for (i=0; i<nbnd; i++)203order[label[bndind[i]]] = --lastvtx;204205SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);206207/* Free the memory of the top level graph */208FreeGraph(&graph);209210/* Recurse on lgraph first, as its lastvtx depends on rgraph->nvtxs, which211will not be defined upon return from MlevelNestedDissection. */212if (lgraph->nvtxs > MMDSWITCH && lgraph->nedges > 0)213MlevelNestedDissection(ctrl, lgraph, order, lastvtx-rgraph->nvtxs);214else {215MMDOrder(ctrl, lgraph, order, lastvtx-rgraph->nvtxs);216FreeGraph(&lgraph);217}218if (rgraph->nvtxs > MMDSWITCH && rgraph->nedges > 0)219MlevelNestedDissection(ctrl, rgraph, order, lastvtx);220else {221MMDOrder(ctrl, rgraph, order, lastvtx);222FreeGraph(&rgraph);223}224}225226227/*************************************************************************/228/*! This routine is similar to its non 'CC' counterpart. The difference is229that after each tri-section, the connected components of the original230graph that result after removing the separator vertises are ordered231independently (i.e., this may lead to more than just the left and232the right subgraphs).233*/234/*************************************************************************/235void MlevelNestedDissectionCC(ctrl_t *ctrl, graph_t *graph, idx_t *order,236idx_t lastvtx)237{238idx_t i, j, nvtxs, nbnd, ncmps, rnvtxs, snvtxs;239idx_t *label, *bndind;240idx_t *cptr, *cind;241graph_t **sgraphs;242243nvtxs = graph->nvtxs;244245MlevelNodeBisectionMultiple(ctrl, graph);246247IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO,248printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n",249graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));250251/* Order the nodes in the separator */252nbnd = graph->nbnd;253bndind = graph->bndind;254label = graph->label;255for (i=0; i<nbnd; i++)256order[label[bndind[i]]] = --lastvtx;257258WCOREPUSH;259cptr = iwspacemalloc(ctrl, nvtxs+1);260cind = iwspacemalloc(ctrl, nvtxs);261ncmps = FindSepInducedComponents(ctrl, graph, cptr, cind);262263if (ctrl->dbglvl&METIS_DBG_INFO) {264if (ncmps > 2)265printf(" Bisection resulted in %"PRIDX" connected components\n", ncmps);266}267268sgraphs = SplitGraphOrderCC(ctrl, graph, ncmps, cptr, cind);269270WCOREPOP;271272/* Free the memory of the top level graph */273FreeGraph(&graph);274275/* Go and process the subgraphs */276for (rnvtxs=i=0; i<ncmps; i++) {277/* Save the number of vertices in sgraphs[i] because sgraphs[i] is freed278inside MlevelNestedDissectionCC, and as such it will be undefined. */279snvtxs = sgraphs[i]->nvtxs;280281if (sgraphs[i]->nvtxs > MMDSWITCH && sgraphs[i]->nedges > 0) {282MlevelNestedDissectionCC(ctrl, sgraphs[i], order, lastvtx-rnvtxs);283}284else {285MMDOrder(ctrl, sgraphs[i], order, lastvtx-rnvtxs);286FreeGraph(&sgraphs[i]);287}288rnvtxs += snvtxs;289}290291gk_free((void **)&sgraphs, LTERM);292}293294295/*************************************************************************/296/*! This function performs multilevel node bisection (i.e., tri-section).297It performs multiple bisections and selects the best. */298/*************************************************************************/299void MlevelNodeBisectionMultiple(ctrl_t *ctrl, graph_t *graph)300{301idx_t i, mincut;302idx_t *bestwhere;303304/* if the graph is small, just find a single vertex separator */305if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->compress ? 1000 : 2000)) {306MlevelNodeBisectionL2(ctrl, graph, LARGENIPARTS);307return;308}309310WCOREPUSH;311312bestwhere = iwspacemalloc(ctrl, graph->nvtxs);313314mincut = graph->tvwgt[0];315for (i=0; i<ctrl->nseps; i++) {316MlevelNodeBisectionL2(ctrl, graph, LARGENIPARTS);317318if (i == 0 || graph->mincut < mincut) {319mincut = graph->mincut;320if (i < ctrl->nseps-1)321icopy(graph->nvtxs, graph->where, bestwhere);322}323324if (mincut == 0)325break;326327if (i < ctrl->nseps-1)328FreeRData(graph);329}330331if (mincut != graph->mincut) {332icopy(graph->nvtxs, bestwhere, graph->where);333Compute2WayNodePartitionParams(ctrl, graph);334}335336WCOREPOP;337}338339340/*************************************************************************/341/*! This function performs multilevel node bisection (i.e., tri-section).342It performs multiple bisections and selects the best. */343/*************************************************************************/344void MlevelNodeBisectionL2(ctrl_t *ctrl, graph_t *graph, idx_t niparts)345{346idx_t i, mincut, nruns=5;347graph_t *cgraph;348idx_t *bestwhere;349350/* if the graph is small, just find a single vertex separator */351if (graph->nvtxs < 5000) {352MlevelNodeBisectionL1(ctrl, graph, niparts);353return;354}355356WCOREPUSH;357358ctrl->CoarsenTo = gk_max(100, graph->nvtxs/30);359360cgraph = CoarsenGraphNlevels(ctrl, graph, 4);361362bestwhere = iwspacemalloc(ctrl, cgraph->nvtxs);363364mincut = graph->tvwgt[0];365for (i=0; i<nruns; i++) {366MlevelNodeBisectionL1(ctrl, cgraph, 0.7*niparts);367368if (i == 0 || cgraph->mincut < mincut) {369mincut = cgraph->mincut;370if (i < nruns-1)371icopy(cgraph->nvtxs, cgraph->where, bestwhere);372}373374if (mincut == 0)375break;376377if (i < nruns-1)378FreeRData(cgraph);379}380381if (mincut != cgraph->mincut)382icopy(cgraph->nvtxs, bestwhere, cgraph->where);383384WCOREPOP;385386Refine2WayNode(ctrl, graph, cgraph);387388}389390391/*************************************************************************/392/*! The top-level routine of the actual multilevel node bisection */393/*************************************************************************/394void MlevelNodeBisectionL1(ctrl_t *ctrl, graph_t *graph, idx_t niparts)395{396graph_t *cgraph;397398ctrl->CoarsenTo = graph->nvtxs/8;399if (ctrl->CoarsenTo > 100)400ctrl->CoarsenTo = 100;401else if (ctrl->CoarsenTo < 40)402ctrl->CoarsenTo = 40;403404cgraph = CoarsenGraph(ctrl, graph);405406niparts = gk_max(1, (cgraph->nvtxs <= ctrl->CoarsenTo ? niparts/2: niparts));407/*niparts = (cgraph->nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);*/408InitSeparator(ctrl, cgraph, niparts);409410Refine2WayNode(ctrl, graph, cgraph);411}412413414/*************************************************************************/415/*! This function takes a graph and a tri-section (left, right, separator)416and splits it into two graphs.417418This function relies on the fact that adjwgt is all equal to 1.419*/420/*************************************************************************/421void SplitGraphOrder(ctrl_t *ctrl, graph_t *graph, graph_t **r_lgraph,422graph_t **r_rgraph)423{424idx_t i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3];425idx_t *xadj, *vwgt, *adjncy, *adjwgt, *label, *where, *bndptr, *bndind;426idx_t *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *slabel[2];427idx_t *rename;428idx_t *auxadjncy;429graph_t *lgraph, *rgraph;430431WCOREPUSH;432433IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->SplitTmr));434435nvtxs = graph->nvtxs;436xadj = graph->xadj;437vwgt = graph->vwgt;438adjncy = graph->adjncy;439adjwgt = graph->adjwgt;440label = graph->label;441where = graph->where;442bndptr = graph->bndptr;443bndind = graph->bndind;444ASSERT(bndptr != NULL);445446rename = iwspacemalloc(ctrl, nvtxs);447448snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0;449for (i=0; i<nvtxs; i++) {450k = where[i];451rename[i] = snvtxs[k]++;452snedges[k] += xadj[i+1]-xadj[i];453}454455lgraph = SetupSplitGraph(graph, snvtxs[0], snedges[0]);456sxadj[0] = lgraph->xadj;457svwgt[0] = lgraph->vwgt;458sadjncy[0] = lgraph->adjncy;459sadjwgt[0] = lgraph->adjwgt;460slabel[0] = lgraph->label;461462rgraph = SetupSplitGraph(graph, snvtxs[1], snedges[1]);463sxadj[1] = rgraph->xadj;464svwgt[1] = rgraph->vwgt;465sadjncy[1] = rgraph->adjncy;466sadjwgt[1] = rgraph->adjwgt;467slabel[1] = rgraph->label;468469/* Go and use bndptr to also mark the boundary nodes in the two partitions */470for (ii=0; ii<graph->nbnd; ii++) {471i = bndind[ii];472for (j=xadj[i]; j<xadj[i+1]; j++)473bndptr[adjncy[j]] = 1;474}475476snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;477sxadj[0][0] = sxadj[1][0] = 0;478for (i=0; i<nvtxs; i++) {479if ((mypart = where[i]) == 2)480continue;481482istart = xadj[i];483iend = xadj[i+1];484if (bndptr[i] == -1) { /* This is an interior vertex */485auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;486for(j=istart; j<iend; j++)487auxadjncy[j] = adjncy[j];488snedges[mypart] += iend-istart;489}490else {491auxadjncy = sadjncy[mypart];492l = snedges[mypart];493for (j=istart; j<iend; j++) {494k = adjncy[j];495if (where[k] == mypart)496auxadjncy[l++] = k;497}498snedges[mypart] = l;499}500501svwgt[mypart][snvtxs[mypart]] = vwgt[i];502slabel[mypart][snvtxs[mypart]] = label[i];503sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];504}505506for (mypart=0; mypart<2; mypart++) {507iend = snedges[mypart];508iset(iend, 1, sadjwgt[mypart]);509510auxadjncy = sadjncy[mypart];511for (i=0; i<iend; i++)512auxadjncy[i] = rename[auxadjncy[i]];513}514515lgraph->nvtxs = snvtxs[0];516lgraph->nedges = snedges[0];517rgraph->nvtxs = snvtxs[1];518rgraph->nedges = snedges[1];519520SetupGraph_tvwgt(lgraph);521SetupGraph_tvwgt(rgraph);522523IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->SplitTmr));524525*r_lgraph = lgraph;526*r_rgraph = rgraph;527528WCOREPOP;529}530531532/*************************************************************************/533/*! This function takes a graph and generates a set of graphs, each of534which is a connected component in the original graph.535536This function relies on the fact that adjwgt is all equal to 1.537538\param ctrl stores run state info.539\param graph is the graph to be split.540\param ncmps is the number of connected components.541\param cptr is an array of size ncmps+1 that marks the start and end542locations of the vertices in cind that make up the respective543components (i.e., cptr, cind is in CSR format).544\param cind is an array of size equal to the number of vertices in545the original graph and stores the vertices that belong to each546connected component.547548\returns an array of subgraphs corresponding to the extracted subgraphs.549*/550/*************************************************************************/551graph_t **SplitGraphOrderCC(ctrl_t *ctrl, graph_t *graph, idx_t ncmps,552idx_t *cptr, idx_t *cind)553{554idx_t i, ii, iii, j, k, l, istart, iend, mypart, nvtxs, snvtxs, snedges;555idx_t *xadj, *vwgt, *adjncy, *adjwgt, *label, *where, *bndptr, *bndind;556idx_t *sxadj, *svwgt, *sadjncy, *sadjwgt, *slabel;557idx_t *rename;558idx_t *auxadjncy;559graph_t **sgraphs;560561WCOREPUSH;562563IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->SplitTmr));564565nvtxs = graph->nvtxs;566xadj = graph->xadj;567vwgt = graph->vwgt;568adjncy = graph->adjncy;569adjwgt = graph->adjwgt;570label = graph->label;571where = graph->where;572bndptr = graph->bndptr;573bndind = graph->bndind;574ASSERT(bndptr != NULL);575576/* Go and use bndptr to also mark the boundary nodes in the two partitions */577for (ii=0; ii<graph->nbnd; ii++) {578i = bndind[ii];579for (j=xadj[i]; j<xadj[i+1]; j++)580bndptr[adjncy[j]] = 1;581}582583rename = iwspacemalloc(ctrl, nvtxs);584585sgraphs = (graph_t **)gk_malloc(sizeof(graph_t *)*ncmps, "SplitGraphOrderCC: sgraphs");586587/* Go and split the graph a component at a time */588for (iii=0; iii<ncmps; iii++) {589irandArrayPermute(cptr[iii+1]-cptr[iii], cind+cptr[iii], cptr[iii+1]-cptr[iii], 0);590snvtxs = snedges = 0;591for (j=cptr[iii]; j<cptr[iii+1]; j++) {592i = cind[j];593rename[i] = snvtxs++;594snedges += xadj[i+1]-xadj[i];595}596597sgraphs[iii] = SetupSplitGraph(graph, snvtxs, snedges);598599sxadj = sgraphs[iii]->xadj;600svwgt = sgraphs[iii]->vwgt;601sadjncy = sgraphs[iii]->adjncy;602sadjwgt = sgraphs[iii]->adjwgt;603slabel = sgraphs[iii]->label;604605snvtxs = snedges = sxadj[0] = 0;606for (ii=cptr[iii]; ii<cptr[iii+1]; ii++) {607i = cind[ii];608609istart = xadj[i];610iend = xadj[i+1];611if (bndptr[i] == -1) { /* This is an interior vertex */612auxadjncy = sadjncy + snedges - istart;613for(j=istart; j<iend; j++)614auxadjncy[j] = adjncy[j];615snedges += iend-istart;616}617else {618l = snedges;619for (j=istart; j<iend; j++) {620k = adjncy[j];621if (where[k] != 2)622sadjncy[l++] = k;623}624snedges = l;625}626627svwgt[snvtxs] = vwgt[i];628slabel[snvtxs] = label[i];629sxadj[++snvtxs] = snedges;630}631632iset(snedges, 1, sadjwgt);633for (i=0; i<snedges; i++)634sadjncy[i] = rename[sadjncy[i]];635636sgraphs[iii]->nvtxs = snvtxs;637sgraphs[iii]->nedges = snedges;638639SetupGraph_tvwgt(sgraphs[iii]);640}641642IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->SplitTmr));643644WCOREPOP;645646return sgraphs;647}648649650/*************************************************************************/651/*! This function uses MMD to order the graph. The vertices are numbered652from lastvtx downwards. */653/*************************************************************************/654void MMDOrder(ctrl_t *ctrl, graph_t *graph, idx_t *order, idx_t lastvtx)655{656idx_t i, j, k, nvtxs, nofsub, firstvtx;657idx_t *xadj, *adjncy, *label;658idx_t *perm, *iperm, *head, *qsize, *list, *marker;659660WCOREPUSH;661662nvtxs = graph->nvtxs;663xadj = graph->xadj;664adjncy = graph->adjncy;665666/* Relabel the vertices so that it starts from 1 */667k = xadj[nvtxs];668for (i=0; i<k; i++)669adjncy[i]++;670for (i=0; i<nvtxs+1; i++)671xadj[i]++;672673perm = iwspacemalloc(ctrl, nvtxs+5);674iperm = iwspacemalloc(ctrl, nvtxs+5);675head = iwspacemalloc(ctrl, nvtxs+5);676qsize = iwspacemalloc(ctrl, nvtxs+5);677list = iwspacemalloc(ctrl, nvtxs+5);678marker = iwspacemalloc(ctrl, nvtxs+5);679680genmmd(nvtxs, xadj, adjncy, iperm, perm, 1, head, qsize, list, marker, IDX_MAX, &nofsub);681682label = graph->label;683firstvtx = lastvtx-nvtxs;684for (i=0; i<nvtxs; i++)685order[label[i]] = firstvtx+iperm[i]-1;686687/* Relabel the vertices so that it starts from 0 */688for (i=0; i<nvtxs+1; i++)689xadj[i]--;690k = xadj[nvtxs];691for (i=0; i<k; i++)692adjncy[i]--;693694WCOREPOP;695}696697698699700701702703