Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/kwayrefine.c
3206 views
/*!1\file2\brief Driving routines for multilevel k-way refinement34\date Started 7/28/19975\author George6\author Copyright 1997-2009, Regents of the University of Minnesota7\version $Id: kwayrefine.c 10737 2011-09-13 13:37:25Z karypis $8*/910#include "metislib.h"111213/*************************************************************************/14/*! This function is the entry point of cut-based refinement */15/*************************************************************************/16void RefineKWay(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph)17{18idx_t i, nlevels, contig=ctrl->contig;19graph_t *ptr;2021IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->UncoarsenTmr));2223/* Determine how many levels are there */24for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);2526/* Compute the parameters of the coarsest graph */27ComputeKWayPartitionParams(ctrl, graph);2829/* Try to minimize the sub-domain connectivity */30if (ctrl->minconn)31EliminateSubDomainEdges(ctrl, graph);3233/* Deal with contiguity constraints at the beginning */34if (contig && FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) {35EliminateComponents(ctrl, graph);3637ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE);38Greedy_KWayOptimize(ctrl, graph, 5, 0, OMODE_BALANCE);3940ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE);41Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE);4243ctrl->contig = 0;44}4546/* Refine each successively finer graph */47for (i=0; ;i++) {48if (ctrl->minconn && i == nlevels/2)49EliminateSubDomainEdges(ctrl, graph);5051IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->RefTmr));5253if (2*i >= nlevels && !IsBalanced(ctrl, graph, .02)) {54ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE);55Greedy_KWayOptimize(ctrl, graph, 1, 0, OMODE_BALANCE);56ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE);57}5859Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 5.0, OMODE_REFINE);6061IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->RefTmr));6263/* Deal with contiguity constraints in the middle */64if (contig && i == nlevels/2) {65if (FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts) {66EliminateComponents(ctrl, graph);6768if (!IsBalanced(ctrl, graph, .02)) {69ctrl->contig = 1;70ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE);71Greedy_KWayOptimize(ctrl, graph, 5, 0, OMODE_BALANCE);7273ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE);74Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE);75ctrl->contig = 0;76}77}78}7980if (graph == orggraph)81break;8283graph = graph->finer;8485IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr));86ASSERT(graph->vwgt != NULL);8788ProjectKWayPartition(ctrl, graph);89IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr));90}9192/* Deal with contiguity requirement at the end */93ctrl->contig = contig;94if (contig && FindPartitionInducedComponents(graph, graph->where, NULL, NULL) > ctrl->nparts)95EliminateComponents(ctrl, graph);9697if (!IsBalanced(ctrl, graph, 0.0)) {98ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE);99Greedy_KWayOptimize(ctrl, graph, 10, 0, OMODE_BALANCE);100101ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE);102Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 0, OMODE_REFINE);103}104105if (ctrl->contig)106ASSERT(FindPartitionInducedComponents(graph, graph->where, NULL, NULL) == ctrl->nparts);107108IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->UncoarsenTmr));109}110111112/*************************************************************************/113/*! This function allocates memory for the k-way cut-based refinement */114/*************************************************************************/115void AllocateKWayPartitionMemory(ctrl_t *ctrl, graph_t *graph)116{117118graph->pwgts = imalloc(ctrl->nparts*graph->ncon, "AllocateKWayPartitionMemory: pwgts");119graph->where = imalloc(graph->nvtxs, "AllocateKWayPartitionMemory: where");120graph->bndptr = imalloc(graph->nvtxs, "AllocateKWayPartitionMemory: bndptr");121graph->bndind = imalloc(graph->nvtxs, "AllocateKWayPartitionMemory: bndind");122123switch (ctrl->objtype) {124case METIS_OBJTYPE_CUT:125graph->ckrinfo = (ckrinfo_t *)gk_malloc(graph->nvtxs*sizeof(ckrinfo_t),126"AllocateKWayPartitionMemory: ckrinfo");127break;128129case METIS_OBJTYPE_VOL:130graph->vkrinfo = (vkrinfo_t *)gk_malloc(graph->nvtxs*sizeof(vkrinfo_t),131"AllocateKWayVolPartitionMemory: vkrinfo");132133/* This is to let the cut-based -minconn and -contig large-scale graph134changes to go through */135graph->ckrinfo = (ckrinfo_t *)graph->vkrinfo;136break;137138default:139gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);140}141142}143144145/*************************************************************************/146/*! This function computes the initial id/ed for cut-based partitioning */147/**************************************************************************/148void ComputeKWayPartitionParams(ctrl_t *ctrl, graph_t *graph)149{150idx_t i, j, k, l, nvtxs, ncon, nparts, nbnd, mincut, me, other;151idx_t *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr;152153nparts = ctrl->nparts;154155nvtxs = graph->nvtxs;156ncon = graph->ncon;157xadj = graph->xadj;158vwgt = graph->vwgt;159adjncy = graph->adjncy;160adjwgt = graph->adjwgt;161162where = graph->where;163pwgts = iset(nparts*ncon, 0, graph->pwgts);164bndind = graph->bndind;165bndptr = iset(nvtxs, -1, graph->bndptr);166167nbnd = mincut = 0;168169/* Compute pwgts */170if (ncon == 1) {171for (i=0; i<nvtxs; i++) {172ASSERT(where[i] >= 0 && where[i] < nparts);173pwgts[where[i]] += vwgt[i];174}175}176else {177for (i=0; i<nvtxs; i++) {178me = where[i];179for (j=0; j<ncon; j++)180pwgts[me*ncon+j] += vwgt[i*ncon+j];181}182}183184/* Compute the required info for refinement */185switch (ctrl->objtype) {186case METIS_OBJTYPE_CUT:187{188ckrinfo_t *myrinfo;189cnbr_t *mynbrs;190191memset(graph->ckrinfo, 0, sizeof(ckrinfo_t)*nvtxs);192cnbrpoolReset(ctrl);193194for (i=0; i<nvtxs; i++) {195me = where[i];196myrinfo = graph->ckrinfo+i;197198for (j=xadj[i]; j<xadj[i+1]; j++) {199if (me == where[adjncy[j]])200myrinfo->id += adjwgt[j];201else202myrinfo->ed += adjwgt[j];203}204205/* Time to compute the particular external degrees */206if (myrinfo->ed > 0) {207mincut += myrinfo->ed;208209myrinfo->inbr = cnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);210mynbrs = ctrl->cnbrpool + myrinfo->inbr;211212for (j=xadj[i]; j<xadj[i+1]; j++) {213other = where[adjncy[j]];214if (me != other) {215for (k=0; k<myrinfo->nnbrs; k++) {216if (mynbrs[k].pid == other) {217mynbrs[k].ed += adjwgt[j];218break;219}220}221if (k == myrinfo->nnbrs) {222mynbrs[k].pid = other;223mynbrs[k].ed = adjwgt[j];224myrinfo->nnbrs++;225}226}227}228229ASSERT(myrinfo->nnbrs <= xadj[i+1]-xadj[i]);230231/* Only ed-id>=0 nodes are considered to be in the boundary */232if (myrinfo->ed-myrinfo->id >= 0)233BNDInsert(nbnd, bndind, bndptr, i);234}235else {236myrinfo->inbr = -1;237}238}239240graph->mincut = mincut/2;241graph->nbnd = nbnd;242243}244ASSERT(CheckBnd2(graph));245break;246247case METIS_OBJTYPE_VOL:248{249vkrinfo_t *myrinfo;250vnbr_t *mynbrs;251252memset(graph->vkrinfo, 0, sizeof(vkrinfo_t)*nvtxs);253vnbrpoolReset(ctrl);254255/* Compute now the id/ed degrees */256for (i=0; i<nvtxs; i++) {257me = where[i];258myrinfo = graph->vkrinfo+i;259260for (j=xadj[i]; j<xadj[i+1]; j++) {261if (me == where[adjncy[j]])262myrinfo->nid++;263else264myrinfo->ned++;265}266267/* Time to compute the particular external degrees */268if (myrinfo->ned > 0) {269mincut += myrinfo->ned;270271myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);272mynbrs = ctrl->vnbrpool + myrinfo->inbr;273274for (j=xadj[i]; j<xadj[i+1]; j++) {275other = where[adjncy[j]];276if (me != other) {277for (k=0; k<myrinfo->nnbrs; k++) {278if (mynbrs[k].pid == other) {279mynbrs[k].ned++;280break;281}282}283if (k == myrinfo->nnbrs) {284mynbrs[k].gv = 0;285mynbrs[k].pid = other;286mynbrs[k].ned = 1;287myrinfo->nnbrs++;288}289}290}291ASSERT(myrinfo->nnbrs <= xadj[i+1]-xadj[i]);292}293else {294myrinfo->inbr = -1;295}296}297graph->mincut = mincut/2;298299ComputeKWayVolGains(ctrl, graph);300}301ASSERT(graph->minvol == ComputeVolume(graph, graph->where));302break;303default:304gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);305}306307}308309310/*************************************************************************/311/*! This function projects a partition, and at the same time computes the312parameters for refinement. */313/*************************************************************************/314void ProjectKWayPartition(ctrl_t *ctrl, graph_t *graph)315{316idx_t i, j, k, nvtxs, nbnd, nparts, me, other, istart, iend, tid, ted;317idx_t *xadj, *adjncy, *adjwgt;318idx_t *cmap, *where, *bndptr, *bndind, *cwhere, *htable;319graph_t *cgraph;320321WCOREPUSH;322323nparts = ctrl->nparts;324325cgraph = graph->coarser;326cwhere = cgraph->where;327328nvtxs = graph->nvtxs;329cmap = graph->cmap;330xadj = graph->xadj;331adjncy = graph->adjncy;332adjwgt = graph->adjwgt;333334AllocateKWayPartitionMemory(ctrl, graph);335336where = graph->where;337bndind = graph->bndind;338bndptr = iset(nvtxs, -1, graph->bndptr);339340htable = iset(nparts, -1, iwspacemalloc(ctrl, nparts));341342/* Compute the required info for refinement */343switch (ctrl->objtype) {344case METIS_OBJTYPE_CUT:345ASSERT(CheckBnd2(cgraph));346{347ckrinfo_t *myrinfo;348cnbr_t *mynbrs;349350/* go through and project partition and compute id/ed for the nodes */351for (i=0; i<nvtxs; i++) {352k = cmap[i];353where[i] = cwhere[k];354cmap[i] = cgraph->ckrinfo[k].ed; /* For optimization */355}356357memset(graph->ckrinfo, 0, sizeof(ckrinfo_t)*nvtxs);358cnbrpoolReset(ctrl);359360for (nbnd=0, i=0; i<nvtxs; i++) {361istart = xadj[i];362iend = xadj[i+1];363364myrinfo = graph->ckrinfo+i;365366if (cmap[i] == 0) { /* Interior node. Note that cmap[i] = crinfo[cmap[i]].ed */367for (tid=0, j=istart; j<iend; j++)368tid += adjwgt[j];369370myrinfo->id = tid;371myrinfo->inbr = -1;372}373else { /* Potentially an interface node */374myrinfo->inbr = cnbrpoolGetNext(ctrl, iend-istart+1);375mynbrs = ctrl->cnbrpool + myrinfo->inbr;376377me = where[i];378for (tid=0, ted=0, j=istart; j<iend; j++) {379other = where[adjncy[j]];380if (me == other) {381tid += adjwgt[j];382}383else {384ted += adjwgt[j];385if ((k = htable[other]) == -1) {386htable[other] = myrinfo->nnbrs;387mynbrs[myrinfo->nnbrs].pid = other;388mynbrs[myrinfo->nnbrs++].ed = adjwgt[j];389}390else {391mynbrs[k].ed += adjwgt[j];392}393}394}395myrinfo->id = tid;396myrinfo->ed = ted;397398/* Remove space for edegrees if it was interior */399if (ted == 0) {400ctrl->nbrpoolcpos -= iend-istart+1;401myrinfo->inbr = -1;402}403else {404if (ted-tid >= 0)405BNDInsert(nbnd, bndind, bndptr, i);406407for (j=0; j<myrinfo->nnbrs; j++)408htable[mynbrs[j].pid] = -1;409}410}411}412413graph->nbnd = nbnd;414415}416ASSERT(CheckBnd2(graph));417break;418419case METIS_OBJTYPE_VOL:420{421vkrinfo_t *myrinfo;422vnbr_t *mynbrs;423424ASSERT(cgraph->minvol == ComputeVolume(cgraph, cgraph->where));425426/* go through and project partition and compute id/ed for the nodes */427for (i=0; i<nvtxs; i++) {428k = cmap[i];429where[i] = cwhere[k];430cmap[i] = cgraph->vkrinfo[k].ned; /* For optimization */431}432433memset(graph->vkrinfo, 0, sizeof(vkrinfo_t)*nvtxs);434vnbrpoolReset(ctrl);435436for (i=0; i<nvtxs; i++) {437istart = xadj[i];438iend = xadj[i+1];439myrinfo = graph->vkrinfo+i;440441if (cmap[i] == 0) { /* Note that cmap[i] = crinfo[cmap[i]].ed */442myrinfo->nid = iend-istart;443myrinfo->inbr = -1;444}445else { /* Potentially an interface node */446myrinfo->inbr = vnbrpoolGetNext(ctrl, iend-istart+1);447mynbrs = ctrl->vnbrpool + myrinfo->inbr;448449me = where[i];450for (tid=0, ted=0, j=istart; j<iend; j++) {451other = where[adjncy[j]];452if (me == other) {453tid++;454}455else {456ted++;457if ((k = htable[other]) == -1) {458htable[other] = myrinfo->nnbrs;459mynbrs[myrinfo->nnbrs].gv = 0;460mynbrs[myrinfo->nnbrs].pid = other;461mynbrs[myrinfo->nnbrs++].ned = 1;462}463else {464mynbrs[k].ned++;465}466}467}468myrinfo->nid = tid;469myrinfo->ned = ted;470471/* Remove space for edegrees if it was interior */472if (ted == 0) {473ctrl->nbrpoolcpos -= iend-istart+1;474myrinfo->inbr = -1;475}476else {477for (j=0; j<myrinfo->nnbrs; j++)478htable[mynbrs[j].pid] = -1;479}480}481}482483ComputeKWayVolGains(ctrl, graph);484485ASSERT(graph->minvol == ComputeVolume(graph, graph->where));486}487break;488489default:490gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);491}492493graph->mincut = cgraph->mincut;494icopy(nparts*graph->ncon, cgraph->pwgts, graph->pwgts);495496FreeGraph(&graph->coarser);497graph->coarser = NULL;498499WCOREPOP;500}501502503/*************************************************************************/504/*! This function computes the boundary definition for balancing. */505/*************************************************************************/506void ComputeKWayBoundary(ctrl_t *ctrl, graph_t *graph, idx_t bndtype)507{508idx_t i, nvtxs, nbnd;509idx_t *bndind, *bndptr;510511nvtxs = graph->nvtxs;512bndind = graph->bndind;513bndptr = iset(nvtxs, -1, graph->bndptr);514515nbnd = 0;516517switch (ctrl->objtype) {518case METIS_OBJTYPE_CUT:519/* Compute the boundary */520if (bndtype == BNDTYPE_REFINE) {521for (i=0; i<nvtxs; i++) {522if (graph->ckrinfo[i].ed-graph->ckrinfo[i].id >= 0)523BNDInsert(nbnd, bndind, bndptr, i);524}525}526else { /* BNDTYPE_BALANCE */527for (i=0; i<nvtxs; i++) {528if (graph->ckrinfo[i].ed > 0)529BNDInsert(nbnd, bndind, bndptr, i);530}531}532break;533534case METIS_OBJTYPE_VOL:535/* Compute the boundary */536if (bndtype == BNDTYPE_REFINE) {537for (i=0; i<nvtxs; i++) {538if (graph->vkrinfo[i].gv >= 0)539BNDInsert(nbnd, bndind, bndptr, i);540}541}542else { /* BNDTYPE_BALANCE */543for (i=0; i<nvtxs; i++) {544if (graph->vkrinfo[i].ned > 0)545BNDInsert(nbnd, bndind, bndptr, i);546}547}548break;549550default:551gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);552}553554graph->nbnd = nbnd;555}556557558/*************************************************************************/559/*! This function computes the initial gains in the communication volume */560/*************************************************************************/561void ComputeKWayVolGains(ctrl_t *ctrl, graph_t *graph)562{563idx_t i, ii, j, k, l, nvtxs, nparts, me, other, pid;564idx_t *xadj, *vsize, *adjncy, *adjwgt, *where,565*bndind, *bndptr, *ophtable;566vkrinfo_t *myrinfo, *orinfo;567vnbr_t *mynbrs, *onbrs;568569WCOREPUSH;570571nparts = ctrl->nparts;572573nvtxs = graph->nvtxs;574xadj = graph->xadj;575vsize = graph->vsize;576adjncy = graph->adjncy;577adjwgt = graph->adjwgt;578579where = graph->where;580bndind = graph->bndind;581bndptr = iset(nvtxs, -1, graph->bndptr);582583ophtable = iset(nparts, -1, iwspacemalloc(ctrl, nparts));584585/* Compute the volume gains */586graph->minvol = graph->nbnd = 0;587for (i=0; i<nvtxs; i++) {588myrinfo = graph->vkrinfo+i;589myrinfo->gv = IDX_MIN;590591if (myrinfo->nnbrs > 0) {592me = where[i];593mynbrs = ctrl->vnbrpool + myrinfo->inbr;594595graph->minvol += myrinfo->nnbrs*vsize[i];596597for (j=xadj[i]; j<xadj[i+1]; j++) {598ii = adjncy[j];599other = where[ii];600orinfo = graph->vkrinfo+ii;601onbrs = ctrl->vnbrpool + orinfo->inbr;602603for (k=0; k<orinfo->nnbrs; k++)604ophtable[onbrs[k].pid] = k;605ophtable[other] = 1; /* this is to simplify coding */606607if (me == other) {608/* Find which domains 'i' is connected to but 'ii' is not609and update their gain */610for (k=0; k<myrinfo->nnbrs; k++) {611if (ophtable[mynbrs[k].pid] == -1)612mynbrs[k].gv -= vsize[ii];613}614}615else {616ASSERT(ophtable[me] != -1);617618if (onbrs[ophtable[me]].ned == 1) {619/* I'm the only connection of 'ii' in 'me' */620/* Increase the gains for all the common domains between 'i' and 'ii' */621for (k=0; k<myrinfo->nnbrs; k++) {622if (ophtable[mynbrs[k].pid] != -1)623mynbrs[k].gv += vsize[ii];624}625}626else {627/* Find which domains 'i' is connected to and 'ii' is not628and update their gain */629for (k=0; k<myrinfo->nnbrs; k++) {630if (ophtable[mynbrs[k].pid] == -1)631mynbrs[k].gv -= vsize[ii];632}633}634}635636/* Reset the marker vector */637for (k=0; k<orinfo->nnbrs; k++)638ophtable[onbrs[k].pid] = -1;639ophtable[other] = -1;640}641642/* Compute the max vgain */643for (k=0; k<myrinfo->nnbrs; k++) {644if (mynbrs[k].gv > myrinfo->gv)645myrinfo->gv = mynbrs[k].gv;646}647648/* Add the extra gain due to id == 0 */649if (myrinfo->ned > 0 && myrinfo->nid == 0)650myrinfo->gv += vsize[i];651}652653if (myrinfo->gv >= 0)654BNDInsert(graph->nbnd, bndind, bndptr, i);655}656657WCOREPOP;658}659660661/*************************************************************************/662/*! This function checks if the partition weights are within the balance663contraints */664/*************************************************************************/665int IsBalanced(ctrl_t *ctrl, graph_t *graph, real_t ffactor)666{667return668(ComputeLoadImbalanceDiff(graph, ctrl->nparts, ctrl->pijbm, ctrl->ubfactors)669<= ffactor);670}671672673674