Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/pmetis.c
3206 views
/**1\file2\brief This file contains the top level routines for the multilevel recursive bisection3algorithm PMETIS.45\date Started 7/24/19976\author George7\author Copyright 1997-2009, Regents of the University of Minnesota8\version\verbatim $Id: pmetis.c 10513 2011-07-07 22:06:03Z karypis $ \endverbatim9*/101112#include "metislib.h"131415/*************************************************************************/16/*! \ingroup api17\brief Recursive partitioning routine.1819This function computes a partitioning of a graph based on multilevel20recursive bisection. It can be used to partition a graph into \e k21parts. The objective of the partitioning is to minimize the edgecut22subject to one or more balancing constraints.2324\param[in] nvtxs is the number of vertices in the graph.2526\param[in] ncon is the number of balancing constraints. For the standard27partitioning problem in which each vertex is either unweighted28or has a single weight, ncon should be 1.2930\param[in] xadj is an array of size nvtxs+1 used to specify the starting31positions of the adjacency structure of the vertices in the32adjncy array.3334\param[in] adjncy is an array of size to the sum of the degrees of the35graph that stores for each vertex the set of vertices that36is adjancent to.3738\param[in] vwgt is an array of size nvtxs*ncon that stores the weights39of the vertices for each constraint. The ncon weights for the40ith vertex are stored in the ncon consecutive locations starting41at vwgt[i*ncon]. When ncon==1, a NULL value can be passed indicating42that all the vertices in the graph have the same weight.4344\param[in] adjwgt is an array of size equal to adjncy, specifying the weight45for each edge (i.e., adjwgt[j] corresponds to the weight of the46edge stored in adjncy[j]).47A NULL value can be passed indicating that all the edges in the48graph have the same weight.4950\param[in] nparts is the number of desired partitions.5152\param[in] tpwgts is an array of size nparts*ncon that specifies the53desired weight for each part and constraint. The \e{target partition54weight} for the ith part and jth constraint is specified55at tpwgts[i*ncon+j] (the numbering of i and j starts from 0).56For each constraint, the sum of the tpwgts[] entries must be571.0 (i.e., \f$ \sum_i tpwgts[i*ncon+j] = 1.0 \f$).58A NULL value can be passed indicating that the graph should59be equally divided among the parts.6061\param[in] ubvec is an array of size ncon that specifies the allowed62load imbalance tolerance for each constraint.63For the ith part and jth constraint the allowed weight is the64ubvec[j]*tpwgts[i*ncon+j] fraction of the jth's constraint total65weight. The load imbalances must be greater than 1.0.66A NULL value can be passed indicating that the load imbalance67tolerance for each constraint should be 1.001 (for ncon==1)68or 1.01 (for ncon>1).6970\params[in] options is the array for passing additional parameters71in order to customize the behaviour of the partitioning72algorithm.7374\params[out] edgecut stores the cut of the partitioning.7576\params[out] part is an array of size nvtxs used to store the77computed partitioning. The partition number for the ith78vertex is stored in part[i]. Based on the numflag parameter,79the numbering of the parts starts from either 0 or 1.808182\returns83\retval METIS_OK indicates that the function returned normally.84\retval METIS_ERROR_INPUT indicates an input error.85\retval METIS_ERROR_MEMORY indicates that it could not allocate86the required memory.8788*/89/*************************************************************************/90int METIS_PartGraphRecursive(idx_t *nvtxs, idx_t *ncon, idx_t *xadj,91idx_t *adjncy, idx_t *vwgt, idx_t *vsize, idx_t *adjwgt,92idx_t *nparts, real_t *tpwgts, real_t *ubvec, idx_t *options,93idx_t *objval, idx_t *part)94{95int sigrval=0, renumber=0;96graph_t *graph;97ctrl_t *ctrl;9899/* set up malloc cleaning code and signal catchers */100if (!gk_malloc_init())101return METIS_ERROR_MEMORY;102103gk_sigtrap();104105if ((sigrval = gk_sigcatch()) != 0)106goto SIGTHROW;107108109/* set up the run parameters */110ctrl = SetupCtrl(METIS_OP_PMETIS, options, *ncon, *nparts, tpwgts, ubvec);111if (!ctrl) {112gk_siguntrap();113return METIS_ERROR_INPUT;114}115116/* if required, change the numbering to 0 */117if (ctrl->numflag == 1) {118Change2CNumbering(*nvtxs, xadj, adjncy);119renumber = 1;120}121122/* set up the graph */123graph = SetupGraph(ctrl, *nvtxs, *ncon, xadj, adjncy, vwgt, vsize, adjwgt);124125/* allocate workspace memory */126AllocateWorkSpace(ctrl, graph);127128/* start the partitioning */129IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl));130IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr));131132*objval = MlevelRecursiveBisection(ctrl, graph, *nparts, part, ctrl->tpwgts, 0);133134IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr));135IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl));136137/* clean up */138FreeCtrl(&ctrl);139140SIGTHROW:141/* if required, change the numbering back to 1 */142if (renumber)143Change2FNumbering(*nvtxs, xadj, adjncy, part);144145gk_siguntrap();146gk_malloc_cleanup(0);147148return metis_rcode(sigrval);149}150151152/*************************************************************************/153/*! This function is the top-level driver of the recursive bisection154routine. */155/*************************************************************************/156idx_t MlevelRecursiveBisection(ctrl_t *ctrl, graph_t *graph, idx_t nparts,157idx_t *part, real_t *tpwgts, idx_t fpart)158{159idx_t i, j, nvtxs, ncon, objval;160idx_t *label, *where;161graph_t *lgraph, *rgraph;162real_t wsum, *tpwgts2;163164if ((nvtxs = graph->nvtxs) == 0) {165printf("\t***Cannot bisect a graph with 0 vertices!\n"166"\t***You are trying to partition a graph into too many parts!\n");167return 0;168}169170ncon = graph->ncon;171172/* determine the weights of the two partitions as a function of the weight of the173target partition weights */174WCOREPUSH;175tpwgts2 = rwspacemalloc(ctrl, 2*ncon);176for (i=0; i<ncon; i++) {177tpwgts2[i] = rsum((nparts>>1), tpwgts+i, ncon);178tpwgts2[ncon+i] = 1.0 - tpwgts2[i];179}180181/* perform the bisection */182objval = MultilevelBisect(ctrl, graph, tpwgts2);183184WCOREPOP;185186label = graph->label;187where = graph->where;188for (i=0; i<nvtxs; i++)189part[label[i]] = where[i] + fpart;190191if (nparts > 2)192SplitGraphPart(ctrl, graph, &lgraph, &rgraph);193194/* Free the memory of the top level graph */195FreeGraph(&graph);196197/* Scale the fractions in the tpwgts according to the true weight */198for (i=0; i<ncon; i++) {199wsum = rsum((nparts>>1), tpwgts+i, ncon);200rscale((nparts>>1), 1.0/wsum, tpwgts+i, ncon);201rscale(nparts-(nparts>>1), 1.0/(1.0-wsum), tpwgts+(nparts>>1)*ncon+i, ncon);202}203204/* Do the recursive call */205if (nparts > 3) {206objval += MlevelRecursiveBisection(ctrl, lgraph, (nparts>>1), part,207tpwgts, fpart);208objval += MlevelRecursiveBisection(ctrl, rgraph, nparts-(nparts>>1), part,209tpwgts+(nparts>>1)*ncon, fpart+(nparts>>1));210}211else if (nparts == 3) {212FreeGraph(&lgraph);213objval += MlevelRecursiveBisection(ctrl, rgraph, nparts-(nparts>>1), part,214tpwgts+(nparts>>1)*ncon, fpart+(nparts>>1));215}216217218return objval;219}220221222/*************************************************************************/223/*! This function performs a multilevel bisection */224/*************************************************************************/225idx_t MultilevelBisect(ctrl_t *ctrl, graph_t *graph, real_t *tpwgts)226{227idx_t i, niparts, bestobj=0, curobj=0, *bestwhere=NULL;228graph_t *cgraph;229real_t bestbal=0.0, curbal=0.0;230231Setup2WayBalMultipliers(ctrl, graph, tpwgts);232233WCOREPUSH;234235if (ctrl->ncuts > 1)236bestwhere = iwspacemalloc(ctrl, graph->nvtxs);237238for (i=0; i<ctrl->ncuts; i++) {239cgraph = CoarsenGraph(ctrl, graph);240241niparts = (cgraph->nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);242Init2WayPartition(ctrl, cgraph, tpwgts, niparts);243244Refine2Way(ctrl, graph, cgraph, tpwgts);245246curobj = graph->mincut;247curbal = ComputeLoadImbalanceDiff(graph, 2, ctrl->pijbm, ctrl->ubfactors);248249if (i == 0250|| (curbal <= 0.0005 && bestobj > curobj)251|| (bestbal > 0.0005 && curbal < bestbal)) {252bestobj = curobj;253bestbal = curbal;254if (i < ctrl->ncuts-1)255icopy(graph->nvtxs, graph->where, bestwhere);256}257258if (bestobj == 0)259break;260261if (i < ctrl->ncuts-1)262FreeRData(graph);263}264265if (bestobj != curobj) {266icopy(graph->nvtxs, bestwhere, graph->where);267Compute2WayPartitionParams(ctrl, graph);268}269270WCOREPOP;271272return bestobj;273}274275276/*************************************************************************/277/*! This function splits a graph into two based on its bisection */278/*************************************************************************/279void SplitGraphPart(ctrl_t *ctrl, graph_t *graph, graph_t **r_lgraph,280graph_t **r_rgraph)281{282idx_t i, j, k, l, istart, iend, mypart, nvtxs, ncon, snvtxs[2], snedges[2];283idx_t *xadj, *vwgt, *adjncy, *adjwgt, *label, *where, *bndptr;284idx_t *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *slabel[2];285idx_t *rename;286idx_t *auxadjncy, *auxadjwgt;287graph_t *lgraph, *rgraph;288289WCOREPUSH;290291IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->SplitTmr));292293nvtxs = graph->nvtxs;294ncon = graph->ncon;295xadj = graph->xadj;296vwgt = graph->vwgt;297adjncy = graph->adjncy;298adjwgt = graph->adjwgt;299label = graph->label;300where = graph->where;301bndptr = graph->bndptr;302303ASSERT(bndptr != NULL);304305rename = iwspacemalloc(ctrl, nvtxs);306307snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;308for (i=0; i<nvtxs; i++) {309k = where[i];310rename[i] = snvtxs[k]++;311snedges[k] += xadj[i+1]-xadj[i];312}313314lgraph = SetupSplitGraph(graph, snvtxs[0], snedges[0]);315sxadj[0] = lgraph->xadj;316svwgt[0] = lgraph->vwgt;317sadjncy[0] = lgraph->adjncy;318sadjwgt[0] = lgraph->adjwgt;319slabel[0] = lgraph->label;320321rgraph = SetupSplitGraph(graph, snvtxs[1], snedges[1]);322sxadj[1] = rgraph->xadj;323svwgt[1] = rgraph->vwgt;324sadjncy[1] = rgraph->adjncy;325sadjwgt[1] = rgraph->adjwgt;326slabel[1] = rgraph->label;327328snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;329sxadj[0][0] = sxadj[1][0] = 0;330for (i=0; i<nvtxs; i++) {331mypart = where[i];332333istart = xadj[i];334iend = xadj[i+1];335if (bndptr[i] == -1) { /* This is an interior vertex */336auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;337auxadjwgt = sadjwgt[mypart] + snedges[mypart] - istart;338for(j=istart; j<iend; j++) {339auxadjncy[j] = adjncy[j];340auxadjwgt[j] = adjwgt[j];341}342snedges[mypart] += iend-istart;343}344else {345auxadjncy = sadjncy[mypart];346auxadjwgt = sadjwgt[mypart];347l = snedges[mypart];348for (j=istart; j<iend; j++) {349k = adjncy[j];350if (where[k] == mypart) {351auxadjncy[l] = k;352auxadjwgt[l++] = adjwgt[j];353}354}355snedges[mypart] = l;356}357358/* copy vertex weights */359for (k=0; k<ncon; k++)360svwgt[mypart][snvtxs[mypart]*ncon+k] = vwgt[i*ncon+k];361362slabel[mypart][snvtxs[mypart]] = label[i];363sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];364}365366for (mypart=0; mypart<2; mypart++) {367iend = sxadj[mypart][snvtxs[mypart]];368auxadjncy = sadjncy[mypart];369for (i=0; i<iend; i++)370auxadjncy[i] = rename[auxadjncy[i]];371}372373lgraph->nedges = snedges[0];374rgraph->nedges = snedges[1];375376SetupGraph_tvwgt(lgraph);377SetupGraph_tvwgt(rgraph);378379IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->SplitTmr));380381*r_lgraph = lgraph;382*r_rgraph = rgraph;383384WCOREPOP;385}386387388389