~elmer-csc-ubuntu/elmercsc/devel

« back to all changes in this revision

Viewing changes to elmergrid/src/metis-5.1.0/libmetis/contig.c

  • Committer: GitHub
  • Author(s): Peter R
  • Date: 2017-10-04 13:47:14 UTC
  • mfrom: (575.1.17)
  • Revision ID: git-v1:91780af69137b74ec539fedc4ad70c9ec52d732a
Merge pull request #115 from ElmerCSC/metis_update

Updated to new Metis API for devel branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*!
 
2
\file 
 
3
\brief Functions that deal with eliminating disconnected partitions
 
4
 
 
5
\date Started 7/15/98
 
6
\author George
 
7
\author Copyright 1997-2009, Regents of the University of Minnesota 
 
8
\version $Id: contig.c 10513 2011-07-07 22:06:03Z karypis $
 
9
*/
 
10
 
 
11
#include "metislib.h"
 
12
 
 
13
 
 
14
/*************************************************************************/
 
15
/*! This function finds the connected components induced by the 
 
16
    partitioning vector.
 
17
 
 
18
    \param graph is the graph structure
 
19
    \param where is the partitioning vector. If this is NULL, then the
 
20
           entire graph is treated to belong into a single partition.
 
21
    \param cptr is the ptr structure of the CSR representation of the 
 
22
           components. The length of this vector must be graph->nvtxs+1.
 
23
    \param cind is the indices structure of the CSR representation of 
 
24
           the components. The length of this vector must be graph->nvtxs.
 
25
 
 
26
    \returns the number of components that it found.
 
27
 
 
28
    \note The cptr and cind parameters can be NULL, in which case only the
 
29
          number of connected components is returned.
 
30
*/
 
31
/*************************************************************************/
 
32
idx_t FindPartitionInducedComponents(graph_t *graph, idx_t *where, 
 
33
          idx_t *cptr, idx_t *cind)
 
34
{
 
35
  idx_t i, ii, j, jj, k, me=0, nvtxs, first, last, nleft, ncmps;
 
36
  idx_t *xadj, *adjncy;
 
37
  idx_t *touched, *perm, *todo;
 
38
  idx_t mustfree_ccsr=0, mustfree_where=0;
 
39
 
 
40
  nvtxs  = graph->nvtxs;
 
41
  xadj   = graph->xadj;
 
42
  adjncy = graph->adjncy;
 
43
 
 
44
  /* Deal with NULL supplied cptr/cind vectors */
 
45
  if (cptr == NULL) {
 
46
    cptr = imalloc(nvtxs+1, "FindPartitionInducedComponents: cptr");
 
47
    cind = imalloc(nvtxs, "FindPartitionInducedComponents: cind");
 
48
    mustfree_ccsr = 1;
 
49
  }
 
50
 
 
51
  /* Deal with NULL supplied where vector */
 
52
  if (where == NULL) {
 
53
    where = ismalloc(nvtxs, 0, "FindPartitionInducedComponents: where");
 
54
    mustfree_where = 1;
 
55
  }
 
56
 
 
57
  /* Allocate memory required for the BFS traversal */
 
58
  perm    = iincset(nvtxs, 0, imalloc(nvtxs, "FindPartitionInducedComponents: perm"));
 
59
  todo    = iincset(nvtxs, 0, imalloc(nvtxs, "FindPartitionInducedComponents: todo"));
 
60
  touched = ismalloc(nvtxs, 0, "FindPartitionInducedComponents: touched");
 
61
 
 
62
 
 
63
  /* Find the connected componends induced by the partition */
 
64
  ncmps = -1;
 
65
  first = last = 0;
 
66
  nleft = nvtxs;
 
67
  while (nleft > 0) {
 
68
    if (first == last) { /* Find another starting vertex */
 
69
      cptr[++ncmps] = first;
 
70
      ASSERT(touched[todo[0]] == 0);
 
71
      i = todo[0];
 
72
      cind[last++] = i;
 
73
      touched[i] = 1;
 
74
      me = where[i];
 
75
    }
 
76
 
 
77
    i = cind[first++];
 
78
    k = perm[i];
 
79
    j = todo[k] = todo[--nleft];
 
80
    perm[j] = k;
 
81
 
 
82
    for (j=xadj[i]; j<xadj[i+1]; j++) {
 
83
      k = adjncy[j];
 
84
      if (where[k] == me && !touched[k]) {
 
85
        cind[last++] = k;
 
86
        touched[k] = 1;
 
87
      }
 
88
    }
 
89
  }
 
90
  cptr[++ncmps] = first;
 
91
 
 
92
  if (mustfree_ccsr)
 
93
    gk_free((void **)&cptr, &cind, LTERM);
 
94
  if (mustfree_where)
 
95
    gk_free((void **)&where, LTERM);
 
96
 
 
97
  gk_free((void **)&perm, &todo, &touched, LTERM);
 
98
 
 
99
  return ncmps;
 
100
}
 
101
 
 
102
 
 
103
/*************************************************************************/
 
104
/*! This function computes a permutation of the vertices based on a
 
105
    breadth-first-traversal. It can be used for re-ordering the graph
 
106
    to reduce its bandwidth for better cache locality.
 
107
 
 
108
    \param ctrl is the control structure
 
109
    \param graph is the graph structure
 
110
    \param perm is the array that upon completion, perm[i] will store
 
111
           the ID of the vertex that corresponds to the ith vertex in the
 
112
           re-ordered graph.
 
113
*/
 
114
/*************************************************************************/
 
115
void ComputeBFSOrdering(ctrl_t *ctrl, graph_t *graph, idx_t *bfsperm)
 
116
{
 
117
  idx_t i, j, k, nvtxs, first, last;
 
118
  idx_t *xadj, *adjncy, *perm;
 
119
 
 
120
  WCOREPUSH;
 
121
 
 
122
  nvtxs  = graph->nvtxs;
 
123
  xadj   = graph->xadj;
 
124
  adjncy = graph->adjncy;
 
125
 
 
126
  /* Allocate memory required for the BFS traversal */
 
127
  perm = iincset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
 
128
 
 
129
  iincset(nvtxs, 0, bfsperm);  /* this array will also store the vertices
 
130
                                  still to be processed */
 
131
 
 
132
  /* Find the connected componends induced by the partition */
 
133
  first = last = 0;
 
134
  while (first < nvtxs) {
 
135
    if (first == last) { /* Find another starting vertex */
 
136
      k = bfsperm[last];
 
137
      ASSERT(perm[k] != -1);
 
138
      perm[k] = -1; /* mark node as being visited */
 
139
      last++;
 
140
    }
 
141
 
 
142
    i = bfsperm[first++];
 
143
    for (j=xadj[i]; j<xadj[i+1]; j++) {
 
144
      k = adjncy[j];
 
145
      /* if a node has been already been visited, its perm[] will be -1 */
 
146
      if (perm[k] != -1) {
 
147
        /* perm[k] is the location within bfsperm of where k resides; 
 
148
           put in that location bfsperm[last] that we are about to
 
149
           overwrite and update perm[bfsperm[last]] to reflect that. */
 
150
        bfsperm[perm[k]]    = bfsperm[last];
 
151
        perm[bfsperm[last]] = perm[k];
 
152
 
 
153
        bfsperm[last++] = k;  /* put node at the end of the "queue" */
 
154
        perm[k]         = -1; /* mark node as being visited */
 
155
      }
 
156
    }
 
157
  }
 
158
 
 
159
  WCOREPOP;
 
160
}
 
161
 
 
162
 
 
163
/*************************************************************************/
 
164
/*! This function checks whether a graph is contiguous or not. 
 
165
 */
 
166
/**************************************************************************/
 
167
idx_t IsConnected(graph_t *graph, idx_t report)
 
168
{
 
169
  idx_t ncmps;
 
170
 
 
171
  ncmps = FindPartitionInducedComponents(graph, NULL, NULL, NULL);
 
172
 
 
173
  if (ncmps != 1 && report)
 
174
    printf("The graph is not connected. It has %"PRIDX" connected components.\n", ncmps);
 
175
 
 
176
  return (ncmps == 1);
 
177
}
 
178
 
 
179
 
 
180
/*************************************************************************/
 
181
/*! This function checks whether or not partition pid is contigous
 
182
  */
 
183
/*************************************************************************/
 
184
idx_t IsConnectedSubdomain(ctrl_t *ctrl, graph_t *graph, idx_t pid, idx_t report)
 
185
{
 
186
  idx_t i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
 
187
  idx_t *xadj, *adjncy, *where, *touched, *queue;
 
188
  idx_t *cptr;
 
189
 
 
190
  nvtxs  = graph->nvtxs;
 
191
  xadj   = graph->xadj;
 
192
  adjncy = graph->adjncy;
 
193
  where  = graph->where;
 
194
 
 
195
  touched = ismalloc(nvtxs, 0, "IsConnected: touched");
 
196
  queue   = imalloc(nvtxs, "IsConnected: queue");
 
197
  cptr    = imalloc(nvtxs+1, "IsConnected: cptr");
 
198
 
 
199
  nleft = 0;
 
200
  for (i=0; i<nvtxs; i++) {
 
201
    if (where[i] == pid) 
 
202
      nleft++;
 
203
  }
 
204
 
 
205
  for (i=0; i<nvtxs; i++) {
 
206
    if (where[i] == pid) 
 
207
      break;
 
208
  }
 
209
 
 
210
  touched[i] = 1;
 
211
  queue[0] = i;
 
212
  first = 0; last = 1;
 
213
 
 
214
  cptr[0] = 0;  /* This actually points to queue */
 
215
  ncmps = 0;
 
216
  while (first != nleft) {
 
217
    if (first == last) { /* Find another starting vertex */
 
218
      cptr[++ncmps] = first;
 
219
      for (i=0; i<nvtxs; i++) {
 
220
        if (where[i] == pid && !touched[i])
 
221
          break;
 
222
      }
 
223
      queue[last++] = i;
 
224
      touched[i] = 1;
 
225
    }
 
226
 
 
227
    i = queue[first++];
 
228
    for (j=xadj[i]; j<xadj[i+1]; j++) {
 
229
      k = adjncy[j];
 
230
      if (where[k] == pid && !touched[k]) {
 
231
        queue[last++] = k;
 
232
        touched[k] = 1;
 
233
      }
 
234
    }
 
235
  }
 
236
  cptr[++ncmps] = first;
 
237
 
 
238
  if (ncmps > 1 && report) {
 
239
    printf("The graph has %"PRIDX" connected components in partition %"PRIDX":\t", ncmps, pid);
 
240
    for (i=0; i<ncmps; i++) {
 
241
      wgt = 0;
 
242
      for (j=cptr[i]; j<cptr[i+1]; j++)
 
243
        wgt += graph->vwgt[queue[j]];
 
244
      printf("[%5"PRIDX" %5"PRIDX"] ", cptr[i+1]-cptr[i], wgt);
 
245
      /*
 
246
      if (cptr[i+1]-cptr[i] == 1)
 
247
        printf("[%"PRIDX" %"PRIDX"] ", queue[cptr[i]], xadj[queue[cptr[i]]+1]-xadj[queue[cptr[i]]]);
 
248
      */
 
249
    }
 
250
    printf("\n");
 
251
  }
 
252
 
 
253
  gk_free((void **)&touched, &queue, &cptr, LTERM);
 
254
 
 
255
  return (ncmps == 1 ? 1 : 0);
 
256
}
 
257
 
 
258
 
 
259
/*************************************************************************/
 
260
/*! This function identifies the number of connected components in a graph
 
261
    that result after removing the vertices that belong to the vertex 
 
262
    separator (i.e., graph->where[i] == 2).
 
263
    The connected component memberships are returned in the CSR-style 
 
264
    pair of arrays cptr, cind.
 
265
*/
 
266
/**************************************************************************/
 
267
idx_t FindSepInducedComponents(ctrl_t *ctrl, graph_t *graph, idx_t *cptr, 
 
268
          idx_t *cind)
 
269
{
 
270
  idx_t i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
 
271
  idx_t *xadj, *adjncy, *where, *touched, *queue;
 
272
 
 
273
  nvtxs  = graph->nvtxs;
 
274
  xadj   = graph->xadj;
 
275
  adjncy = graph->adjncy;
 
276
  where  = graph->where;
 
277
 
 
278
  touched = ismalloc(nvtxs, 0, "IsConnected: queue");
 
279
 
 
280
  for (i=0; i<graph->nbnd; i++)
 
281
    touched[graph->bndind[i]] = 1;
 
282
 
 
283
  queue = cind;
 
284
 
 
285
  nleft = 0;
 
286
  for (i=0; i<nvtxs; i++) {
 
287
    if (where[i] != 2) 
 
288
      nleft++;
 
289
  }
 
290
 
 
291
  for (i=0; i<nvtxs; i++) {
 
292
    if (where[i] != 2)
 
293
      break;
 
294
  }
 
295
 
 
296
  touched[i] = 1;
 
297
  queue[0]   = i;
 
298
  first      = 0; 
 
299
  last       = 1;
 
300
  cptr[0]    = 0;  /* This actually points to queue */
 
301
  ncmps      = 0;
 
302
 
 
303
  while (first != nleft) {
 
304
    if (first == last) { /* Find another starting vertex */
 
305
      cptr[++ncmps] = first;
 
306
      for (i=0; i<nvtxs; i++) {
 
307
        if (!touched[i])
 
308
          break;
 
309
      }
 
310
      queue[last++] = i;
 
311
      touched[i] = 1;
 
312
    }
 
313
 
 
314
    i = queue[first++];
 
315
    for (j=xadj[i]; j<xadj[i+1]; j++) {
 
316
      k = adjncy[j];
 
317
      if (!touched[k]) {
 
318
        queue[last++] = k;
 
319
        touched[k] = 1;
 
320
      }
 
321
    }
 
322
  }
 
323
  cptr[++ncmps] = first;
 
324
 
 
325
  gk_free((void **)&touched, LTERM);
 
326
 
 
327
  return ncmps;
 
328
}
 
329
 
 
330
 
 
331
/*************************************************************************/
 
332
/*! This function finds all the connected components induced by the 
 
333
    partitioning vector in graph->where and tries to push them around to 
 
334
    remove some of them. */
 
335
/*************************************************************************/
 
336
void EliminateComponents(ctrl_t *ctrl, graph_t *graph)
 
337
{
 
338
  idx_t i, ii, j, jj, k, me, nparts, nvtxs, ncon, ncmps, other, 
 
339
        ncand, target;
 
340
  idx_t *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts;
 
341
  idx_t *cptr, *cind, *cpvec, *pcptr, *pcind, *cwhere;
 
342
  idx_t cid, bestcid, *cwgt, *bestcwgt;
 
343
  idx_t ntodo, oldntodo, *todo;
 
344
  rkv_t *cand;
 
345
  real_t *tpwgts;
 
346
  idx_t *vmarker=NULL, *pmarker=NULL, *modind=NULL;  /* volume specific work arrays */
 
347
 
 
348
  WCOREPUSH;
 
349
 
 
350
  nvtxs  = graph->nvtxs;
 
351
  ncon   = graph->ncon;
 
352
  xadj   = graph->xadj;
 
353
  adjncy = graph->adjncy;
 
354
  vwgt   = graph->vwgt;
 
355
  adjwgt = (ctrl->objtype == METIS_OBJTYPE_VOL ? NULL : graph->adjwgt);
 
356
 
 
357
  where = graph->where;
 
358
  pwgts = graph->pwgts;
 
359
 
 
360
  nparts = ctrl->nparts;
 
361
  tpwgts = ctrl->tpwgts;
 
362
 
 
363
  cptr = iwspacemalloc(ctrl, nvtxs+1);
 
364
  cind = iwspacemalloc(ctrl, nvtxs);
 
365
 
 
366
  ncmps = FindPartitionInducedComponents(graph, where, cptr, cind);
 
367
 
 
368
  IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, 
 
369
      printf("I found %"PRIDX" components, for this %"PRIDX"-way partition\n", 
 
370
          ncmps, nparts)); 
 
371
 
 
372
  /* There are more components than partitions */
 
373
  if (ncmps > nparts) {
 
374
    cwgt     = iwspacemalloc(ctrl, ncon);
 
375
    bestcwgt = iwspacemalloc(ctrl, ncon);
 
376
    cpvec    = iwspacemalloc(ctrl, nparts);
 
377
    pcptr    = iset(nparts+1, 0, iwspacemalloc(ctrl, nparts+1));
 
378
    pcind    = iwspacemalloc(ctrl, ncmps);
 
379
    cwhere   = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
 
380
    todo     = iwspacemalloc(ctrl, ncmps);
 
381
    cand     = (rkv_t *)wspacemalloc(ctrl, nparts*sizeof(rkv_t));
 
382
 
 
383
    if (ctrl->objtype == METIS_OBJTYPE_VOL) {
 
384
      /* Vol-refinement specific working arrays */
 
385
      modind  = iwspacemalloc(ctrl, nvtxs);
 
386
      vmarker = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs));
 
387
      pmarker = iset(nparts, -1, iwspacemalloc(ctrl, nparts));
 
388
    }
 
389
 
 
390
 
 
391
    /* Get a CSR representation of the components-2-partitions mapping */
 
392
    for (i=0; i<ncmps; i++) 
 
393
      pcptr[where[cind[cptr[i]]]]++;
 
394
    MAKECSR(i, nparts, pcptr);
 
395
    for (i=0; i<ncmps; i++) 
 
396
      pcind[pcptr[where[cind[cptr[i]]]]++] = i;
 
397
    SHIFTCSR(i, nparts, pcptr);
 
398
 
 
399
    /* Assign the heaviest component of each partition to its original partition */
 
400
    for (ntodo=0, i=0; i<nparts; i++) {
 
401
      if (pcptr[i+1]-pcptr[i] == 1)
 
402
        bestcid = pcind[pcptr[i]];
 
403
      else {
 
404
        for (bestcid=-1, j=pcptr[i]; j<pcptr[i+1]; j++) {
 
405
          cid = pcind[j];
 
406
          iset(ncon, 0, cwgt);
 
407
          for (ii=cptr[cid]; ii<cptr[cid+1]; ii++)
 
408
            iaxpy(ncon, 1, vwgt+cind[ii]*ncon, 1, cwgt, 1);
 
409
          if (bestcid == -1 || isum(ncon, bestcwgt, 1) < isum(ncon, cwgt, 1)) {
 
410
            bestcid  = cid;
 
411
            icopy(ncon, cwgt, bestcwgt);
 
412
          }
 
413
        }
 
414
        /* Keep track of those that need to be dealt with */
 
415
        for (j=pcptr[i]; j<pcptr[i+1]; j++) {
 
416
          if (pcind[j] != bestcid)
 
417
            todo[ntodo++] = pcind[j];
 
418
        }
 
419
      }
 
420
 
 
421
      for (j=cptr[bestcid]; j<cptr[bestcid+1]; j++) {
 
422
        ASSERT(where[cind[j]] == i);
 
423
        cwhere[cind[j]] = i;
 
424
      }
 
425
    }
 
426
 
 
427
 
 
428
    while (ntodo > 0) {
 
429
      oldntodo = ntodo;
 
430
      for (i=0; i<ntodo; i++) {
 
431
        cid = todo[i];
 
432
        me = where[cind[cptr[cid]]];  /* Get the domain of this component */
 
433
 
 
434
        /* Determine the weight of the block to be moved */
 
435
        iset(ncon, 0, cwgt);
 
436
        for (j=cptr[cid]; j<cptr[cid+1]; j++) 
 
437
          iaxpy(ncon, 1, vwgt+cind[j]*ncon, 1, cwgt, 1);
 
438
 
 
439
        IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, 
 
440
            printf("Trying to move %"PRIDX" [%"PRIDX"] from %"PRIDX"\n", 
 
441
                cid, isum(ncon, cwgt, 1), me)); 
 
442
 
 
443
        /* Determine the connectivity */
 
444
        iset(nparts, 0, cpvec);
 
445
        for (j=cptr[cid]; j<cptr[cid+1]; j++) {
 
446
          ii = cind[j];
 
447
          for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) 
 
448
            if (cwhere[adjncy[jj]] != -1)
 
449
              cpvec[cwhere[adjncy[jj]]] += (adjwgt ? adjwgt[jj] : 1);
 
450
        }
 
451
 
 
452
        /* Put the neighbors into a cand[] array for sorting */
 
453
        for (ncand=0, j=0; j<nparts; j++) {
 
454
          if (cpvec[j] > 0) {
 
455
            cand[ncand].key   = cpvec[j];
 
456
            cand[ncand++].val = j;
 
457
          }
 
458
        }
 
459
        if (ncand == 0)
 
460
          continue;
 
461
 
 
462
        rkvsortd(ncand, cand);
 
463
 
 
464
        /* Limit the moves to only the top candidates, which are defined as 
 
465
           those with connectivity at least 50% of the best.
 
466
           This applies only when ncon=1, as for multi-constraint, balancing
 
467
           will be hard. */
 
468
        if (ncon == 1) {
 
469
          for (j=1; j<ncand; j++) {
 
470
            if (cand[j].key < .5*cand[0].key)
 
471
              break;
 
472
          }
 
473
          ncand = j;
 
474
        }
 
475
      
 
476
        /* Now among those, select the one with the best balance */
 
477
        target = cand[0].val;
 
478
        for (j=1; j<ncand; j++) {
 
479
          if (BetterBalanceKWay(ncon, cwgt, ctrl->ubfactors,
 
480
                1, pwgts+target*ncon, ctrl->pijbm+target*ncon,
 
481
                1, pwgts+cand[j].val*ncon, ctrl->pijbm+cand[j].val*ncon))
 
482
            target = cand[j].val;
 
483
        }
 
484
 
 
485
        IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, 
 
486
            printf("\tMoving it to %"PRIDX" [%"PRIDX"] [%"PRIDX"]\n", target, cpvec[target], ncand));
 
487
 
 
488
        /* Note that as a result of a previous movement, a connected component may
 
489
           now will like to stay to its original partition */
 
490
        if (target != me) {
 
491
          switch (ctrl->objtype) {
 
492
            case METIS_OBJTYPE_CUT:
 
493
              MoveGroupContigForCut(ctrl, graph, target, cid, cptr, cind);
 
494
              break;
 
495
 
 
496
            case METIS_OBJTYPE_VOL:
 
497
              MoveGroupContigForVol(ctrl, graph, target, cid, cptr, cind, 
 
498
                  vmarker, pmarker, modind);
 
499
              break;
 
500
 
 
501
            default:
 
502
              gk_errexit(SIGERR, "Unknown objtype %d\n", ctrl->objtype);
 
503
          }
 
504
        }
 
505
 
 
506
        /* Update the cwhere vector */
 
507
        for (j=cptr[cid]; j<cptr[cid+1]; j++) 
 
508
          cwhere[cind[j]] = target;
 
509
 
 
510
        todo[i] = todo[--ntodo];
 
511
      }
 
512
      if (oldntodo == ntodo) {
 
513
        IFSET(ctrl->dbglvl, METIS_DBG_CONTIGINFO, printf("Stopped at ntodo: %"PRIDX"\n", ntodo));
 
514
        break;
 
515
      }
 
516
    }
 
517
 
 
518
    for (i=0; i<nvtxs; i++)
 
519
      ASSERT(where[i] == cwhere[i]);
 
520
 
 
521
  }
 
522
 
 
523
  WCOREPOP;
 
524
}
 
525
 
 
526
 
 
527
/*************************************************************************/
 
528
/*! This function moves a collection of vertices and updates their rinfo 
 
529
 */
 
530
/*************************************************************************/
 
531
void MoveGroupContigForCut(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t gid, 
 
532
         idx_t *ptr, idx_t *ind)
 
533
{
 
534
  idx_t i, ii, iii, j, jj, k, l, nvtxs, nbnd, from, me;
 
535
  idx_t *xadj, *adjncy, *adjwgt, *where, *bndptr, *bndind;
 
536
  ckrinfo_t *myrinfo;
 
537
  cnbr_t *mynbrs;
 
538
 
 
539
  nvtxs  = graph->nvtxs;
 
540
  xadj   = graph->xadj;
 
541
  adjncy = graph->adjncy;
 
542
  adjwgt = graph->adjwgt;
 
543
 
 
544
  where  = graph->where;
 
545
  bndptr = graph->bndptr;
 
546
  bndind = graph->bndind;
 
547
 
 
548
  nbnd = graph->nbnd;
 
549
 
 
550
  for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
 
551
    i    = ind[iii];
 
552
    from = where[i];
 
553
 
 
554
    myrinfo = graph->ckrinfo+i;
 
555
    if (myrinfo->inbr == -1) {
 
556
      myrinfo->inbr = cnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
 
557
      myrinfo->nnbrs = 0;
 
558
    }
 
559
    mynbrs = ctrl->cnbrpool + myrinfo->inbr; 
 
560
 
 
561
    /* find the location of 'to' in myrinfo or create it if it is not there */
 
562
    for (k=0; k<myrinfo->nnbrs; k++) {
 
563
      if (mynbrs[k].pid == to)
 
564
        break;
 
565
    }
 
566
    if (k == myrinfo->nnbrs) {
 
567
      mynbrs[k].pid = to;
 
568
      mynbrs[k].ed = 0;
 
569
      myrinfo->nnbrs++;
 
570
    }
 
571
 
 
572
    graph->mincut -= mynbrs[k].ed-myrinfo->id;
 
573
 
 
574
    /* Update ID/ED and BND related information for the moved vertex */
 
575
    iaxpy(graph->ncon,  1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon,   1);
 
576
    iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
 
577
    UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd, 
 
578
        bndptr, bndind, BNDTYPE_REFINE);
 
579
 
 
580
    /* Update the degrees of adjacent vertices */
 
581
    for (j=xadj[i]; j<xadj[i+1]; j++) {
 
582
      ii = adjncy[j];
 
583
      me = where[ii];
 
584
      myrinfo = graph->ckrinfo+ii;
 
585
 
 
586
      UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me,
 
587
          from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, BNDTYPE_REFINE);
 
588
    }
 
589
 
 
590
    ASSERT(CheckRInfo(ctrl, graph->ckrinfo+i));
 
591
  }
 
592
 
 
593
  graph->nbnd = nbnd;
 
594
}
 
595
 
 
596
 
 
597
/*************************************************************************/
 
598
/*! This function moves a collection of vertices and updates their rinfo 
 
599
 */
 
600
/*************************************************************************/
 
601
void MoveGroupContigForVol(ctrl_t *ctrl, graph_t *graph, idx_t to, idx_t gid, 
 
602
         idx_t *ptr, idx_t *ind, idx_t *vmarker, idx_t *pmarker, 
 
603
         idx_t *modind)
 
604
{
 
605
  idx_t i, ii, iii, j, jj, k, l, nvtxs, from, me, other, xgain;
 
606
  idx_t *xadj, *vsize, *adjncy, *where;
 
607
  vkrinfo_t *myrinfo, *orinfo;
 
608
  vnbr_t *mynbrs, *onbrs;
 
609
 
 
610
  nvtxs  = graph->nvtxs;
 
611
  xadj   = graph->xadj;
 
612
  vsize  = graph->vsize;
 
613
  adjncy = graph->adjncy;
 
614
  where  = graph->where;
 
615
 
 
616
  for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
 
617
    i    = ind[iii];
 
618
    from = where[i];
 
619
 
 
620
    myrinfo = graph->vkrinfo+i;
 
621
    if (myrinfo->inbr == -1) {
 
622
      myrinfo->inbr = vnbrpoolGetNext(ctrl, xadj[i+1]-xadj[i]+1);
 
623
      myrinfo->nnbrs = 0;
 
624
    }
 
625
    mynbrs = ctrl->vnbrpool + myrinfo->inbr; 
 
626
 
 
627
    xgain = (myrinfo->nid == 0 && myrinfo->ned > 0 ? vsize[i] : 0);
 
628
 
 
629
    /* find the location of 'to' in myrinfo or create it if it is not there */
 
630
    for (k=0; k<myrinfo->nnbrs; k++) {
 
631
      if (mynbrs[k].pid == to)
 
632
        break;
 
633
    }
 
634
    if (k == myrinfo->nnbrs) {
 
635
      if (myrinfo->nid > 0)
 
636
        xgain -= vsize[i];
 
637
 
 
638
      /* determine the volume gain resulting from that move */
 
639
      for (j=xadj[i]; j<xadj[i+1]; j++) {
 
640
        ii     = adjncy[j];
 
641
        other  = where[ii];
 
642
        orinfo = graph->vkrinfo+ii;
 
643
        onbrs  = ctrl->vnbrpool + orinfo->inbr;
 
644
        ASSERT(other != to)
 
645
 
 
646
        if (from == other) {
 
647
          /* Same subdomain vertex: Decrease the gain if 'to' is a new neighbor. */
 
648
          for (l=0; l<orinfo->nnbrs; l++) {
 
649
            if (onbrs[l].pid == to)
 
650
              break;
 
651
          }
 
652
          if (l == orinfo->nnbrs) 
 
653
            xgain -= vsize[ii];
 
654
        }
 
655
        else {
 
656
          /* Remote vertex: increase if 'to' is a new subdomain */
 
657
          for (l=0; l<orinfo->nnbrs; l++) {
 
658
            if (onbrs[l].pid == to)
 
659
              break;
 
660
          }
 
661
          if (l == orinfo->nnbrs) 
 
662
            xgain -= vsize[ii];
 
663
 
 
664
          /* Remote vertex: decrease if i is the only connection to 'from' */
 
665
          for (l=0; l<orinfo->nnbrs; l++) {
 
666
            if (onbrs[l].pid == from && onbrs[l].ned == 1) {
 
667
              xgain += vsize[ii];
 
668
              break;
 
669
            }
 
670
          }
 
671
        }
 
672
      }
 
673
      graph->minvol -= xgain;
 
674
      graph->mincut -= -myrinfo->nid;
 
675
    }
 
676
    else {
 
677
      graph->minvol -= (xgain + mynbrs[k].gv);
 
678
      graph->mincut -= mynbrs[k].ned-myrinfo->nid;
 
679
    }
 
680
 
 
681
 
 
682
    /* Update where and pwgts */
 
683
    where[i] = to;
 
684
    iaxpy(graph->ncon,  1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+to*graph->ncon,   1);
 
685
    iaxpy(graph->ncon, -1, graph->vwgt+i*graph->ncon, 1, graph->pwgts+from*graph->ncon, 1);
 
686
 
 
687
    /* Update the id/ed/gains/bnd of potentially affected nodes */
 
688
    KWayVolUpdate(ctrl, graph, i, from, to, NULL, NULL, NULL, NULL,
 
689
        NULL, BNDTYPE_REFINE, vmarker, pmarker, modind);
 
690
 
 
691
    /*CheckKWayVolPartitionParams(ctrl, graph);*/
 
692
  }
 
693
 
 
694
  ASSERT(ComputeCut(graph, where) == graph->mincut);
 
695
  ASSERTP(ComputeVolume(graph, where) == graph->minvol,
 
696
      ("%"PRIDX" %"PRIDX"\n", ComputeVolume(graph, where), graph->minvol));
 
697
 
 
698
}
 
699