You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
699 lines
21 KiB
699 lines
21 KiB
/*!
|
|
\file
|
|
\brief Functions that deal with eliminating disconnected partitions
|
|
|
|
\date Started 7/15/98
|
|
\author George
|
|
\author Copyright 1997-2009, Regents of the University of Minnesota
|
|
\version $Id: contig.c 10513 2011-07-07 22:06:03Z karypis $
|
|
*/
|
|
|
|
#include "metislib.h"
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function finds the connected components induced by the
|
|
partitioning vector.
|
|
|
|
\param graph is the graph structure
|
|
\param where is the partitioning vector. If this is NULL, then the
|
|
entire graph is treated to belong into a single partition.
|
|
\param cptr is the ptr structure of the CSR representation of the
|
|
components. The length of this vector must be graph->nvtxs+1.
|
|
\param cind is the indices structure of the CSR representation of
|
|
the components. The length of this vector must be graph->nvtxs.
|
|
|
|
\returns the number of components that it found.
|
|
|
|
\note The cptr and cind parameters can be NULL, in which case only the
|
|
number of connected components is returned.
|
|
*/
|
|
/*************************************************************************/
|
|
idx_t FindPartitionInducedComponents(graph_t *graph, idx_t *where,
|
|
idx_t *cptr, idx_t *cind)
|
|
{
|
|
idx_t i, ii, j, jj, k, me=0, nvtxs, first, last, nleft, ncmps;
|
|
idx_t *xadj, *adjncy;
|
|
idx_t *touched, *perm, *todo;
|
|
idx_t mustfree_ccsr=0, mustfree_where=0;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
|
|
/* Deal with NULL supplied cptr/cind vectors */
|
|
if (cptr == NULL) {
|
|
cptr = imalloc(nvtxs+1, "FindPartitionInducedComponents: cptr");
|
|
cind = imalloc(nvtxs, "FindPartitionInducedComponents: cind");
|
|
mustfree_ccsr = 1;
|
|
}
|
|
|
|
/* Deal with NULL supplied where vector */
|
|
if (where == NULL) {
|
|
where = ismalloc(nvtxs, 0, "FindPartitionInducedComponents: where");
|
|
mustfree_where = 1;
|
|
}
|
|
|
|
/* Allocate memory required for the BFS traversal */
|
|
perm = iincset(nvtxs, 0, imalloc(nvtxs, "FindPartitionInducedComponents: perm"));
|
|
todo = iincset(nvtxs, 0, imalloc(nvtxs, "FindPartitionInducedComponents: todo"));
|
|
touched = ismalloc(nvtxs, 0, "FindPartitionInducedComponents: touched");
|
|
|
|
|
|
/* Find the connected componends induced by the partition */
|
|
ncmps = -1;
|
|
first = last = 0;
|
|
nleft = nvtxs;
|
|
while (nleft > 0) {
|
|
if (first == last) { /* Find another starting vertex */
|
|
cptr[++ncmps] = first;
|
|
ASSERT(touched[todo[0]] == 0);
|
|
i = todo[0];
|
|
cind[last++] = i;
|
|
touched[i] = 1;
|
|
me = where[i];
|
|
}
|
|
|
|
i = cind[first++];
|
|
k = perm[i];
|
|
j = todo[k] = todo[--nleft];
|
|
perm[j] = k;
|
|
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
k = adjncy[j];
|
|
if (where[k] == me && !touched[k]) {
|
|
cind[last++] = k;
|
|
touched[k] = 1;
|
|
}
|
|
}
|
|
}
|
|
cptr[++ncmps] = first;
|
|
|
|
if (mustfree_ccsr)
|
|
gk_free((void **)&cptr, &cind, LTERM);
|
|
if (mustfree_where)
|
|
gk_free((void **)&where, LTERM);
|
|
|
|
gk_free((void **)&perm, &todo, &touched, LTERM);
|
|
|
|
return ncmps;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function computes a permutation of the vertices based on a
|
|
breadth-first-traversal. It can be used for re-ordering the graph
|
|
to reduce its bandwidth for better cache locality.
|
|
|
|
\param ctrl is the control structure
|
|
\param graph is the graph structure
|
|
\param perm is the array that upon completion, perm[i] will store
|
|
the ID of the vertex that corresponds to the ith vertex in the
|
|
re-ordered graph.
|
|
*/
|
|
/*************************************************************************/
|
|
void ComputeBFSOrdering(ctrl_t *ctrl, graph_t *graph, idx_t *bfsperm)
|
|
{
|
|
idx_t i, j, k, nvtxs, first, last;
|
|
idx_t *xadj, *adjncy, *perm;
|
|
|
|
WCOREPUSH;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
|
|
/* Allocate memory required for the BFS traversal */
|
|
perm = iincset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
|
|
|
|
iincset(nvtxs, 0, bfsperm); /* this array will also store the vertices
|
|
still to be processed */
|
|
|
|
/* Find the connected componends induced by the partition */
|
|
first = last = 0;
|
|
while (first < nvtxs) {
|
|
if (first == last) { /* Find another starting vertex */
|
|
k = bfsperm[last];
|
|
ASSERT(perm[k] != -1);
|
|
perm[k] = -1; /* mark node as being visited */
|
|
last++;
|
|
}
|
|
|
|
i = bfsperm[first++];
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
k = adjncy[j];
|
|
/* if a node has been already been visited, its perm[] will be -1 */
|
|
if (perm[k] != -1) {
|
|
/* perm[k] is the location within bfsperm of where k resides;
|
|
put in that location bfsperm[last] that we are about to
|
|
overwrite and update perm[bfsperm[last]] to reflect that. */
|
|
bfsperm[perm[k]] = bfsperm[last];
|
|
perm[bfsperm[last]] = perm[k];
|
|
|
|
bfsperm[last++] = k; /* put node at the end of the "queue" */
|
|
perm[k] = -1; /* mark node as being visited */
|
|
}
|
|
}
|
|
}
|
|
|
|
WCOREPOP;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function checks whether a graph is contiguous or not.
|
|
*/
|
|
/**************************************************************************/
|
|
idx_t IsConnected(graph_t *graph, idx_t report)
|
|
{
|
|
idx_t ncmps;
|
|
|
|
ncmps = FindPartitionInducedComponents(graph, NULL, NULL, NULL);
|
|
|
|
if (ncmps != 1 && report)
|
|
printf("The graph is not connected. It has %"PRIDX" connected components.\n", ncmps);
|
|
|
|
return (ncmps == 1);
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function checks whether or not partition pid is contiguous
|
|
*/
|
|
/*************************************************************************/
|
|
idx_t IsConnectedSubdomain(ctrl_t *ctrl, graph_t *graph, idx_t pid, idx_t report)
|
|
{
|
|
idx_t i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
|
|
idx_t *xadj, *adjncy, *where, *touched, *queue;
|
|
idx_t *cptr;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
where = graph->where;
|
|
|
|
touched = ismalloc(nvtxs, 0, "IsConnected: touched");
|
|
queue = imalloc(nvtxs, "IsConnected: queue");
|
|
cptr = imalloc(nvtxs+1, "IsConnected: cptr");
|
|
|
|
nleft = 0;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (where[i] == pid)
|
|
nleft++;
|
|
}
|
|
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (where[i] == pid)
|
|
break;
|
|
}
|
|
|
|
touched[i] = 1;
|
|
queue[0] = i;
|
|
first = 0; last = 1;
|
|
|
|
cptr[0] = 0; /* This actually points to queue */
|
|
ncmps = 0;
|
|
while (first != nleft) {
|
|
if (first == last) { /* Find another starting vertex */
|
|
cptr[++ncmps] = first;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (where[i] == pid && !touched[i])
|
|
break;
|
|
}
|
|
queue[last++] = i;
|
|
touched[i] = 1;
|
|
}
|
|
|
|
i = queue[first++];
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
k = adjncy[j];
|
|
if (where[k] == pid && !touched[k]) {
|
|
queue[last++] = k;
|
|
touched[k] = 1;
|
|
}
|
|
}
|
|
}
|
|
cptr[++ncmps] = first;
|
|
|
|
if (ncmps > 1 && report) {
|
|
printf("The graph has %"PRIDX" connected components in partition %"PRIDX":\t", ncmps, pid);
|
|
for (i=0; i<ncmps; i++) {
|
|
wgt = 0;
|
|
for (j=cptr[i]; j<cptr[i+1]; j++)
|
|
wgt += graph->vwgt[queue[j]];
|
|
printf("[%5"PRIDX" %5"PRIDX"] ", cptr[i+1]-cptr[i], wgt);
|
|
/*
|
|
if (cptr[i+1]-cptr[i] == 1)
|
|
printf("[%"PRIDX" %"PRIDX"] ", queue[cptr[i]], xadj[queue[cptr[i]]+1]-xadj[queue[cptr[i]]]);
|
|
*/
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
gk_free((void **)&touched, &queue, &cptr, LTERM);
|
|
|
|
return (ncmps == 1 ? 1 : 0);
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function identifies the number of connected components in a graph
|
|
that result after removing the vertices that belong to the vertex
|
|
separator (i.e., graph->where[i] == 2).
|
|
The connected component memberships are returned in the CSR-style
|
|
pair of arrays cptr, cind.
|
|
*/
|
|
/**************************************************************************/
|
|
idx_t FindSepInducedComponents(ctrl_t *ctrl, graph_t *graph, idx_t *cptr,
|
|
idx_t *cind)
|
|
{
|
|
idx_t i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
|
|
idx_t *xadj, *adjncy, *where, *touched, *queue;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
where = graph->where;
|
|
|
|
touched = ismalloc(nvtxs, 0, "IsConnected: queue");
|
|
|
|
for (i=0; i<graph->nbnd; i++)
|
|
touched[graph->bndind[i]] = 1;
|
|
|
|
queue = cind;
|
|
|
|
nleft = 0;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (where[i] != 2)
|
|
nleft++;
|
|
}
|
|
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (where[i] != 2)
|
|
break;
|
|
}
|
|
|
|
touched[i] = 1;
|
|
queue[0] = i;
|
|
first = 0;
|
|
last = 1;
|
|
cptr[0] = 0; /* This actually points to queue */
|
|
ncmps = 0;
|
|
|
|
while (first != nleft) {
|
|
if (first == last) { /* Find another starting vertex */
|
|
cptr[++ncmps] = first;
|
|
for (i=0; i<nvtxs; i++) {
|
|
if (!touched[i])
|
|
break;
|
|
}
|
|
queue[last++] = i;
|
|
touched[i] = 1;
|
|
}
|
|
|
|
i = queue[first++];
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
k = adjncy[j];
|
|
if (!touched[k]) {
|
|
queue[last++] = k;
|
|
touched[k] = 1;
|
|
}
|
|
}
|
|
}
|
|
cptr[++ncmps] = first;
|
|
|
|
gk_free((void **)&touched, LTERM);
|
|
|
|
return ncmps;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function finds all the connected components induced by the
|
|
partitioning vector in graph->where and tries to push them around to
|
|
remove some of them. */
|
|
/*************************************************************************/
|
|
void EliminateComponents(ctrl_t *ctrl, graph_t *graph)
|
|
{
|
|
idx_t i, ii, j, jj, k, me, nparts, nvtxs, ncon, ncmps, other,
|
|
ncand, target;
|
|
idx_t *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts;
|
|
idx_t *cptr, *cind, *cpvec, *pcptr, *pcind, *cwhere;
|
|
idx_t cid, bestcid, *cwgt, *bestcwgt;
|
|
idx_t ntodo, oldntodo, *todo;
|
|
rkv_t *cand;
|
|
real_t *tpwgts;
|
|
idx_t *vmarker=NULL, *pmarker=NULL, *modind=NULL; /* volume specific work arrays */
|
|
|
|
WCOREPUSH;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
ncon = graph->ncon;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
vwgt = graph->vwgt;
|
|
adjwgt = (ctrl->objtype == METIS_OBJTYPE_VOL ? NULL : graph->adjwgt);
|
|
|
|
where = graph->where;
|
|
pwgts = graph->pwgts;
|
|
|
|
nparts = ctrl->nparts;
|
|
tpwgts = ctrl->tpwgts;
|
|
|
|
cptr = iwspacemalloc(ctrl, nvtxs+1);
|
|
cind = iwspacemalloc(ctrl, nvtxs);
|
|
|
|
ncmps = FindPartitionInducedComponents(graph, where, cptr, cind);
|
|
|
|
IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO,
|
|
printf("I found %"PRIDX" components, for this %"PRIDX"-way partition\n",
|
|
ncmps, nparts));
|
|
|
|
/* There are more components than partitions */
|
|
if (ncmps > nparts) {
|
|
cwgt = iwspacemalloc(ctrl, ncon);
|
|
bestcwgt = iwspacemalloc(ctrl, ncon);
|
|
cpvec = iwspacemalloc(ctrl, nparts);
|
|
pcptr = iset(nparts+1, 0, iwspacemalloc(ctrl, nparts+1));
|
|
pcind = iwspacemalloc(ctrl, ncmps);
|
|
cwhere = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
|
|
todo = iwspacemalloc(ctrl, ncmps);
|
|
cand = (rkv_t *)wspacemalloc(ctrl, nparts*sizeof(rkv_t));
|
|
|
|
if (ctrl->objtype == METIS_OBJTYPE_VOL) {
|
|
/* Vol-refinement specific working arrays */
|
|
modind = iwspacemalloc(ctrl, nvtxs);
|
|
vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
|
|
pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
|
|
}
|
|
|
|
|
|
/* Get a CSR representation of the components-2-partitions mapping */
|
|
for (i=0; i<ncmps; i++)
|
|
pcptr[where[cind[cptr[i]]]]++;
|
|
MAKECSR(i, nparts, pcptr);
|
|
for (i=0; i<ncmps; i++)
|
|
pcind[pcptr[where[cind[cptr[i]]]]++] = i;
|
|
SHIFTCSR(i, nparts, pcptr);
|
|
|
|
/* Assign the heaviest component of each partition to its original partition */
|
|
for (ntodo=0, i=0; i<nparts; i++) {
|
|
if (pcptr[i+1]-pcptr[i] == 1)
|
|
bestcid = pcind[pcptr[i]];
|
|
else {
|
|
for (bestcid=-1, j=pcptr[i]; j<pcptr[i+1]; j++) {
|
|
cid = pcind[j];
|
|
iset(ncon, 0, cwgt);
|
|
for (ii=cptr[cid]; ii<cptr[cid+1]; ii++)
|
|
iaxpy(ncon, 1, vwgt+cind[ii]*ncon, 1, cwgt, 1);
|
|
if (bestcid == -1 || isum(ncon, bestcwgt, 1) < isum(ncon, cwgt, 1)) {
|
|
bestcid = cid;
|
|
icopy(ncon, cwgt, bestcwgt);
|
|
}
|
|
}
|
|
/* Keep track of those that need to be dealt with */
|
|
for (j=pcptr[i]; j<pcptr[i+1]; j++) {
|
|
if (pcind[j] != bestcid)
|
|
todo[ntodo++] = pcind[j];
|
|
}
|
|
}
|
|
|
|
for (j=cptr[bestcid]; j<cptr[bestcid+1]; j++) {
|
|
ASSERT(where[cind[j]] == i);
|
|
cwhere[cind[j]] = i;
|
|
}
|
|
}
|
|
|
|
|
|
while (ntodo > 0) {
|
|
oldntodo = ntodo;
|
|
for (i=0; i<ntodo; i++) {
|
|
cid = todo[i];
|
|
me = where[cind[cptr[cid]]]; /* Get the domain of this component */
|
|
|
|
/* Determine the weight of the block to be moved */
|
|
iset(ncon, 0, cwgt);
|
|
for (j=cptr[cid]; j<cptr[cid+1]; j++)
|
|
iaxpy(ncon, 1, vwgt+cind[j]*ncon, 1, cwgt, 1);
|
|
|
|
IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO,
|
|
printf("Trying to move %"PRIDX" [%"PRIDX"] from %"PRIDX"\n",
|
|
cid, isum(ncon, cwgt, 1), me));
|
|
|
|
/* Determine the connectivity */
|
|
iset(nparts, 0, cpvec);
|
|
for (j=cptr[cid]; j<cptr[cid+1]; j++) {
|
|
ii = cind[j];
|
|
for (jj=xadj[ii]; jj<xadj[ii+1]; jj++)
|
|
if (cwhere[adjncy[jj]] != -1)
|
|
cpvec[cwhere[adjncy[jj]]] += (adjwgt ? adjwgt[jj] : 1);
|
|
}
|
|
|
|
/* Put the neighbors into a cand[] array for sorting */
|
|
for (ncand=0, j=0; j<nparts; j++) {
|
|
if (cpvec[j] > 0) {
|
|
cand[ncand].key = cpvec[j];
|
|
cand[ncand++].val = j;
|
|
}
|
|
}
|
|
if (ncand == 0)
|
|
continue;
|
|
|
|
rkvsortd(ncand, cand);
|
|
|
|
/* Limit the moves to only the top candidates, which are defined as
|
|
those with connectivity at least 50% of the best.
|
|
This applies only when ncon=1, as for multi-constraint, balancing
|
|
will be hard. */
|
|
if (ncon == 1) {
|
|
for (j=1; j<ncand; j++) {
|
|
if (cand[j].key < .5*cand[0].key)
|
|
break;
|
|
}
|
|
ncand = j;
|
|
}
|
|
|
|
/* Now among those, select the one with the best balance */
|
|
target = cand[0].val;
|
|
for (j=1; j<ncand; j++) {
|
|
if (BetterBalanceKWay(ncon, cwgt, ctrl->ubfactors,
|
|
1, pwgts+target*ncon, ctrl->pijbm+target*ncon,
|
|
1, pwgts+cand[j].val*ncon, ctrl->pijbm+cand[j].val*ncon))
|
|
target = cand[j].val;
|
|
}
|
|
|
|
IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO,
|
|
printf("\tMoving it to %"PRIDX" [%"PRIDX"] [%"PRIDX"]\n", target, cpvec[target], ncand));
|
|
|
|
/* Note that as a result of a previous movement, a connected component may
|
|
now will like to stay to its original partition */
|
|
if (target != me) {
|
|
switch (ctrl->objtype) {
|
|
case METIS_OBJTYPE_CUT:
|
|
MoveGroupContigForCut(ctrl, graph, target, cid, cptr, cind);
|
|
break;
|
|
|
|
case METIS_OBJTYPE_VOL:
|
|
MoveGroupContigForVol(ctrl, graph, target, cid, cptr, cind,
|
|
vmarker, pmarker, modind);
|
|
break;
|
|
|
|
default:
|
|
gk_errexit(SIGERR, "Unknown objtype %d\n", ctrl->objtype);
|
|
}
|
|
}
|
|
|
|
/* Update the cwhere vector */
|
|
for (j=cptr[cid]; j<cptr[cid+1]; j++)
|
|
cwhere[cind[j]] = target;
|
|
|
|
todo[i] = todo[--ntodo];
|
|
}
|
|
if (oldntodo == ntodo) {
|
|
IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("Stopped at ntodo: %"PRIDX"\n", ntodo));
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<nvtxs; i++)
|
|
ASSERT(where[i] == cwhere[i]);
|
|
|
|
}
|
|
|
|
WCOREPOP;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function moves a collection of vertices and updates their rinfo
|
|
*/
|
|
/*************************************************************************/
|
|
void MoveGroupContigForCut(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t gid,
|
|
idx_t *ptr, idx_t *ind)
|
|
{
|
|
idx_t i, ii, iii, j, jj, k, l, nvtxs, nbnd, from, me;
|
|
idx_t *xadj, *adjncy, *adjwgt, *where, *bndptr, *bndind;
|
|
ckrinfo_t *myrinfo;
|
|
cnbr_t *mynbrs;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
adjncy = graph->adjncy;
|
|
adjwgt = graph->adjwgt;
|
|
|
|
where = graph->where;
|
|
bndptr = graph->bndptr;
|
|
bndind = graph->bndind;
|
|
|
|
nbnd = graph->nbnd;
|
|
|
|
for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
|
|
i = ind[iii];
|
|
from = where[i];
|
|
|
|
myrinfo = graph->ckrinfo+i;
|
|
if (myrinfo->inbr == -1) {
|
|
myrinfo->inbr = cnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]);
|
|
myrinfo->nnbrs = 0;
|
|
}
|
|
mynbrs = ctrl->cnbrpool + myrinfo->inbr;
|
|
|
|
/* find the location of 'to' in myrinfo or create it if it is not there */
|
|
for (k=0; k<myrinfo->nnbrs; k++) {
|
|
if (mynbrs[k].pid == to)
|
|
break;
|
|
}
|
|
if (k == myrinfo->nnbrs) {
|
|
mynbrs[k].pid = to;
|
|
mynbrs[k].ed = 0;
|
|
myrinfo->nnbrs++;
|
|
}
|
|
|
|
graph->mincut -= mynbrs[k].ed-myrinfo->id;
|
|
|
|
/* Update ID/ED and BND related information for the moved vertex */
|
|
iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
|
|
iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
|
|
UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd,
|
|
bndptr, bndind, BNDTYPE_REFINE);
|
|
|
|
/* Update the degrees of adjacent vertices */
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
ii = adjncy[j];
|
|
me = where[ii];
|
|
myrinfo = graph->ckrinfo+ii;
|
|
|
|
UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
|
|
from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, BNDTYPE_REFINE);
|
|
}
|
|
|
|
ASSERT(CheckRInfo(ctrl, graph->ckrinfo+i));
|
|
}
|
|
|
|
graph->nbnd = nbnd;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/*! This function moves a collection of vertices and updates their rinfo
|
|
*/
|
|
/*************************************************************************/
|
|
void MoveGroupContigForVol(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t gid,
|
|
idx_t *ptr, idx_t *ind, idx_t *vmarker, idx_t *pmarker,
|
|
idx_t *modind)
|
|
{
|
|
idx_t i, ii, iii, j, jj, k, l, nvtxs, from, me, other, xgain;
|
|
idx_t *xadj, *vsize, *adjncy, *where;
|
|
vkrinfo_t *myrinfo, *orinfo;
|
|
vnbr_t *mynbrs, *onbrs;
|
|
|
|
nvtxs = graph->nvtxs;
|
|
xadj = graph->xadj;
|
|
vsize = graph->vsize;
|
|
adjncy = graph->adjncy;
|
|
where = graph->where;
|
|
|
|
for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
|
|
i = ind[iii];
|
|
from = where[i];
|
|
|
|
myrinfo = graph->vkrinfo+i;
|
|
if (myrinfo->inbr == -1) {
|
|
myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]);
|
|
myrinfo->nnbrs = 0;
|
|
}
|
|
mynbrs = ctrl->vnbrpool + myrinfo->inbr;
|
|
|
|
xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? vsize[i] : 0);
|
|
|
|
/* find the location of 'to' in myrinfo or create it if it is not there */
|
|
for (k=0; k<myrinfo->nnbrs; k++) {
|
|
if (mynbrs[k].pid == to)
|
|
break;
|
|
}
|
|
if (k == myrinfo->nnbrs) {
|
|
if (myrinfo->nid > 0)
|
|
xgain -= vsize[i];
|
|
|
|
/* determine the volume gain resulting from that move */
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
ii = adjncy[j];
|
|
other = where[ii];
|
|
orinfo = graph->vkrinfo+ii;
|
|
onbrs = ctrl->vnbrpool + orinfo->inbr;
|
|
ASSERT(other != to)
|
|
|
|
if (from == other) {
|
|
/* Same subdomain vertex: Decrease the gain if 'to' is a new neighbor. */
|
|
for (l=0; l<orinfo->nnbrs; l++) {
|
|
if (onbrs[l].pid == to)
|
|
break;
|
|
}
|
|
if (l == orinfo->nnbrs)
|
|
xgain -= vsize[ii];
|
|
}
|
|
else {
|
|
/* Remote vertex: increase if 'to' is a new subdomain */
|
|
for (l=0; l<orinfo->nnbrs; l++) {
|
|
if (onbrs[l].pid == to)
|
|
break;
|
|
}
|
|
if (l == orinfo->nnbrs)
|
|
xgain -= vsize[ii];
|
|
|
|
/* Remote vertex: decrease if i is the only connection to 'from' */
|
|
for (l=0; l<orinfo->nnbrs; l++) {
|
|
if (onbrs[l].pid == from && onbrs[l].ned == 1) {
|
|
xgain += vsize[ii];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
graph->minvol -= xgain;
|
|
graph->mincut -= -myrinfo->nid;
|
|
}
|
|
else {
|
|
graph->minvol -= (xgain + mynbrs[k].gv);
|
|
graph->mincut -= mynbrs[k].ned-myrinfo->nid;
|
|
}
|
|
|
|
|
|
/* Update where and pwgts */
|
|
where[i] = to;
|
|
iaxpy(graph->ncon, 1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon, 1);
|
|
iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
|
|
|
|
/* Update the id/ed/gains/bnd of potentially affected nodes */
|
|
KWayVolUpdate(ctrl, graph, i, from, to, NULL, NULL, NULL, NULL,
|
|
NULL, BNDTYPE_REFINE, vmarker, pmarker, modind);
|
|
|
|
/*CheckKWayVolPartitionParams(ctrl, graph);*/
|
|
}
|
|
|
|
ASSERT(ComputeCut(graph, where) == graph->mincut);
|
|
ASSERTP(ComputeVolume(graph, where) == graph->minvol,
|
|
("%"PRIDX" %"PRIDX"\n", ComputeVolume(graph, where), graph->minvol));
|
|
|
|
}
|
|
|
|
|