Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/parmetis.c
3206 views
/*1* Copyright 1997, Regents of the University of Minnesota2*3* parmetis.c4*5* This file contains top level routines that are used by ParMETIS6*7* Started 10/14/978* George9*10* $Id: parmetis.c 10481 2011-07-05 18:01:23Z karypis $11*12*/1314#include "metislib.h"151617/*************************************************************************/18/*! This function is the entry point for the node ND code for ParMETIS.19The difference between this routine and the standard METIS_NodeND are20the following2122- It performs at least log2(npes) levels of nested dissection.23- It stores the size of the log2(npes) top-level separators in the24sizes array.25*/26/*************************************************************************/27int METIS_NodeNDP(idx_t nvtxs, idx_t *xadj, idx_t *adjncy, idx_t *vwgt,28idx_t npes, idx_t *options, idx_t *perm, idx_t *iperm, idx_t *sizes)29{30idx_t i, ii, j, l, nnvtxs=0;31graph_t *graph;32ctrl_t *ctrl;33idx_t *cptr, *cind;3435ctrl = SetupCtrl(METIS_OP_OMETIS, options, 1, 3, NULL, NULL);36if (!ctrl) return METIS_ERROR_INPUT;3738IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl));39IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr));4041/* compress the graph; not that compression only happens if not prunning42has taken place. */43if (ctrl->compress) {44cptr = imalloc(nvtxs+1, "OMETIS: cptr");45cind = imalloc(nvtxs, "OMETIS: cind");4647graph = CompressGraph(ctrl, nvtxs, xadj, adjncy, vwgt, cptr, cind);48if (graph == NULL) {49/* if there was no compression, cleanup the compress flag */50gk_free((void **)&cptr, &cind, LTERM);51ctrl->compress = 0;52}53else {54nnvtxs = graph->nvtxs;55}56}5758/* if no compression, setup the graph in the normal way. */59if (ctrl->compress == 0)60graph = SetupGraph(ctrl, nvtxs, 1, xadj, adjncy, vwgt, NULL, NULL);616263/* allocate workspace memory */64AllocateWorkSpace(ctrl, graph);656667/* do the nested dissection ordering */68iset(2*npes-1, 0, sizes);69MlevelNestedDissectionP(ctrl, graph, iperm, graph->nvtxs, npes, 0, sizes);707172/* Uncompress the ordering */73if (ctrl->compress) {74/* construct perm from iperm */75for (i=0; i<nnvtxs; i++)76perm[iperm[i]] = i;77for (l=ii=0; ii<nnvtxs; ii++) {78i = perm[ii];79for (j=cptr[i]; j<cptr[i+1]; j++)80iperm[cind[j]] = l++;81}8283gk_free((void **)&cptr, &cind, LTERM);84}858687for (i=0; i<nvtxs; i++)88perm[iperm[i]] = i;8990IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr));91IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl));9293/* clean up */94FreeCtrl(&ctrl);9596return METIS_OK;97}9899100/*************************************************************************/101/*! This function is similar to MlevelNestedDissection with the difference102that it also records separator sizes for the top log2(npes) levels */103/**************************************************************************/104void MlevelNestedDissectionP(ctrl_t *ctrl, graph_t *graph, idx_t *order,105idx_t lastvtx, idx_t npes, idx_t cpos, idx_t *sizes)106{107idx_t i, j, nvtxs, nbnd;108idx_t *label, *bndind;109graph_t *lgraph, *rgraph;110111nvtxs = graph->nvtxs;112113if (nvtxs == 0) {114FreeGraph(&graph);115return;116}117118MlevelNodeBisectionMultiple(ctrl, graph);119120IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO,121printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n",122graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));123124if (cpos < npes-1) {125sizes[2*npes-2-cpos] = graph->pwgts[2];126sizes[2*npes-2-(2*cpos+1)] = graph->pwgts[1];127sizes[2*npes-2-(2*cpos+2)] = graph->pwgts[0];128}129130/* Order the nodes in the separator */131nbnd = graph->nbnd;132bndind = graph->bndind;133label = graph->label;134for (i=0; i<nbnd; i++)135order[label[bndind[i]]] = --lastvtx;136137SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);138139/* Free the memory of the top level graph */140FreeGraph(&graph);141142if ((lgraph->nvtxs > MMDSWITCH || 2*cpos+2 < npes-1) && lgraph->nedges > 0)143MlevelNestedDissectionP(ctrl, lgraph, order, lastvtx-rgraph->nvtxs, npes, 2*cpos+2, sizes);144else {145MMDOrder(ctrl, lgraph, order, lastvtx-rgraph->nvtxs);146FreeGraph(&lgraph);147}148if ((rgraph->nvtxs > MMDSWITCH || 2*cpos+1 < npes-1) && rgraph->nedges > 0)149MlevelNestedDissectionP(ctrl, rgraph, order, lastvtx, npes, 2*cpos+1, sizes);150else {151MMDOrder(ctrl, rgraph, order, lastvtx);152FreeGraph(&rgraph);153}154}155156157/*************************************************************************/158/*! This function bisects a graph by computing a vertex separator */159/**************************************************************************/160int METIS_ComputeVertexSeparator(idx_t *nvtxs, idx_t *xadj, idx_t *adjncy,161idx_t *vwgt, idx_t *options, idx_t *r_sepsize, idx_t *part)162{163idx_t i, j;164graph_t *graph;165ctrl_t *ctrl;166167if ((ctrl = SetupCtrl(METIS_OP_OMETIS, options, 1, 3, NULL, NULL)) == NULL)168return METIS_ERROR_INPUT;169170InitRandom(ctrl->seed);171172graph = SetupGraph(ctrl, *nvtxs, 1, xadj, adjncy, vwgt, NULL, NULL);173174AllocateWorkSpace(ctrl, graph);175176/*============================================================177* Perform the bisection178*============================================================*/179ctrl->CoarsenTo = 100;180181MlevelNodeBisectionMultiple(ctrl, graph);182183*r_sepsize = graph->pwgts[2];184icopy(*nvtxs, graph->where, part);185186FreeGraph(&graph);187188FreeCtrl(&ctrl);189190return METIS_OK;191}192193194/*************************************************************************/195/*! This function is the entry point of a node-based separator refinement196of the nodes with an hmarker[] of 0. */197/*************************************************************************/198int METIS_NodeRefine(idx_t nvtxs, idx_t *xadj, idx_t *vwgt, idx_t *adjncy,199idx_t *where, idx_t *hmarker, real_t ubfactor)200{201graph_t *graph;202ctrl_t *ctrl;203204/* set up the run time parameters */205ctrl = SetupCtrl(METIS_OP_OMETIS, NULL, 1, 3, NULL, NULL);206if (!ctrl) return METIS_ERROR_INPUT;207208/* set up the graph */209graph = SetupGraph(ctrl, nvtxs, 1, xadj, adjncy, vwgt, NULL, NULL);210211/* allocate workspace memory */212AllocateWorkSpace(ctrl, graph);213214/* set up the memory and the input partition */215Allocate2WayNodePartitionMemory(ctrl, graph);216icopy(nvtxs, where, graph->where);217218Compute2WayNodePartitionParams(ctrl, graph);219220FM_2WayNodeRefine1SidedP(ctrl, graph, hmarker, ubfactor, 10);221/* FM_2WayNodeRefine2SidedP(ctrl, graph, hmarker, ubfactor, 10); */222223icopy(nvtxs, graph->where, where);224225FreeGraph(&graph);226FreeCtrl(&ctrl);227228return METIS_OK;229}230231232/*************************************************************************/233/*! This function performs a node-based 1-sided FM refinement that moves234only nodes whose hmarker[] == -1. It is used by Parmetis. */235/*************************************************************************/236void FM_2WayNodeRefine1SidedP(ctrl_t *ctrl, graph_t *graph,237idx_t *hmarker, real_t ubfactor, idx_t npasses)238{239idx_t i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind, nbad, qsize;240idx_t *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;241idx_t *mptr, *mind, *swaps, *inqueue;242rpq_t *queue;243nrinfo_t *rinfo;244idx_t higain, oldgain, mincut, initcut, mincutorder;245idx_t pass, from, to, limit;246idx_t badmaxpwgt, mindiff, newdiff;247248WCOREPUSH;249250ASSERT(graph->mincut == graph->pwgts[2]);251252nvtxs = graph->nvtxs;253xadj = graph->xadj;254adjncy = graph->adjncy;255vwgt = graph->vwgt;256257bndind = graph->bndind;258bndptr = graph->bndptr;259where = graph->where;260pwgts = graph->pwgts;261rinfo = graph->nrinfo;262263queue = rpqCreate(nvtxs);264265inqueue = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));266swaps = iwspacemalloc(ctrl, nvtxs);267mptr = iwspacemalloc(ctrl, nvtxs+1);268mind = iwspacemalloc(ctrl, 2*nvtxs);269270badmaxpwgt = (idx_t)(ubfactor*gk_max(pwgts[0], pwgts[1]));271272IFSET(ctrl->dbglvl, METIS_DBG_REFINE,273printf("Partitions-N1: [%6"PRIDX" %6"PRIDX"] Nv-Nb[%6"PRIDX" %6"PRIDX"] "274"MaxPwgt[%6"PRIDX"]. ISep: %6"PRIDX"\n",275pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, badmaxpwgt,276graph->mincut));277278to = (pwgts[0] < pwgts[1] ? 1 : 0);279for (pass=0; pass<npasses; pass++) {280from = to;281to = (from+1)%2;282283rpqReset(queue);284285mincutorder = -1;286initcut = mincut = graph->mincut;287nbnd = graph->nbnd;288289/* use the swaps array in place of the traditional perm array to save memory */290irandArrayPermute(nbnd, swaps, nbnd, 1);291for (ii=0; ii<nbnd; ii++) {292i = bndind[swaps[ii]];293ASSERT(where[i] == 2);294if (hmarker[i] == -1 || hmarker[i] == to) {295rpqInsert(queue, i, vwgt[i]-rinfo[i].edegrees[from]);296inqueue[i] = pass;297}298}299qsize = rpqLength(queue);300301ASSERT(CheckNodeBnd(graph, nbnd));302ASSERT(CheckNodePartitionParams(graph));303304limit = nbnd;305306/******************************************************307* Get into the FM loop308*******************************************************/309mptr[0] = nmind = nbad = 0;310mindiff = abs(pwgts[0]-pwgts[1]);311for (nswaps=0; nswaps<nvtxs; nswaps++) {312if ((higain = rpqGetTop(queue)) == -1)313break;314315ASSERT(bndptr[higain] != -1);316317/* The following check is to ensure we break out if there is a posibility318of over-running the mind array. */319if (nmind + xadj[higain+1]-xadj[higain] >= 2*nvtxs-1)320break;321322inqueue[higain] = -1;323324if (pwgts[to]+vwgt[higain] > badmaxpwgt) { /* Skip this vertex */325if (nbad++ > limit)326break;327else {328nswaps--;329continue;330}331}332333pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[from]);334335newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[from]-rinfo[higain].edegrees[from]));336if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {337mincut = pwgts[2];338mincutorder = nswaps;339mindiff = newdiff;340nbad = 0;341}342else {343if (nbad++ > limit) {344pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[from]);345break; /* No further improvement, break out */346}347}348349BNDDelete(nbnd, bndind, bndptr, higain);350pwgts[to] += vwgt[higain];351where[higain] = to;352swaps[nswaps] = higain;353354355/**********************************************************356* Update the degrees of the affected nodes357***********************************************************/358for (j=xadj[higain]; j<xadj[higain+1]; j++) {359k = adjncy[j];360if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */361rinfo[k].edegrees[to] += vwgt[higain];362}363else if (where[k] == from) { /* This vertex is pulled into the separator */364ASSERTP(bndptr[k] == -1, ("%"PRIDX" %"PRIDX" %"PRIDX"\n", k, bndptr[k], where[k]));365BNDInsert(nbnd, bndind, bndptr, k);366367mind[nmind++] = k; /* Keep track for rollback */368where[k] = 2;369pwgts[from] -= vwgt[k];370371edegrees = rinfo[k].edegrees;372edegrees[0] = edegrees[1] = 0;373for (jj=xadj[k]; jj<xadj[k+1]; jj++) {374kk = adjncy[jj];375if (where[kk] != 2)376edegrees[where[kk]] += vwgt[kk];377else {378oldgain = vwgt[kk]-rinfo[kk].edegrees[from];379rinfo[kk].edegrees[from] -= vwgt[k];380381/* Update the gain of this node if it was not skipped */382if (inqueue[kk] == pass)383rpqUpdate(queue, kk, oldgain+vwgt[k]);384}385}386387/* Insert the new vertex into the priority queue. Safe due to one-sided moves */388if (hmarker[k] == -1 || hmarker[k] == to) {389rpqInsert(queue, k, vwgt[k]-edegrees[from]);390inqueue[k] = pass;391}392}393}394mptr[nswaps+1] = nmind;395396397IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,398printf("Moved %6"PRIDX" to %3"PRIDX", Gain: %5"PRIDX" [%5"PRIDX"] \t[%5"PRIDX" %5"PRIDX" %5"PRIDX"] [%3"PRIDX" %2"PRIDX"]\n",399higain, to, (vwgt[higain]-rinfo[higain].edegrees[from]),400vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit));401402}403404405/****************************************************************406* Roll back computation407*****************************************************************/408for (nswaps--; nswaps>mincutorder; nswaps--) {409higain = swaps[nswaps];410411ASSERT(CheckNodePartitionParams(graph));412ASSERT(where[higain] == to);413414INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);415where[higain] = 2;416BNDInsert(nbnd, bndind, bndptr, higain);417418edegrees = rinfo[higain].edegrees;419edegrees[0] = edegrees[1] = 0;420for (j=xadj[higain]; j<xadj[higain+1]; j++) {421k = adjncy[j];422if (where[k] == 2)423rinfo[k].edegrees[to] -= vwgt[higain];424else425edegrees[where[k]] += vwgt[k];426}427428/* Push nodes out of the separator */429for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {430k = mind[j];431ASSERT(where[k] == 2);432where[k] = from;433INC_DEC(pwgts[from], pwgts[2], vwgt[k]);434BNDDelete(nbnd, bndind, bndptr, k);435for (jj=xadj[k]; jj<xadj[k+1]; jj++) {436kk = adjncy[jj];437if (where[kk] == 2)438rinfo[kk].edegrees[from] += vwgt[k];439}440}441}442443ASSERT(mincut == pwgts[2]);444445IFSET(ctrl->dbglvl, METIS_DBG_REFINE,446printf("\tMinimum sep: %6"PRIDX" at %5"PRIDX", PWGTS: [%6"PRIDX" %6"PRIDX"], NBND: %6"PRIDX", QSIZE: %6"PRIDX"\n",447mincut, mincutorder, pwgts[0], pwgts[1], nbnd, qsize));448449graph->mincut = mincut;450graph->nbnd = nbnd;451452if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut))453break;454}455456rpqDestroy(queue);457458WCOREPOP;459}460461462/*************************************************************************/463/*! This function performs a node-based (two-sided) FM refinement that464moves only nodes whose hmarker[] == -1. It is used by Parmetis. */465/*************************************************************************/466void FM_2WayNodeRefine2SidedP(ctrl_t *ctrl, graph_t *graph,467idx_t *hmarker, real_t ubfactor, idx_t npasses)468{469idx_t i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;470idx_t *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;471idx_t *mptr, *mind, *moved, *swaps;472rpq_t *queues[2];473nrinfo_t *rinfo;474idx_t higain, oldgain, mincut, initcut, mincutorder;475idx_t pass, to, other, limit;476idx_t badmaxpwgt, mindiff, newdiff;477idx_t u[2], g[2];478479WCOREPUSH;480481nvtxs = graph->nvtxs;482xadj = graph->xadj;483adjncy = graph->adjncy;484vwgt = graph->vwgt;485486bndind = graph->bndind;487bndptr = graph->bndptr;488where = graph->where;489pwgts = graph->pwgts;490rinfo = graph->nrinfo;491492queues[0] = rpqCreate(nvtxs);493queues[1] = rpqCreate(nvtxs);494495moved = iwspacemalloc(ctrl, nvtxs);496swaps = iwspacemalloc(ctrl, nvtxs);497mptr = iwspacemalloc(ctrl, nvtxs+1);498mind = iwspacemalloc(ctrl, 2*nvtxs);499500IFSET(ctrl->dbglvl, METIS_DBG_REFINE,501printf("Partitions: [%6"PRIDX" %6"PRIDX"] Nv-Nb[%6"PRIDX" %6"PRIDX"]. ISep: %6"PRIDX"\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));502503badmaxpwgt = (idx_t)(ubfactor*gk_max(pwgts[0], pwgts[1]));504505for (pass=0; pass<npasses; pass++) {506iset(nvtxs, -1, moved);507rpqReset(queues[0]);508rpqReset(queues[1]);509510mincutorder = -1;511initcut = mincut = graph->mincut;512nbnd = graph->nbnd;513514/* use the swaps array in place of the traditional perm array to save memory */515irandArrayPermute(nbnd, swaps, nbnd, 1);516for (ii=0; ii<nbnd; ii++) {517i = bndind[swaps[ii]];518ASSERT(where[i] == 2);519if (hmarker[i] == -1) {520rpqInsert(queues[0], i, vwgt[i]-rinfo[i].edegrees[1]);521rpqInsert(queues[1], i, vwgt[i]-rinfo[i].edegrees[0]);522moved[i] = -5;523}524else if (hmarker[i] != 2) {525rpqInsert(queues[hmarker[i]], i, vwgt[i]-rinfo[i].edegrees[(hmarker[i]+1)%2]);526moved[i] = -(10+hmarker[i]);527}528}529530ASSERT(CheckNodeBnd(graph, nbnd));531ASSERT(CheckNodePartitionParams(graph));532533limit = nbnd;534535/******************************************************536* Get into the FM loop537*******************************************************/538mptr[0] = nmind = 0;539mindiff = abs(pwgts[0]-pwgts[1]);540to = (pwgts[0] < pwgts[1] ? 0 : 1);541for (nswaps=0; nswaps<nvtxs; nswaps++) {542u[0] = rpqSeeTopVal(queues[0]);543u[1] = rpqSeeTopVal(queues[1]);544if (u[0] != -1 && u[1] != -1) {545g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];546g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];547548to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));549550if (pwgts[to]+vwgt[u[to]] > badmaxpwgt)551to = (to+1)%2;552}553else if (u[0] == -1 && u[1] == -1) {554break;555}556else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) {557to = 0;558}559else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) {560to = 1;561}562else563break;564565other = (to+1)%2;566567higain = rpqGetTop(queues[to]);568569/* Delete its matching entry in the other queue */570if (moved[higain] == -5)571rpqDelete(queues[other], higain);572573ASSERT(bndptr[higain] != -1);574575/* The following check is to ensure we break out if there is a posibility576of over-running the mind array. */577if (nmind + xadj[higain+1]-xadj[higain] >= 2*nvtxs-1)578break;579580pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);581582newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));583if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {584mincut = pwgts[2];585mincutorder = nswaps;586mindiff = newdiff;587}588else {589if (nswaps - mincutorder > limit) {590pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);591break; /* No further improvement, break out */592}593}594595BNDDelete(nbnd, bndind, bndptr, higain);596pwgts[to] += vwgt[higain];597where[higain] = to;598moved[higain] = nswaps;599swaps[nswaps] = higain;600601602/**********************************************************603* Update the degrees of the affected nodes604***********************************************************/605for (j=xadj[higain]; j<xadj[higain+1]; j++) {606k = adjncy[j];607if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */608oldgain = vwgt[k]-rinfo[k].edegrees[to];609rinfo[k].edegrees[to] += vwgt[higain];610if (moved[k] == -5 || moved[k] == -(10+other))611rpqUpdate(queues[other], k, oldgain-vwgt[higain]);612}613else if (where[k] == other) { /* This vertex is pulled into the separator */614ASSERTP(bndptr[k] == -1, ("%"PRIDX" %"PRIDX" %"PRIDX"\n", k, bndptr[k], where[k]));615BNDInsert(nbnd, bndind, bndptr, k);616617mind[nmind++] = k; /* Keep track for rollback */618where[k] = 2;619pwgts[other] -= vwgt[k];620621edegrees = rinfo[k].edegrees;622edegrees[0] = edegrees[1] = 0;623for (jj=xadj[k]; jj<xadj[k+1]; jj++) {624kk = adjncy[jj];625if (where[kk] != 2)626edegrees[where[kk]] += vwgt[kk];627else {628oldgain = vwgt[kk]-rinfo[kk].edegrees[other];629rinfo[kk].edegrees[other] -= vwgt[k];630if (moved[kk] == -5 || moved[kk] == -(10+to))631rpqUpdate(queues[to], kk, oldgain+vwgt[k]);632}633}634635/* Insert the new vertex into the priority queue (if it has not been moved). */636if (moved[k] == -1 && (hmarker[k] == -1 || hmarker[k] == to)) {637rpqInsert(queues[to], k, vwgt[k]-edegrees[other]);638moved[k] = -(10+to);639}640#ifdef FULLMOVES /* this does not work as well as the above partial one */641if (moved[k] == -1) {642if (hmarker[k] == -1) {643rpqInsert(queues[0], k, vwgt[k]-edegrees[1]);644rpqInsert(queues[1], k, vwgt[k]-edegrees[0]);645moved[k] = -5;646}647else if (hmarker[k] != 2) {648rpqInsert(queues[hmarker[k]], k, vwgt[k]-edegrees[(hmarker[k]+1)%2]);649moved[k] = -(10+hmarker[k]);650}651}652#endif653}654}655mptr[nswaps+1] = nmind;656657IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,658printf("Moved %6"PRIDX" to %3"PRIDX", Gain: %5"PRIDX" [%5"PRIDX"] "659"[%4"PRIDX" %4"PRIDX"] \t[%5"PRIDX" %5"PRIDX" %5"PRIDX"]\n",660higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]],661pwgts[0], pwgts[1], pwgts[2]));662663}664665666/****************************************************************667* Roll back computation668*****************************************************************/669for (nswaps--; nswaps>mincutorder; nswaps--) {670higain = swaps[nswaps];671672ASSERT(CheckNodePartitionParams(graph));673674to = where[higain];675other = (to+1)%2;676INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);677where[higain] = 2;678BNDInsert(nbnd, bndind, bndptr, higain);679680edegrees = rinfo[higain].edegrees;681edegrees[0] = edegrees[1] = 0;682for (j=xadj[higain]; j<xadj[higain+1]; j++) {683k = adjncy[j];684if (where[k] == 2)685rinfo[k].edegrees[to] -= vwgt[higain];686else687edegrees[where[k]] += vwgt[k];688}689690/* Push nodes out of the separator */691for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {692k = mind[j];693ASSERT(where[k] == 2);694where[k] = other;695INC_DEC(pwgts[other], pwgts[2], vwgt[k]);696BNDDelete(nbnd, bndind, bndptr, k);697for (jj=xadj[k]; jj<xadj[k+1]; jj++) {698kk = adjncy[jj];699if (where[kk] == 2)700rinfo[kk].edegrees[other] += vwgt[k];701}702}703}704705ASSERT(mincut == pwgts[2]);706707IFSET(ctrl->dbglvl, METIS_DBG_REFINE,708printf("\tMinimum sep: %6"PRIDX" at %5"PRIDX", PWGTS: [%6"PRIDX" %6"PRIDX"], NBND: %6"PRIDX"\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));709710graph->mincut = mincut;711graph->nbnd = nbnd;712713if (mincutorder == -1 || mincut >= initcut)714break;715}716717rpqDestroy(queues[0]);718rpqDestroy(queues[1]);719720WCOREPOP;721}722723724725