Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/contig.c
3206 views
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
700
701