Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/kwayfm.c
3206 views
/*!1\file2\brief Routines for k-way refinement34\date Started 7/28/975\author George6\author Copyright 1997-2009, Regents of the University of Minnesota7\version $Id: kwayfm.c 10567 2011-07-13 16:17:07Z karypis $8*/910#include "metislib.h"11121314/*************************************************************************/15/* Top-level routine for k-way partitioning refinement. This routine just16calls the appropriate refinement routine based on the objectives and17constraints. */18/*************************************************************************/19void Greedy_KWayOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,20real_t ffactor, idx_t omode)21{22switch (ctrl->objtype) {23case METIS_OBJTYPE_CUT:24if (graph->ncon == 1)25Greedy_KWayCutOptimize(ctrl, graph, niter, ffactor, omode);26else27Greedy_McKWayCutOptimize(ctrl, graph, niter, ffactor, omode);28break;2930case METIS_OBJTYPE_VOL:31if (graph->ncon == 1)32Greedy_KWayVolOptimize(ctrl, graph, niter, ffactor, omode);33else34Greedy_McKWayVolOptimize(ctrl, graph, niter, ffactor, omode);35break;3637default:38gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype);39}40}414243/*************************************************************************/44/*! K-way partitioning optimization in which the vertices are visited in45decreasing ed/sqrt(nnbrs)-id order. Note this is just an46approximation, as the ed is often split across different subdomains47and the sqrt(nnbrs) is just a crude approximation.4849\param graph is the graph that is being refined.50\param niter is the number of refinement iterations.51\param ffactor is the \em fudge-factor for allowing positive gain moves52to violate the max-pwgt constraint.53\param omode is the type of optimization that will performed among54OMODE_REFINE and OMODE_BALANCE555657*/58/**************************************************************************/59void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,60real_t ffactor, idx_t omode)61{62/* Common variables to all types of kway-refinement/balancing routines */63idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain;64idx_t from, me, to, oldcut, vwgt;65idx_t *xadj, *adjncy, *adjwgt;66idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;67idx_t nmoved, nupd, *vstatus, *updptr, *updind;68idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;69idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;70idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);7172/* Edgecut-specific/different variables */73idx_t nbnd, oldnnbrs;74rpq_t *queue;75real_t rgain;76ckrinfo_t *myrinfo;77cnbr_t *mynbrs;7879WCOREPUSH;8081/* Link the graph fields */82nvtxs = graph->nvtxs;83xadj = graph->xadj;84adjncy = graph->adjncy;85adjwgt = graph->adjwgt;8687bndind = graph->bndind;88bndptr = graph->bndptr;8990where = graph->where;91pwgts = graph->pwgts;9293nparts = ctrl->nparts;9495/* Setup the weight intervals of the various subdomains */96minwgt = iwspacemalloc(ctrl, nparts);97maxwgt = iwspacemalloc(ctrl, nparts);98itpwgts = iwspacemalloc(ctrl, nparts);99100for (i=0; i<nparts; i++) {101itpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0];102maxwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0];103minwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]);104}105106perm = iwspacemalloc(ctrl, nvtxs);107108109/* This stores the valid target subdomains. It is used when ctrl->minconn to110control the subdomains to which moves are allowed to be made.111When ctrl->minconn is false, the default values of 2 allow all moves to112go through and it does not interfere with the zero-gain move selection. */113safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));114115if (ctrl->minconn) {116ComputeSubDomainGraph(ctrl, graph);117118nads = ctrl->nads;119adids = ctrl->adids;120adwgts = ctrl->adwgts;121doms = iset(nparts, 0, ctrl->pvec1);122}123124125/* Setup updptr, updind like boundary info to keep track of the vertices whose126vstatus's need to be reset at the end of the inner iteration */127vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));128updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));129updind = iwspacemalloc(ctrl, nvtxs);130131if (ctrl->contig) {132/* The arrays that will be used for limited check of articulation points */133bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));134bfsind = iwspacemalloc(ctrl, nvtxs);135bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));136}137138if (ctrl->dbglvl&METIS_DBG_REFINE) {139printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL","140" Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX,141(omode == OMODE_REFINE ? "GRC" : "GBC"),142pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), minwgt[0], maxwgt[0],143ComputeLoadImbalance(graph, nparts, ctrl->pijbm),144graph->nvtxs, graph->nbnd, graph->mincut);145if (ctrl->minconn)146printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));147printf("\n");148}149150queue = rpqCreate(nvtxs);151152/*=====================================================================153* The top-level refinement loop154*======================================================================*/155for (pass=0; pass<niter; pass++) {156ASSERT(ComputeCut(graph, where) == graph->mincut);157158if (omode == OMODE_BALANCE) {159/* Check to see if things are out of balance, given the tolerance */160for (i=0; i<nparts; i++) {161if (pwgts[i] > maxwgt[i])162break;163}164if (i == nparts) /* Things are balanced. Return right away */165break;166}167168oldcut = graph->mincut;169nbnd = graph->nbnd;170nupd = 0;171172if (ctrl->minconn)173maxndoms = imax(nparts, nads);174175/* Insert the boundary vertices in the priority queue */176irandArrayPermute(nbnd, perm, nbnd/4, 1);177for (ii=0; ii<nbnd; ii++) {178i = bndind[perm[ii]];179rgain = (graph->ckrinfo[i].nnbrs > 0 ?1801.0*graph->ckrinfo[i].ed/sqrt(graph->ckrinfo[i].nnbrs) : 0.0)181- graph->ckrinfo[i].id;182rpqInsert(queue, i, rgain);183vstatus[i] = VPQSTATUS_PRESENT;184ListInsert(nupd, updind, updptr, i);185}186187/* Start extracting vertices from the queue and try to move them */188for (nmoved=0, iii=0;;iii++) {189if ((i = rpqGetTop(queue)) == -1)190break;191vstatus[i] = VPQSTATUS_EXTRACTED;192193myrinfo = graph->ckrinfo+i;194mynbrs = ctrl->cnbrpool + myrinfo->inbr;195196from = where[i];197vwgt = graph->vwgt[i];198199/* Prevent moves that make 'from' domain underbalanced */200if (omode == OMODE_REFINE) {201if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])202continue;203}204else { /* OMODE_BALANCE */205if (pwgts[from]-vwgt < minwgt[from])206continue;207}208209if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))210continue;211212if (ctrl->minconn)213SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);214215/* Find the most promising subdomain to move to */216if (omode == OMODE_REFINE) {217for (k=myrinfo->nnbrs-1; k>=0; k--) {218if (!safetos[to=mynbrs[k].pid])219continue;220gain = mynbrs[k].ed-myrinfo->id;221if (gain >= 0 && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)222break;223}224if (k < 0)225continue; /* break out if you did not find a candidate */226227for (j=k-1; j>=0; j--) {228if (!safetos[to=mynbrs[j].pid])229continue;230gain = mynbrs[j].ed-myrinfo->id;231if ((mynbrs[j].ed > mynbrs[k].ed && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)232||233(mynbrs[j].ed == mynbrs[k].ed &&234itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid]))235k = j;236}237238to = mynbrs[k].pid;239240gain = mynbrs[k].ed-myrinfo->id;241if (!(gain > 0242|| (gain == 0243&& (pwgts[from] >= maxwgt[from]244|| itpwgts[to]*pwgts[from] > itpwgts[from]*(pwgts[to]+vwgt)245|| (iii%2 == 0 && safetos[to] == 2)246)247)248)249)250continue;251}252else { /* OMODE_BALANCE */253for (k=myrinfo->nnbrs-1; k>=0; k--) {254if (!safetos[to=mynbrs[k].pid])255continue;256if (pwgts[to]+vwgt <= maxwgt[to] ||257itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])258break;259}260if (k < 0)261continue; /* break out if you did not find a candidate */262263for (j=k-1; j>=0; j--) {264if (!safetos[to=mynbrs[j].pid])265continue;266if (itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])267k = j;268}269270to = mynbrs[k].pid;271272if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&273mynbrs[k].ed-myrinfo->id < 0)274continue;275}276277278279/*=====================================================================280* If we got here, we can now move the vertex from 'from' to 'to'281*======================================================================*/282graph->mincut -= mynbrs[k].ed-myrinfo->id;283nmoved++;284285IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,286printf("\t\tMoving %6"PRIDX" to %3"PRIDX". Gain: %4"PRIDX". Cut: %6"PRIDX"\n",287i, to, mynbrs[k].ed-myrinfo->id, graph->mincut));288289/* Update the subdomain connectivity information */290if (ctrl->minconn) {291/* take care of i's move itself */292UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, &maxndoms);293294/* take care of the adjancent vertices */295for (j=xadj[i]; j<xadj[i+1]; j++) {296me = where[adjncy[j]];297if (me != from && me != to) {298UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], &maxndoms);299UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], &maxndoms);300}301}302}303304/* Update ID/ED and BND related information for the moved vertex */305INC_DEC(pwgts[to], pwgts[from], vwgt);306UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd,307bndptr, bndind, bndtype);308309/* Update the degrees of adjacent vertices */310for (j=xadj[i]; j<xadj[i+1]; j++) {311ii = adjncy[j];312me = where[ii];313myrinfo = graph->ckrinfo+ii;314315oldnnbrs = myrinfo->nnbrs;316317UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,318from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype);319320UpdateQueueInfo(queue, vstatus, ii, me, from, to, myrinfo, oldnnbrs,321nupd, updptr, updind, bndtype);322323ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]);324}325}326327graph->nbnd = nbnd;328329/* Reset the vstatus and associated data structures */330for (i=0; i<nupd; i++) {331ASSERT(updptr[updind[i]] != -1);332ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);333vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;334updptr[updind[i]] = -1;335}336337if (ctrl->dbglvl&METIS_DBG_REFINE) {338printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."339" Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,340pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts),341ComputeLoadImbalance(graph, nparts, ctrl->pijbm),342graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where));343if (ctrl->minconn)344printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));345printf("\n");346}347348if (nmoved == 0 || (omode == OMODE_REFINE && graph->mincut == oldcut))349break;350}351352rpqDestroy(queue);353354WCOREPOP;355}356357358/*************************************************************************/359/*! K-way refinement that minimizes the communication volume. This is a360greedy routine and the vertices are visited in decreasing gv order.361362\param graph is the graph that is being refined.363\param niter is the number of refinement iterations.364\param ffactor is the \em fudge-factor for allowing positive gain moves365to violate the max-pwgt constraint.366367*/368/**************************************************************************/369void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,370real_t ffactor, idx_t omode)371{372/* Common variables to all types of kway-refinement/balancing routines */373idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain;374idx_t from, me, to, oldcut, vwgt;375idx_t *xadj, *adjncy;376idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;377idx_t nmoved, nupd, *vstatus, *updptr, *updind;378idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;379idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;380idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);381382/* Volume-specific/different variables */383ipq_t *queue;384idx_t oldvol, xgain;385idx_t *vmarker, *pmarker, *modind;386vkrinfo_t *myrinfo;387vnbr_t *mynbrs;388389WCOREPUSH;390391/* Link the graph fields */392nvtxs = graph->nvtxs;393xadj = graph->xadj;394adjncy = graph->adjncy;395bndptr = graph->bndptr;396bndind = graph->bndind;397where = graph->where;398pwgts = graph->pwgts;399400nparts = ctrl->nparts;401402/* Setup the weight intervals of the various subdomains */403minwgt = iwspacemalloc(ctrl, nparts);404maxwgt = iwspacemalloc(ctrl, nparts);405itpwgts = iwspacemalloc(ctrl, nparts);406407for (i=0; i<nparts; i++) {408itpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0];409maxwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0];410minwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]);411}412413perm = iwspacemalloc(ctrl, nvtxs);414415416/* This stores the valid target subdomains. It is used when ctrl->minconn to417control the subdomains to which moves are allowed to be made.418When ctrl->minconn is false, the default values of 2 allow all moves to419go through and it does not interfere with the zero-gain move selection. */420safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));421422if (ctrl->minconn) {423ComputeSubDomainGraph(ctrl, graph);424425nads = ctrl->nads;426adids = ctrl->adids;427adwgts = ctrl->adwgts;428doms = iset(nparts, 0, ctrl->pvec1);429}430431432/* Setup updptr, updind like boundary info to keep track of the vertices whose433vstatus's need to be reset at the end of the inner iteration */434vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));435updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));436updind = iwspacemalloc(ctrl, nvtxs);437438if (ctrl->contig) {439/* The arrays that will be used for limited check of articulation points */440bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));441bfsind = iwspacemalloc(ctrl, nvtxs);442bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));443}444445/* Vol-refinement specific working arrays */446modind = iwspacemalloc(ctrl, nvtxs);447vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));448pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));449450if (ctrl->dbglvl&METIS_DBG_REFINE) {451printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL452", Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %5"PRIDX", Vol: %5"PRIDX,453(omode == OMODE_REFINE ? "GRV" : "GBV"),454pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), minwgt[0], maxwgt[0],455ComputeLoadImbalance(graph, nparts, ctrl->pijbm),456graph->nvtxs, graph->nbnd, graph->mincut, graph->minvol);457if (ctrl->minconn)458printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));459printf("\n");460}461462queue = ipqCreate(nvtxs);463464465/*=====================================================================466* The top-level refinement loop467*======================================================================*/468for (pass=0; pass<niter; pass++) {469ASSERT(ComputeVolume(graph, where) == graph->minvol);470471if (omode == OMODE_BALANCE) {472/* Check to see if things are out of balance, given the tolerance */473for (i=0; i<nparts; i++) {474if (pwgts[i] > maxwgt[i])475break;476}477if (i == nparts) /* Things are balanced. Return right away */478break;479}480481oldcut = graph->mincut;482oldvol = graph->minvol;483nupd = 0;484485if (ctrl->minconn)486maxndoms = imax(nparts, nads);487488/* Insert the boundary vertices in the priority queue */489irandArrayPermute(graph->nbnd, perm, graph->nbnd/4, 1);490for (ii=0; ii<graph->nbnd; ii++) {491i = bndind[perm[ii]];492ipqInsert(queue, i, graph->vkrinfo[i].gv);493vstatus[i] = VPQSTATUS_PRESENT;494ListInsert(nupd, updind, updptr, i);495}496497/* Start extracting vertices from the queue and try to move them */498for (nmoved=0, iii=0;;iii++) {499if ((i = ipqGetTop(queue)) == -1)500break;501vstatus[i] = VPQSTATUS_EXTRACTED;502503myrinfo = graph->vkrinfo+i;504mynbrs = ctrl->vnbrpool + myrinfo->inbr;505506from = where[i];507vwgt = graph->vwgt[i];508509/* Prevent moves that make 'from' domain underbalanced */510if (omode == OMODE_REFINE) {511if (myrinfo->nid > 0 && pwgts[from]-vwgt < minwgt[from])512continue;513}514else { /* OMODE_BALANCE */515if (pwgts[from]-vwgt < minwgt[from])516continue;517}518519if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))520continue;521522if (ctrl->minconn)523SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);524525xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? graph->vsize[i] : 0);526527/* Find the most promising subdomain to move to */528if (omode == OMODE_REFINE) {529for (k=myrinfo->nnbrs-1; k>=0; k--) {530if (!safetos[to=mynbrs[k].pid])531continue;532gain = mynbrs[k].gv + xgain;533if (gain >= 0 && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)534break;535}536if (k < 0)537continue; /* break out if you did not find a candidate */538539for (j=k-1; j>=0; j--) {540if (!safetos[to=mynbrs[j].pid])541continue;542gain = mynbrs[j].gv + xgain;543if ((mynbrs[j].gv > mynbrs[k].gv &&544pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain)545||546(mynbrs[j].gv == mynbrs[k].gv &&547mynbrs[j].ned > mynbrs[k].ned &&548pwgts[to]+vwgt <= maxwgt[to])549||550(mynbrs[j].gv == mynbrs[k].gv &&551mynbrs[j].ned == mynbrs[k].ned &&552itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])553)554k = j;555}556to = mynbrs[k].pid;557558ASSERT(xgain+mynbrs[k].gv >= 0);559560j = 0;561if (xgain+mynbrs[k].gv > 0 || mynbrs[k].ned-myrinfo->nid > 0)562j = 1;563else if (mynbrs[k].ned-myrinfo->nid == 0) {564if ((iii%2 == 0 && safetos[to] == 2) ||565pwgts[from] >= maxwgt[from] ||566itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])567j = 1;568}569if (j == 0)570continue;571}572else { /* OMODE_BALANCE */573for (k=myrinfo->nnbrs-1; k>=0; k--) {574if (!safetos[to=mynbrs[k].pid])575continue;576if (pwgts[to]+vwgt <= maxwgt[to] ||577itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])578break;579}580if (k < 0)581continue; /* break out if you did not find a candidate */582583for (j=k-1; j>=0; j--) {584if (!safetos[to=mynbrs[j].pid])585continue;586if (itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])587k = j;588}589to = mynbrs[k].pid;590591if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&592(xgain+mynbrs[k].gv < 0 ||593(xgain+mynbrs[k].gv == 0 && mynbrs[k].ned-myrinfo->nid < 0))594)595continue;596}597598599/*=====================================================================600* If we got here, we can now move the vertex from 'from' to 'to'601*======================================================================*/602INC_DEC(pwgts[to], pwgts[from], vwgt);603graph->mincut -= mynbrs[k].ned-myrinfo->nid;604graph->minvol -= (xgain+mynbrs[k].gv);605where[i] = to;606nmoved++;607608IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,609printf("\t\tMoving %6"PRIDX" from %3"PRIDX" to %3"PRIDX". "610"Gain: [%4"PRIDX" %4"PRIDX"]. Cut: %6"PRIDX", Vol: %6"PRIDX"\n",611i, from, to, xgain+mynbrs[k].gv, mynbrs[k].ned-myrinfo->nid,612graph->mincut, graph->minvol));613614/* Update the subdomain connectivity information */615if (ctrl->minconn) {616/* take care of i's move itself */617UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->nid-mynbrs[k].ned, &maxndoms);618619/* take care of the adjancent vertices */620for (j=xadj[i]; j<xadj[i+1]; j++) {621me = where[adjncy[j]];622if (me != from && me != to) {623UpdateEdgeSubDomainGraph(ctrl, from, me, -1, &maxndoms);624UpdateEdgeSubDomainGraph(ctrl, to, me, 1, &maxndoms);625}626}627}628629/* Update the id/ed/gains/bnd/queue of potentially affected nodes */630KWayVolUpdate(ctrl, graph, i, from, to, queue, vstatus, &nupd, updptr,631updind, bndtype, vmarker, pmarker, modind);632633/*CheckKWayVolPartitionParams(ctrl, graph); */634}635636637/* Reset the vstatus and associated data structures */638for (i=0; i<nupd; i++) {639ASSERT(updptr[updind[i]] != -1);640ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);641vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;642updptr[updind[i]] = -1;643}644645if (ctrl->dbglvl&METIS_DBG_REFINE) {646printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."647" Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,648pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts),649ComputeLoadImbalance(graph, nparts, ctrl->pijbm),650graph->nbnd, nmoved, graph->mincut, graph->minvol);651if (ctrl->minconn)652printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));653printf("\n");654}655656if (nmoved == 0 ||657(omode == OMODE_REFINE && graph->minvol == oldvol && graph->mincut == oldcut))658break;659}660661ipqDestroy(queue);662663WCOREPOP;664}665666667/*************************************************************************/668/*! K-way partitioning optimization in which the vertices are visited in669decreasing ed/sqrt(nnbrs)-id order. Note this is just an670approximation, as the ed is often split across different subdomains671and the sqrt(nnbrs) is just a crude approximation.672673\param graph is the graph that is being refined.674\param niter is the number of refinement iterations.675\param ffactor is the \em fudge-factor for allowing positive gain moves676to violate the max-pwgt constraint.677\param omode is the type of optimization that will performed among678OMODE_REFINE and OMODE_BALANCE679680681*/682/**************************************************************************/683void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,684real_t ffactor, idx_t omode)685{686/* Common variables to all types of kway-refinement/balancing routines */687idx_t i, ii, iii, j, k, l, pass, nvtxs, ncon, nparts, gain;688idx_t from, me, to, cto, oldcut;689idx_t *xadj, *vwgt, *adjncy, *adjwgt;690idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt;691idx_t nmoved, nupd, *vstatus, *updptr, *updind;692idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;693idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;694idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);695real_t *ubfactors, *pijbm;696real_t origbal;697698/* Edgecut-specific/different variables */699idx_t nbnd, oldnnbrs;700rpq_t *queue;701real_t rgain;702ckrinfo_t *myrinfo;703cnbr_t *mynbrs;704705WCOREPUSH;706707/* Link the graph fields */708nvtxs = graph->nvtxs;709ncon = graph->ncon;710xadj = graph->xadj;711vwgt = graph->vwgt;712adjncy = graph->adjncy;713adjwgt = graph->adjwgt;714715bndind = graph->bndind;716bndptr = graph->bndptr;717718where = graph->where;719pwgts = graph->pwgts;720721nparts = ctrl->nparts;722pijbm = ctrl->pijbm;723724725/* Determine the ubfactors. The method used is different based on omode.726When OMODE_BALANCE, the ubfactors are those supplied by the user.727When OMODE_REFINE, the ubfactors are the max of the current partition728and the user-specified ones. */729ubfactors = rwspacemalloc(ctrl, ncon);730ComputeLoadImbalanceVec(graph, nparts, pijbm, ubfactors);731origbal = rvecmaxdiff(ncon, ubfactors, ctrl->ubfactors);732if (omode == OMODE_BALANCE) {733rcopy(ncon, ctrl->ubfactors, ubfactors);734}735else {736for (i=0; i<ncon; i++)737ubfactors[i] = (ubfactors[i] > ctrl->ubfactors[i] ? ubfactors[i] : ctrl->ubfactors[i]);738}739740741/* Setup the weight intervals of the various subdomains */742minwgt = iwspacemalloc(ctrl, nparts*ncon);743maxwgt = iwspacemalloc(ctrl, nparts*ncon);744745for (i=0; i<nparts; i++) {746for (j=0; j<ncon; j++) {747maxwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j];748/*minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]);*/749minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2;750}751}752753perm = iwspacemalloc(ctrl, nvtxs);754755756/* This stores the valid target subdomains. It is used when ctrl->minconn to757control the subdomains to which moves are allowed to be made.758When ctrl->minconn is false, the default values of 2 allow all moves to759go through and it does not interfere with the zero-gain move selection. */760safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));761762if (ctrl->minconn) {763ComputeSubDomainGraph(ctrl, graph);764765nads = ctrl->nads;766adids = ctrl->adids;767adwgts = ctrl->adwgts;768doms = iset(nparts, 0, ctrl->pvec1);769}770771772/* Setup updptr, updind like boundary info to keep track of the vertices whose773vstatus's need to be reset at the end of the inner iteration */774vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));775updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));776updind = iwspacemalloc(ctrl, nvtxs);777778if (ctrl->contig) {779/* The arrays that will be used for limited check of articulation points */780bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));781bfsind = iwspacemalloc(ctrl, nvtxs);782bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));783}784785if (ctrl->dbglvl&METIS_DBG_REFINE) {786printf("%s: [%6"PRIDX" %6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"(%.3"PRREAL"),"787" Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX", (%"PRIDX")",788(omode == OMODE_REFINE ? "GRC" : "GBC"),789imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), imax(nparts*ncon, maxwgt),790ComputeLoadImbalance(graph, nparts, pijbm), origbal,791graph->nvtxs, graph->nbnd, graph->mincut, niter);792if (ctrl->minconn)793printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));794printf("\n");795}796797queue = rpqCreate(nvtxs);798799800/*=====================================================================801* The top-level refinement loop802*======================================================================*/803for (pass=0; pass<niter; pass++) {804ASSERT(ComputeCut(graph, where) == graph->mincut);805806/* In balancing mode, exit as soon as balance is reached */807if (omode == OMODE_BALANCE && IsBalanced(ctrl, graph, 0))808break;809810oldcut = graph->mincut;811nbnd = graph->nbnd;812nupd = 0;813814if (ctrl->minconn)815maxndoms = imax(nparts, nads);816817/* Insert the boundary vertices in the priority queue */818irandArrayPermute(nbnd, perm, nbnd/4, 1);819for (ii=0; ii<nbnd; ii++) {820i = bndind[perm[ii]];821rgain = (graph->ckrinfo[i].nnbrs > 0 ?8221.0*graph->ckrinfo[i].ed/sqrt(graph->ckrinfo[i].nnbrs) : 0.0)823- graph->ckrinfo[i].id;824rpqInsert(queue, i, rgain);825vstatus[i] = VPQSTATUS_PRESENT;826ListInsert(nupd, updind, updptr, i);827}828829/* Start extracting vertices from the queue and try to move them */830for (nmoved=0, iii=0;;iii++) {831if ((i = rpqGetTop(queue)) == -1)832break;833vstatus[i] = VPQSTATUS_EXTRACTED;834835myrinfo = graph->ckrinfo+i;836mynbrs = ctrl->cnbrpool + myrinfo->inbr;837838from = where[i];839840/* Prevent moves that make 'from' domain underbalanced */841if (omode == OMODE_REFINE) {842if (myrinfo->id > 0 &&843!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))844continue;845}846else { /* OMODE_BALANCE */847if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))848continue;849}850851if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))852continue;853854if (ctrl->minconn)855SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);856857/* Find the most promising subdomain to move to */858if (omode == OMODE_REFINE) {859for (k=myrinfo->nnbrs-1; k>=0; k--) {860if (!safetos[to=mynbrs[k].pid])861continue;862gain = mynbrs[k].ed-myrinfo->id;863if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))864break;865}866if (k < 0)867continue; /* break out if you did not find a candidate */868869cto = to;870for (j=k-1; j>=0; j--) {871if (!safetos[to=mynbrs[j].pid])872continue;873if ((mynbrs[j].ed > mynbrs[k].ed &&874ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))875||876(mynbrs[j].ed == mynbrs[k].ed &&877BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,8781, pwgts+cto*ncon, pijbm+cto*ncon,8791, pwgts+to*ncon, pijbm+to*ncon))) {880k = j;881cto = to;882}883}884to = cto;885886gain = mynbrs[k].ed-myrinfo->id;887if (!(gain > 0888|| (gain == 0889&& (BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,890-1, pwgts+from*ncon, pijbm+from*ncon,891+1, pwgts+to*ncon, pijbm+to*ncon)892|| (iii%2 == 0 && safetos[to] == 2)893)894)895)896)897continue;898}899else { /* OMODE_BALANCE */900for (k=myrinfo->nnbrs-1; k>=0; k--) {901if (!safetos[to=mynbrs[k].pid])902continue;903if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon) ||904BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,905-1, pwgts+from*ncon, pijbm+from*ncon,906+1, pwgts+to*ncon, pijbm+to*ncon))907break;908}909if (k < 0)910continue; /* break out if you did not find a candidate */911912cto = to;913for (j=k-1; j>=0; j--) {914if (!safetos[to=mynbrs[j].pid])915continue;916if (BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,9171, pwgts+cto*ncon, pijbm+cto*ncon,9181, pwgts+to*ncon, pijbm+to*ncon)) {919k = j;920cto = to;921}922}923to = cto;924925if (mynbrs[k].ed-myrinfo->id < 0 &&926!BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,927-1, pwgts+from*ncon, pijbm+from*ncon,928+1, pwgts+to*ncon, pijbm+to*ncon))929continue;930}931932933934/*=====================================================================935* If we got here, we can now move the vertex from 'from' to 'to'936*======================================================================*/937graph->mincut -= mynbrs[k].ed-myrinfo->id;938nmoved++;939940IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,941printf("\t\tMoving %6"PRIDX" to %3"PRIDX". Gain: %4"PRIDX". Cut: %6"PRIDX"\n",942i, to, mynbrs[k].ed-myrinfo->id, graph->mincut));943944/* Update the subdomain connectivity information */945if (ctrl->minconn) {946/* take care of i's move itself */947UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, &maxndoms);948949/* take care of the adjancent vertices */950for (j=xadj[i]; j<xadj[i+1]; j++) {951me = where[adjncy[j]];952if (me != from && me != to) {953UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], &maxndoms);954UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], &maxndoms);955}956}957}958959/* Update ID/ED and BND related information for the moved vertex */960iaxpy(ncon, 1, vwgt+i*ncon, 1, pwgts+to*ncon, 1);961iaxpy(ncon, -1, vwgt+i*ncon, 1, pwgts+from*ncon, 1);962UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where,963nbnd, bndptr, bndind, bndtype);964965/* Update the degrees of adjacent vertices */966for (j=xadj[i]; j<xadj[i+1]; j++) {967ii = adjncy[j];968me = where[ii];969myrinfo = graph->ckrinfo+ii;970971oldnnbrs = myrinfo->nnbrs;972973UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,974from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype);975976UpdateQueueInfo(queue, vstatus, ii, me, from, to, myrinfo, oldnnbrs,977nupd, updptr, updind, bndtype);978979ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]);980}981}982983graph->nbnd = nbnd;984985/* Reset the vstatus and associated data structures */986for (i=0; i<nupd; i++) {987ASSERT(updptr[updind[i]] != -1);988ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);989vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;990updptr[updind[i]] = -1;991}992993if (ctrl->dbglvl&METIS_DBG_REFINE) {994printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."995" Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,996imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts),997ComputeLoadImbalance(graph, nparts, pijbm),998graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where));999if (ctrl->minconn)1000printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));1001printf("\n");1002}10031004if (nmoved == 0 || (omode == OMODE_REFINE && graph->mincut == oldcut))1005break;1006}10071008rpqDestroy(queue);10091010WCOREPOP;1011}101210131014/*************************************************************************/1015/*! K-way refinement that minimizes the communication volume. This is a1016greedy routine and the vertices are visited in decreasing gv order.10171018\param graph is the graph that is being refined.1019\param niter is the number of refinement iterations.1020\param ffactor is the \em fudge-factor for allowing positive gain moves1021to violate the max-pwgt constraint.10221023*/1024/**************************************************************************/1025void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter,1026real_t ffactor, idx_t omode)1027{1028/* Common variables to all types of kway-refinement/balancing routines */1029idx_t i, ii, iii, j, k, l, pass, nvtxs, ncon, nparts, gain;1030idx_t from, me, to, cto, oldcut;1031idx_t *xadj, *vwgt, *adjncy;1032idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt;1033idx_t nmoved, nupd, *vstatus, *updptr, *updind;1034idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL;1035idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL;1036idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE);1037real_t *ubfactors, *pijbm;1038real_t origbal;10391040/* Volume-specific/different variables */1041ipq_t *queue;1042idx_t oldvol, xgain;1043idx_t *vmarker, *pmarker, *modind;1044vkrinfo_t *myrinfo;1045vnbr_t *mynbrs;10461047WCOREPUSH;10481049/* Link the graph fields */1050nvtxs = graph->nvtxs;1051ncon = graph->ncon;1052xadj = graph->xadj;1053vwgt = graph->vwgt;1054adjncy = graph->adjncy;1055bndptr = graph->bndptr;1056bndind = graph->bndind;1057where = graph->where;1058pwgts = graph->pwgts;10591060nparts = ctrl->nparts;1061pijbm = ctrl->pijbm;106210631064/* Determine the ubfactors. The method used is different based on omode.1065When OMODE_BALANCE, the ubfactors are those supplied by the user.1066When OMODE_REFINE, the ubfactors are the max of the current partition1067and the user-specified ones. */1068ubfactors = rwspacemalloc(ctrl, ncon);1069ComputeLoadImbalanceVec(graph, nparts, pijbm, ubfactors);1070origbal = rvecmaxdiff(ncon, ubfactors, ctrl->ubfactors);1071if (omode == OMODE_BALANCE) {1072rcopy(ncon, ctrl->ubfactors, ubfactors);1073}1074else {1075for (i=0; i<ncon; i++)1076ubfactors[i] = (ubfactors[i] > ctrl->ubfactors[i] ? ubfactors[i] : ctrl->ubfactors[i]);1077}107810791080/* Setup the weight intervals of the various subdomains */1081minwgt = iwspacemalloc(ctrl, nparts*ncon);1082maxwgt = iwspacemalloc(ctrl, nparts*ncon);10831084for (i=0; i<nparts; i++) {1085for (j=0; j<ncon; j++) {1086maxwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j];1087/*minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]); */1088minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2;1089}1090}10911092perm = iwspacemalloc(ctrl, nvtxs);109310941095/* This stores the valid target subdomains. It is used when ctrl->minconn to1096control the subdomains to which moves are allowed to be made.1097When ctrl->minconn is false, the default values of 2 allow all moves to1098go through and it does not interfere with the zero-gain move selection. */1099safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts));11001101if (ctrl->minconn) {1102ComputeSubDomainGraph(ctrl, graph);11031104nads = ctrl->nads;1105adids = ctrl->adids;1106adwgts = ctrl->adwgts;1107doms = iset(nparts, 0, ctrl->pvec1);1108}110911101111/* Setup updptr, updind like boundary info to keep track of the vertices whose1112vstatus's need to be reset at the end of the inner iteration */1113vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs));1114updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));1115updind = iwspacemalloc(ctrl, nvtxs);11161117if (ctrl->contig) {1118/* The arrays that will be used for limited check of articulation points */1119bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));1120bfsind = iwspacemalloc(ctrl, nvtxs);1121bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));1122}11231124/* Vol-refinement specific working arrays */1125modind = iwspacemalloc(ctrl, nvtxs);1126vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));1127pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));11281129if (ctrl->dbglvl&METIS_DBG_REFINE) {1130printf("%s: [%6"PRIDX" %6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"(%.3"PRREAL"),"1131", Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %5"PRIDX", Vol: %5"PRIDX", (%"PRIDX")",1132(omode == OMODE_REFINE ? "GRV" : "GBV"),1133imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), imax(nparts*ncon, maxwgt),1134ComputeLoadImbalance(graph, nparts, pijbm), origbal,1135graph->nvtxs, graph->nbnd, graph->mincut, graph->minvol, niter);1136if (ctrl->minconn)1137printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));1138printf("\n");1139}11401141queue = ipqCreate(nvtxs);114211431144/*=====================================================================1145* The top-level refinement loop1146*======================================================================*/1147for (pass=0; pass<niter; pass++) {1148ASSERT(ComputeVolume(graph, where) == graph->minvol);11491150/* In balancing mode, exit as soon as balance is reached */1151if (omode == OMODE_BALANCE && IsBalanced(ctrl, graph, 0))1152break;11531154oldcut = graph->mincut;1155oldvol = graph->minvol;1156nupd = 0;11571158if (ctrl->minconn)1159maxndoms = imax(nparts, nads);11601161/* Insert the boundary vertices in the priority queue */1162irandArrayPermute(graph->nbnd, perm, graph->nbnd/4, 1);1163for (ii=0; ii<graph->nbnd; ii++) {1164i = bndind[perm[ii]];1165ipqInsert(queue, i, graph->vkrinfo[i].gv);1166vstatus[i] = VPQSTATUS_PRESENT;1167ListInsert(nupd, updind, updptr, i);1168}11691170/* Start extracting vertices from the queue and try to move them */1171for (nmoved=0, iii=0;;iii++) {1172if ((i = ipqGetTop(queue)) == -1)1173break;1174vstatus[i] = VPQSTATUS_EXTRACTED;11751176myrinfo = graph->vkrinfo+i;1177mynbrs = ctrl->vnbrpool + myrinfo->inbr;11781179from = where[i];11801181/* Prevent moves that make 'from' domain underbalanced */1182if (omode == OMODE_REFINE) {1183if (myrinfo->nid > 0 &&1184!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))1185continue;1186}1187else { /* OMODE_BALANCE */1188if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon))1189continue;1190}11911192if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk))1193continue;11941195if (ctrl->minconn)1196SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms);11971198xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? graph->vsize[i] : 0);11991200/* Find the most promising subdomain to move to */1201if (omode == OMODE_REFINE) {1202for (k=myrinfo->nnbrs-1; k>=0; k--) {1203if (!safetos[to=mynbrs[k].pid])1204continue;1205gain = mynbrs[k].gv + xgain;1206if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))1207break;1208}1209if (k < 0)1210continue; /* break out if you did not find a candidate */12111212cto = to;1213for (j=k-1; j>=0; j--) {1214if (!safetos[to=mynbrs[j].pid])1215continue;1216gain = mynbrs[j].gv + xgain;1217if ((mynbrs[j].gv > mynbrs[k].gv &&1218ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))1219||1220(mynbrs[j].gv == mynbrs[k].gv &&1221mynbrs[j].ned > mynbrs[k].ned &&1222ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon))1223||1224(mynbrs[j].gv == mynbrs[k].gv &&1225mynbrs[j].ned == mynbrs[k].ned &&1226BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,12271, pwgts+cto*ncon, pijbm+cto*ncon,12281, pwgts+to*ncon, pijbm+to*ncon))) {1229k = j;1230cto = to;1231}1232}1233to = cto;12341235j = 0;1236if (xgain+mynbrs[k].gv > 0 || mynbrs[k].ned-myrinfo->nid > 0)1237j = 1;1238else if (mynbrs[k].ned-myrinfo->nid == 0) {1239if ((iii%2 == 0 && safetos[to] == 2) ||1240BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,1241-1, pwgts+from*ncon, pijbm+from*ncon,1242+1, pwgts+to*ncon, pijbm+to*ncon))1243j = 1;1244}1245if (j == 0)1246continue;1247}1248else { /* OMODE_BALANCE */1249for (k=myrinfo->nnbrs-1; k>=0; k--) {1250if (!safetos[to=mynbrs[k].pid])1251continue;1252if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon) ||1253BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,1254-1, pwgts+from*ncon, pijbm+from*ncon,1255+1, pwgts+to*ncon, pijbm+to*ncon))1256break;1257}1258if (k < 0)1259continue; /* break out if you did not find a candidate */12601261cto = to;1262for (j=k-1; j>=0; j--) {1263if (!safetos[to=mynbrs[j].pid])1264continue;1265if (BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,12661, pwgts+cto*ncon, pijbm+cto*ncon,12671, pwgts+to*ncon, pijbm+to*ncon)) {1268k = j;1269cto = to;1270}1271}1272to = cto;12731274if ((xgain+mynbrs[k].gv < 0 ||1275(xgain+mynbrs[k].gv == 0 && mynbrs[k].ned-myrinfo->nid < 0))1276&&1277!BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors,1278-1, pwgts+from*ncon, pijbm+from*ncon,1279+1, pwgts+to*ncon, pijbm+to*ncon))1280continue;1281}128212831284/*=====================================================================1285* If we got here, we can now move the vertex from 'from' to 'to'1286*======================================================================*/1287graph->mincut -= mynbrs[k].ned-myrinfo->nid;1288graph->minvol -= (xgain+mynbrs[k].gv);1289where[i] = to;1290nmoved++;12911292IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,1293printf("\t\tMoving %6"PRIDX" from %3"PRIDX" to %3"PRIDX". "1294"Gain: [%4"PRIDX" %4"PRIDX"]. Cut: %6"PRIDX", Vol: %6"PRIDX"\n",1295i, from, to, xgain+mynbrs[k].gv, mynbrs[k].ned-myrinfo->nid,1296graph->mincut, graph->minvol));12971298/* Update the subdomain connectivity information */1299if (ctrl->minconn) {1300/* take care of i's move itself */1301UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->nid-mynbrs[k].ned, &maxndoms);13021303/* take care of the adjancent vertices */1304for (j=xadj[i]; j<xadj[i+1]; j++) {1305me = where[adjncy[j]];1306if (me != from && me != to) {1307UpdateEdgeSubDomainGraph(ctrl, from, me, -1, &maxndoms);1308UpdateEdgeSubDomainGraph(ctrl, to, me, 1, &maxndoms);1309}1310}1311}13121313/* Update pwgts */1314iaxpy(ncon, 1, vwgt+i*ncon, 1, pwgts+to*ncon, 1);1315iaxpy(ncon, -1, vwgt+i*ncon, 1, pwgts+from*ncon, 1);13161317/* Update the id/ed/gains/bnd/queue of potentially affected nodes */1318KWayVolUpdate(ctrl, graph, i, from, to, queue, vstatus, &nupd, updptr,1319updind, bndtype, vmarker, pmarker, modind);13201321/*CheckKWayVolPartitionParams(ctrl, graph); */1322}132313241325/* Reset the vstatus and associated data structures */1326for (i=0; i<nupd; i++) {1327ASSERT(updptr[updind[i]] != -1);1328ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT);1329vstatus[updind[i]] = VPQSTATUS_NOTPRESENT;1330updptr[updind[i]] = -1;1331}13321333if (ctrl->dbglvl&METIS_DBG_REFINE) {1334printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"."1335" Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX,1336imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts),1337ComputeLoadImbalance(graph, nparts, pijbm),1338graph->nbnd, nmoved, graph->mincut, graph->minvol);1339if (ctrl->minconn)1340printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1));1341printf("\n");1342}13431344if (nmoved == 0 ||1345(omode == OMODE_REFINE && graph->minvol == oldvol && graph->mincut == oldcut))1346break;1347}13481349ipqDestroy(queue);13501351WCOREPOP;1352}135313541355/*************************************************************************/1356/*! This function performs an approximate articulation vertex test.1357It assumes that the bfslvl, bfsind, and bfsmrk arrays are initialized1358appropriately. */1359/*************************************************************************/1360idx_t IsArticulationNode(idx_t i, idx_t *xadj, idx_t *adjncy, idx_t *where,1361idx_t *bfslvl, idx_t *bfsind, idx_t *bfsmrk)1362{1363idx_t ii, j, k=0, head, tail, nhits, tnhits, from, BFSDEPTH=5;13641365from = where[i];13661367/* Determine if the vertex is safe to move from a contiguity standpoint */1368for (tnhits=0, j=xadj[i]; j<xadj[i+1]; j++) {1369if (where[adjncy[j]] == from) {1370ASSERT(bfsmrk[adjncy[j]] == 0);1371ASSERT(bfslvl[adjncy[j]] == 0);1372bfsmrk[k=adjncy[j]] = 1;1373tnhits++;1374}1375}13761377/* Easy cases */1378if (tnhits == 0)1379return 0;1380if (tnhits == 1) {1381bfsmrk[k] = 0;1382return 0;1383}13841385ASSERT(bfslvl[i] == 0);1386bfslvl[i] = 1;13871388bfsind[0] = k; /* That was the last one from the previous loop */1389bfslvl[k] = 1;1390bfsmrk[k] = 0;1391head = 0;1392tail = 1;13931394/* Do a limited BFS traversal to see if you can get to all the other nodes */1395for (nhits=1; head<tail; ) {1396ii = bfsind[head++];1397for (j=xadj[ii]; j<xadj[ii+1]; j++) {1398if (where[k=adjncy[j]] == from) {1399if (bfsmrk[k]) {1400bfsmrk[k] = 0;1401if (++nhits == tnhits)1402break;1403}1404if (bfslvl[k] == 0 && bfslvl[ii] < BFSDEPTH) {1405bfsind[tail++] = k;1406bfslvl[k] = bfslvl[ii]+1;1407}1408}1409}1410if (nhits == tnhits)1411break;1412}14131414/* Reset the various BFS related arrays */1415bfslvl[i] = 0;1416for (j=0; j<tail; j++)1417bfslvl[bfsind[j]] = 0;141814191420/* Reset the bfsmrk array for the next vertex when has not already being cleared */1421if (nhits < tnhits) {1422for (j=xadj[i]; j<xadj[i+1]; j++)1423if (where[adjncy[j]] == from)1424bfsmrk[adjncy[j]] = 0;1425}14261427return (nhits != tnhits);1428}142914301431/*************************************************************************/1432/*!1433This function updates the edge and volume gains due to a vertex movement.1434v from 'from' to 'to'.14351436\param ctrl is the control structure.1437\param graph is the graph being partitioned.1438\param v is the vertex that is moving.1439\param from is the original partition of v.1440\param to is the new partition of v.1441\param queue is the priority queue. If the queue is NULL, no priority-queue1442related updates are performed.1443\param vstatus is an array that marks the status of the vertex in terms1444of the priority queue. If queue is NULL, this parameter is ignored.1445\param r_nqupd is the number of vertices that have been inserted/removed1446from the queue. If queue is NULL, this parameter is ignored.1447\param updptr stores the index of each vertex in updind. If queue is NULL,1448this parameter is ignored.1449\param updind is the list of vertices that have been inserted/removed from1450the queue. If queue is NULL, this parameter is ignored.1451\param vmarker is of size nvtxs and is used internally as a temporary array.1452On entry and return all of its entries are 0.1453\param pmarker is of sie nparts and is used internally as a temporary marking1454array. On entry and return all of its entries are -1.1455\param modind is an array of size nvtxs and is used to keep track of the1456list of vertices whose gains need to be updated.1457*/1458/*************************************************************************/1459void KWayVolUpdate(ctrl_t *ctrl, graph_t *graph, idx_t v, idx_t from,1460idx_t to, ipq_t *queue, idx_t *vstatus, idx_t *r_nupd, idx_t *updptr,1461idx_t *updind, idx_t bndtype, idx_t *vmarker, idx_t *pmarker,1462idx_t *modind)1463{1464idx_t i, ii, iii, j, jj, k, kk, l, u, nmod, other, me, myidx;1465idx_t *xadj, *vsize, *adjncy, *where;1466vkrinfo_t *myrinfo, *orinfo;1467vnbr_t *mynbrs, *onbrs;14681469xadj = graph->xadj;1470adjncy = graph->adjncy;1471vsize = graph->vsize;1472where = graph->where;14731474myrinfo = graph->vkrinfo+v;1475mynbrs = ctrl->vnbrpool + myrinfo->inbr;147614771478/*======================================================================1479* Remove the contributions on the gain made by 'v'.1480*=====================================================================*/1481for (k=0; k<myrinfo->nnbrs; k++)1482pmarker[mynbrs[k].pid] = k;1483pmarker[from] = k;14841485myidx = pmarker[to]; /* Keep track of the index in mynbrs of the 'to' domain */14861487for (j=xadj[v]; j<xadj[v+1]; j++) {1488ii = adjncy[j];1489other = where[ii];1490orinfo = graph->vkrinfo+ii;1491onbrs = ctrl->vnbrpool + orinfo->inbr;14921493if (other == from) {1494for (k=0; k<orinfo->nnbrs; k++) {1495if (pmarker[onbrs[k].pid] == -1)1496onbrs[k].gv += vsize[v];1497}1498}1499else {1500ASSERT(pmarker[other] != -1);15011502if (mynbrs[pmarker[other]].ned > 1) {1503for (k=0; k<orinfo->nnbrs; k++) {1504if (pmarker[onbrs[k].pid] == -1)1505onbrs[k].gv += vsize[v];1506}1507}1508else { /* There is only one connection */1509for (k=0; k<orinfo->nnbrs; k++) {1510if (pmarker[onbrs[k].pid] != -1)1511onbrs[k].gv -= vsize[v];1512}1513}1514}1515}15161517for (k=0; k<myrinfo->nnbrs; k++)1518pmarker[mynbrs[k].pid] = -1;1519pmarker[from] = -1;152015211522/*======================================================================1523* Update the id/ed of vertex 'v'1524*=====================================================================*/1525if (myidx == -1) {1526myidx = myrinfo->nnbrs++;1527ASSERT(myidx < xadj[v+1]-xadj[v]);1528mynbrs[myidx].ned = 0;1529}1530myrinfo->ned += myrinfo->nid-mynbrs[myidx].ned;1531SWAP(myrinfo->nid, mynbrs[myidx].ned, j);1532if (mynbrs[myidx].ned == 0)1533mynbrs[myidx] = mynbrs[--myrinfo->nnbrs];1534else1535mynbrs[myidx].pid = from;153615371538/*======================================================================1539* Update the degrees of adjacent vertices and their volume gains1540*=====================================================================*/1541vmarker[v] = 1;1542modind[0] = v;1543nmod = 1;1544for (j=xadj[v]; j<xadj[v+1]; j++) {1545ii = adjncy[j];1546me = where[ii];15471548if (!vmarker[ii]) { /* The marking is done for boundary and max gv calculations */1549vmarker[ii] = 2;1550modind[nmod++] = ii;1551}15521553myrinfo = graph->vkrinfo+ii;1554if (myrinfo->inbr == -1)1555myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[ii+1]-xadj[ii]+1);1556mynbrs = ctrl->vnbrpool + myrinfo->inbr;15571558if (me == from) {1559INC_DEC(myrinfo->ned, myrinfo->nid, 1);1560}1561else if (me == to) {1562INC_DEC(myrinfo->nid, myrinfo->ned, 1);1563}15641565/* Remove the edgeweight from the 'pid == from' entry of the vertex */1566if (me != from) {1567for (k=0; k<myrinfo->nnbrs; k++) {1568if (mynbrs[k].pid == from) {1569if (mynbrs[k].ned == 1) {1570mynbrs[k] = mynbrs[--myrinfo->nnbrs];1571vmarker[ii] = 1; /* You do a complete .gv calculation */15721573/* All vertices adjacent to 'ii' need to be updated */1574for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {1575u = adjncy[jj];1576other = where[u];1577orinfo = graph->vkrinfo+u;1578onbrs = ctrl->vnbrpool + orinfo->inbr;15791580for (kk=0; kk<orinfo->nnbrs; kk++) {1581if (onbrs[kk].pid == from) {1582onbrs[kk].gv -= vsize[ii];1583if (!vmarker[u]) { /* Need to update boundary etc */1584vmarker[u] = 2;1585modind[nmod++] = u;1586}1587break;1588}1589}1590}1591}1592else {1593mynbrs[k].ned--;15941595/* Update the gv due to single 'ii' connection to 'from' */1596if (mynbrs[k].ned == 1) {1597/* find the vertex 'u' that 'ii' was connected into 'from' */1598for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {1599u = adjncy[jj];1600other = where[u];16011602if (other == from) {1603orinfo = graph->vkrinfo+u;1604onbrs = ctrl->vnbrpool + orinfo->inbr;16051606/* The following is correct because domains in common1607between ii and u will lead to a reduction over the1608previous gain, whereas domains only in u but not in1609ii, will lead to no change as opposed to the earlier1610increase */1611for (kk=0; kk<orinfo->nnbrs; kk++)1612onbrs[kk].gv += vsize[ii];16131614if (!vmarker[u]) { /* Need to update boundary etc */1615vmarker[u] = 2;1616modind[nmod++] = u;1617}1618break;1619}1620}1621}1622}1623break;1624}1625}1626}162716281629/* Add the edgeweight to the 'pid == to' entry of the vertex */1630if (me != to) {1631for (k=0; k<myrinfo->nnbrs; k++) {1632if (mynbrs[k].pid == to) {1633mynbrs[k].ned++;16341635/* Update the gv due to non-single 'ii' connection to 'to' */1636if (mynbrs[k].ned == 2) {1637/* find the vertex 'u' that 'ii' was connected into 'to' */1638for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {1639u = adjncy[jj];1640other = where[u];16411642if (u != v && other == to) {1643orinfo = graph->vkrinfo+u;1644onbrs = ctrl->vnbrpool + orinfo->inbr;1645for (kk=0; kk<orinfo->nnbrs; kk++)1646onbrs[kk].gv -= vsize[ii];16471648if (!vmarker[u]) { /* Need to update boundary etc */1649vmarker[u] = 2;1650modind[nmod++] = u;1651}1652break;1653}1654}1655}1656break;1657}1658}16591660if (k == myrinfo->nnbrs) {1661mynbrs[myrinfo->nnbrs].pid = to;1662mynbrs[myrinfo->nnbrs++].ned = 1;1663vmarker[ii] = 1; /* You do a complete .gv calculation */16641665/* All vertices adjacent to 'ii' need to be updated */1666for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {1667u = adjncy[jj];1668other = where[u];1669orinfo = graph->vkrinfo+u;1670onbrs = ctrl->vnbrpool + orinfo->inbr;16711672for (kk=0; kk<orinfo->nnbrs; kk++) {1673if (onbrs[kk].pid == to) {1674onbrs[kk].gv += vsize[ii];1675if (!vmarker[u]) { /* Need to update boundary etc */1676vmarker[u] = 2;1677modind[nmod++] = u;1678}1679break;1680}1681}1682}1683}1684}16851686ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]);1687}168816891690/*======================================================================1691* Add the contributions on the volume gain due to 'v'1692*=====================================================================*/1693myrinfo = graph->vkrinfo+v;1694mynbrs = ctrl->vnbrpool + myrinfo->inbr;1695for (k=0; k<myrinfo->nnbrs; k++)1696pmarker[mynbrs[k].pid] = k;1697pmarker[to] = k;16981699for (j=xadj[v]; j<xadj[v+1]; j++) {1700ii = adjncy[j];1701other = where[ii];1702orinfo = graph->vkrinfo+ii;1703onbrs = ctrl->vnbrpool + orinfo->inbr;17041705if (other == to) {1706for (k=0; k<orinfo->nnbrs; k++) {1707if (pmarker[onbrs[k].pid] == -1)1708onbrs[k].gv -= vsize[v];1709}1710}1711else {1712ASSERT(pmarker[other] != -1);17131714if (mynbrs[pmarker[other]].ned > 1) {1715for (k=0; k<orinfo->nnbrs; k++) {1716if (pmarker[onbrs[k].pid] == -1)1717onbrs[k].gv -= vsize[v];1718}1719}1720else { /* There is only one connection */1721for (k=0; k<orinfo->nnbrs; k++) {1722if (pmarker[onbrs[k].pid] != -1)1723onbrs[k].gv += vsize[v];1724}1725}1726}1727}1728for (k=0; k<myrinfo->nnbrs; k++)1729pmarker[mynbrs[k].pid] = -1;1730pmarker[to] = -1;173117321733/*======================================================================1734* Recompute the volume information of the 'hard' nodes, and update the1735* max volume gain for all the modified vertices and the priority queue1736*=====================================================================*/1737for (iii=0; iii<nmod; iii++) {1738i = modind[iii];1739me = where[i];17401741myrinfo = graph->vkrinfo+i;1742mynbrs = ctrl->vnbrpool + myrinfo->inbr;17431744if (vmarker[i] == 1) { /* Only complete gain updates go through */1745for (k=0; k<myrinfo->nnbrs; k++)1746mynbrs[k].gv = 0;17471748for (j=xadj[i]; j<xadj[i+1]; j++) {1749ii = adjncy[j];1750other = where[ii];1751orinfo = graph->vkrinfo+ii;1752onbrs = ctrl->vnbrpool + orinfo->inbr;17531754for (kk=0; kk<orinfo->nnbrs; kk++)1755pmarker[onbrs[kk].pid] = kk;1756pmarker[other] = 1;17571758if (me == other) {1759/* Find which domains 'i' is connected and 'ii' is not and update their gain */1760for (k=0; k<myrinfo->nnbrs; k++) {1761if (pmarker[mynbrs[k].pid] == -1)1762mynbrs[k].gv -= vsize[ii];1763}1764}1765else {1766ASSERT(pmarker[me] != -1);17671768/* I'm the only connection of 'ii' in 'me' */1769if (onbrs[pmarker[me]].ned == 1) {1770/* Increase the gains for all the common domains between 'i' and 'ii' */1771for (k=0; k<myrinfo->nnbrs; k++) {1772if (pmarker[mynbrs[k].pid] != -1)1773mynbrs[k].gv += vsize[ii];1774}1775}1776else {1777/* Find which domains 'i' is connected and 'ii' is not and update their gain */1778for (k=0; k<myrinfo->nnbrs; k++) {1779if (pmarker[mynbrs[k].pid] == -1)1780mynbrs[k].gv -= vsize[ii];1781}1782}1783}17841785for (kk=0; kk<orinfo->nnbrs; kk++)1786pmarker[onbrs[kk].pid] = -1;1787pmarker[other] = -1;17881789}1790}17911792/* Compute the overall gv for that node */1793myrinfo->gv = IDX_MIN;1794for (k=0; k<myrinfo->nnbrs; k++) {1795if (mynbrs[k].gv > myrinfo->gv)1796myrinfo->gv = mynbrs[k].gv;1797}17981799/* Add the xtra gain due to id == 0 */1800if (myrinfo->ned > 0 && myrinfo->nid == 0)1801myrinfo->gv += vsize[i];180218031804/*======================================================================1805* Maintain a consistent boundary1806*=====================================================================*/1807if (bndtype == BNDTYPE_REFINE) {1808if (myrinfo->gv >= 0 && graph->bndptr[i] == -1)1809BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, i);18101811if (myrinfo->gv < 0 && graph->bndptr[i] != -1)1812BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, i);1813}1814else {1815if (myrinfo->ned > 0 && graph->bndptr[i] == -1)1816BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, i);18171818if (myrinfo->ned == 0 && graph->bndptr[i] != -1)1819BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, i);1820}182118221823/*======================================================================1824* Update the priority queue appropriately (if allowed)1825*=====================================================================*/1826if (queue != NULL) {1827if (vstatus[i] != VPQSTATUS_EXTRACTED) {1828if (graph->bndptr[i] != -1) { /* In-boundary vertex */1829if (vstatus[i] == VPQSTATUS_PRESENT) {1830ipqUpdate(queue, i, myrinfo->gv);1831}1832else {1833ipqInsert(queue, i, myrinfo->gv);1834vstatus[i] = VPQSTATUS_PRESENT;1835ListInsert(*r_nupd, updind, updptr, i);1836}1837}1838else { /* Off-boundary vertex */1839if (vstatus[i] == VPQSTATUS_PRESENT) {1840ipqDelete(queue, i);1841vstatus[i] = VPQSTATUS_NOTPRESENT;1842ListDelete(*r_nupd, updind, updptr, i);1843}1844}1845}1846}18471848vmarker[i] = 0;1849}1850}1851185218531854