~elmer-csc-ubuntu/elmercsc/devel

« back to all changes in this revision

Viewing changes to elmergrid/src/metis-5.1.0/libmetis/sfm.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
 * Copyright 1997, Regents of the University of Minnesota
 
3
 *
 
4
 * sfm.c
 
5
 *
 
6
 * This file contains code that implementes an FM-based separator refinement
 
7
 *
 
8
 * Started 8/1/97
 
9
 * George
 
10
 *
 
11
 * $Id: sfm.c 10874 2011-10-17 23:13:00Z karypis $
 
12
 *
 
13
 */
 
14
 
 
15
#include "metislib.h"
 
16
 
 
17
 
 
18
/*************************************************************************/
 
19
/*! This function performs a node-based FM refinement */
 
20
/**************************************************************************/
 
21
void FM_2WayNodeRefine2Sided(ctrl_t *ctrl, graph_t *graph, idx_t niter)
 
22
{
 
23
  idx_t i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
 
24
  idx_t *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
 
25
  idx_t *mptr, *mind, *moved, *swaps;
 
26
  rpq_t *queues[2]; 
 
27
  nrinfo_t *rinfo;
 
28
  idx_t higain, oldgain, mincut, initcut, mincutorder;  
 
29
  idx_t pass, to, other, limit;
 
30
  idx_t badmaxpwgt, mindiff, newdiff;
 
31
  idx_t u[2], g[2];
 
32
  real_t mult;   
 
33
 
 
34
  WCOREPUSH;
 
35
 
 
36
  nvtxs  = graph->nvtxs;
 
37
  xadj   = graph->xadj;
 
38
  adjncy = graph->adjncy;
 
39
  vwgt   = graph->vwgt;
 
40
 
 
41
  bndind = graph->bndind;
 
42
  bndptr = graph->bndptr;
 
43
  where  = graph->where;
 
44
  pwgts  = graph->pwgts;
 
45
  rinfo  = graph->nrinfo;
 
46
 
 
47
  queues[0] = rpqCreate(nvtxs);
 
48
  queues[1] = rpqCreate(nvtxs);
 
49
 
 
50
  moved = iwspacemalloc(ctrl, nvtxs);
 
51
  swaps = iwspacemalloc(ctrl, nvtxs);
 
52
  mptr  = iwspacemalloc(ctrl, nvtxs+1);
 
53
  mind  = iwspacemalloc(ctrl, 2*nvtxs);
 
54
 
 
55
  mult = 0.5*ctrl->ubfactors[0];
 
56
  badmaxpwgt = (idx_t)(mult*(pwgts[0]+pwgts[1]+pwgts[2]));
 
57
 
 
58
  IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
 
59
    printf("Partitions-N2: [%6"PRIDX" %6"PRIDX"] Nv-Nb[%6"PRIDX" %6"PRIDX"]. ISep: %6"PRIDX"\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
 
60
 
 
61
  for (pass=0; pass<niter; pass++) {
 
62
    iset(nvtxs, -1, moved);
 
63
    rpqReset(queues[0]);
 
64
    rpqReset(queues[1]);
 
65
 
 
66
    mincutorder = -1;
 
67
    initcut = mincut = graph->mincut;
 
68
    nbnd = graph->nbnd;
 
69
 
 
70
    /* use the swaps array in place of the traditional perm array to save memory */
 
71
    irandArrayPermute(nbnd, swaps, nbnd, 1);
 
72
    for (ii=0; ii<nbnd; ii++) {
 
73
      i = bndind[swaps[ii]];
 
74
      ASSERT(where[i] == 2);
 
75
      rpqInsert(queues[0], i, vwgt[i]-rinfo[i].edegrees[1]);
 
76
      rpqInsert(queues[1], i, vwgt[i]-rinfo[i].edegrees[0]);
 
77
    }
 
78
 
 
79
    ASSERT(CheckNodeBnd(graph, nbnd));
 
80
    ASSERT(CheckNodePartitionParams(graph));
 
81
 
 
82
    limit = (ctrl->compress ? gk_min(5*nbnd, 400) : gk_min(2*nbnd, 300));
 
83
 
 
84
    /******************************************************
 
85
    * Get into the FM loop
 
86
    *******************************************************/
 
87
    mptr[0] = nmind = 0;
 
88
    mindiff = iabs(pwgts[0]-pwgts[1]);
 
89
    to = (pwgts[0] < pwgts[1] ? 0 : 1);
 
90
    for (nswaps=0; nswaps<nvtxs; nswaps++) {
 
91
      u[0] = rpqSeeTopVal(queues[0]);  
 
92
      u[1] = rpqSeeTopVal(queues[1]);
 
93
      if (u[0] != -1 && u[1] != -1) {
 
94
        g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
 
95
        g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
 
96
 
 
97
        to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2)); 
 
98
 
 
99
        if (pwgts[to]+vwgt[u[to]] > badmaxpwgt) 
 
100
          to = (to+1)%2;
 
101
      }
 
102
      else if (u[0] == -1 && u[1] == -1) {
 
103
        break;
 
104
      }
 
105
      else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) {
 
106
        to = 0;
 
107
      }
 
108
      else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) {
 
109
        to = 1;
 
110
      }
 
111
      else
 
112
        break;
 
113
 
 
114
      other = (to+1)%2;
 
115
 
 
116
      higain = rpqGetTop(queues[to]);
 
117
      if (moved[higain] == -1) /* Delete if it was in the separator originally */
 
118
        rpqDelete(queues[other], higain);
 
119
 
 
120
      ASSERT(bndptr[higain] != -1);
 
121
 
 
122
      /* The following check is to ensure we break out if there is a posibility
 
123
         of over-running the mind array.  */
 
124
      if (nmind + xadj[higain+1]-xadj[higain] >= 2*nvtxs-1) 
 
125
        break;
 
126
 
 
127
      pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
 
128
 
 
129
      newdiff = iabs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
 
130
      if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
 
131
        mincut = pwgts[2];
 
132
        mincutorder = nswaps;
 
133
        mindiff = newdiff;
 
134
      }
 
135
      else {
 
136
        if (nswaps - mincutorder > 2*limit || 
 
137
            (nswaps - mincutorder > limit && pwgts[2] > 1.10*mincut)) {
 
138
          pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
 
139
          break; /* No further improvement, break out */
 
140
        }
 
141
      }
 
142
 
 
143
      BNDDelete(nbnd, bndind, bndptr, higain);
 
144
      pwgts[to] += vwgt[higain];
 
145
      where[higain] = to;
 
146
      moved[higain] = nswaps;
 
147
      swaps[nswaps] = higain;  
 
148
 
 
149
 
 
150
      /**********************************************************
 
151
      * Update the degrees of the affected nodes
 
152
      ***********************************************************/
 
153
      for (j=xadj[higain]; j<xadj[higain+1]; j++) {
 
154
        k = adjncy[j];
 
155
        if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
 
156
          oldgain = vwgt[k]-rinfo[k].edegrees[to];
 
157
          rinfo[k].edegrees[to] += vwgt[higain];
 
158
          if (moved[k] == -1 || moved[k] == -(2+other))
 
159
            rpqUpdate(queues[other], k, oldgain-vwgt[higain]);
 
160
        }
 
161
        else if (where[k] == other) { /* This vertex is pulled into the separator */
 
162
          ASSERTP(bndptr[k] == -1, ("%"PRIDX" %"PRIDX" %"PRIDX"\n", k, bndptr[k], where[k]));
 
163
          BNDInsert(nbnd, bndind, bndptr, k);
 
164
 
 
165
          mind[nmind++] = k;  /* Keep track for rollback */
 
166
          where[k] = 2;
 
167
          pwgts[other] -= vwgt[k];
 
168
 
 
169
          edegrees = rinfo[k].edegrees;
 
170
          edegrees[0] = edegrees[1] = 0;
 
171
          for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
 
172
            kk = adjncy[jj];
 
173
            if (where[kk] != 2) 
 
174
              edegrees[where[kk]] += vwgt[kk];
 
175
            else {
 
176
              oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
 
177
              rinfo[kk].edegrees[other] -= vwgt[k];
 
178
              if (moved[kk] == -1 || moved[kk] == -(2+to))
 
179
                rpqUpdate(queues[to], kk, oldgain+vwgt[k]);
 
180
            }
 
181
          }
 
182
 
 
183
          /* Insert the new vertex into the priority queue. Only one side! */
 
184
          if (moved[k] == -1) {
 
185
            rpqInsert(queues[to], k, vwgt[k]-edegrees[other]);
 
186
            moved[k] = -(2+to);
 
187
          }
 
188
        }
 
189
      }
 
190
      mptr[nswaps+1] = nmind;
 
191
 
 
192
      IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
 
193
            printf("Moved %6"PRIDX" to %3"PRIDX", Gain: %5"PRIDX" [%5"PRIDX"] [%4"PRIDX" %4"PRIDX"] \t[%5"PRIDX" %5"PRIDX" %5"PRIDX"]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
 
194
 
 
195
    }
 
196
 
 
197
 
 
198
    /****************************************************************
 
199
    * Roll back computation 
 
200
    *****************************************************************/
 
201
    for (nswaps--; nswaps>mincutorder; nswaps--) {
 
202
      higain = swaps[nswaps];
 
203
 
 
204
      ASSERT(CheckNodePartitionParams(graph));
 
205
 
 
206
      to = where[higain];
 
207
      other = (to+1)%2;
 
208
      INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
 
209
      where[higain] = 2;
 
210
      BNDInsert(nbnd, bndind, bndptr, higain);
 
211
 
 
212
      edegrees = rinfo[higain].edegrees;
 
213
      edegrees[0] = edegrees[1] = 0;
 
214
      for (j=xadj[higain]; j<xadj[higain+1]; j++) {
 
215
        k = adjncy[j];
 
216
        if (where[k] == 2) 
 
217
          rinfo[k].edegrees[to] -= vwgt[higain];
 
218
        else
 
219
          edegrees[where[k]] += vwgt[k];
 
220
      }
 
221
 
 
222
      /* Push nodes out of the separator */
 
223
      for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
 
224
        k = mind[j];
 
225
        ASSERT(where[k] == 2);
 
226
        where[k] = other;
 
227
        INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
 
228
        BNDDelete(nbnd, bndind, bndptr, k);
 
229
        for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
 
230
          kk = adjncy[jj];
 
231
          if (where[kk] == 2) 
 
232
            rinfo[kk].edegrees[other] += vwgt[k];
 
233
        }
 
234
      }
 
235
    }
 
236
 
 
237
    ASSERT(mincut == pwgts[2]);
 
238
 
 
239
    IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
 
240
      printf("\tMinimum sep: %6"PRIDX" at %5"PRIDX", PWGTS: [%6"PRIDX" %6"PRIDX"], NBND: %6"PRIDX"\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
 
241
 
 
242
    graph->mincut = mincut;
 
243
    graph->nbnd = nbnd;
 
244
 
 
245
    if (mincutorder == -1 || mincut >= initcut)
 
246
      break;
 
247
  }
 
248
 
 
249
  rpqDestroy(queues[0]);
 
250
  rpqDestroy(queues[1]);
 
251
 
 
252
  WCOREPOP;
 
253
}
 
254
 
 
255
 
 
256
/*************************************************************************/
 
257
/*! This function performs a node-based FM refinement. 
 
258
    Each refinement iteration is split into two sub-iterations. 
 
259
    In each sub-iteration only moves to one of the left/right partitions 
 
260
    is allowed; hence, it is one-sided. 
 
261
*/
 
262
/**************************************************************************/
 
263
void FM_2WayNodeRefine1Sided(ctrl_t *ctrl, graph_t *graph, idx_t niter)
 
264
{
 
265
  idx_t i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind, iend;
 
266
  idx_t *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
 
267
  idx_t *mptr, *mind, *swaps;
 
268
  rpq_t *queue; 
 
269
  nrinfo_t *rinfo;
 
270
  idx_t higain, mincut, initcut, mincutorder;   
 
271
  idx_t pass, to, other, limit;
 
272
  idx_t badmaxpwgt, mindiff, newdiff;
 
273
  real_t mult;
 
274
 
 
275
  WCOREPUSH;
 
276
 
 
277
  nvtxs  = graph->nvtxs;
 
278
  xadj   = graph->xadj;
 
279
  adjncy = graph->adjncy;
 
280
  vwgt   = graph->vwgt;
 
281
 
 
282
  bndind = graph->bndind;
 
283
  bndptr = graph->bndptr;
 
284
  where  = graph->where;
 
285
  pwgts  = graph->pwgts;
 
286
  rinfo  = graph->nrinfo;
 
287
 
 
288
  queue = rpqCreate(nvtxs);
 
289
 
 
290
  swaps = iwspacemalloc(ctrl, nvtxs);
 
291
  mptr  = iwspacemalloc(ctrl, nvtxs+1);
 
292
  mind  = iwspacemalloc(ctrl, 2*nvtxs);
 
293
 
 
294
  mult = 0.5*ctrl->ubfactors[0];
 
295
  badmaxpwgt = (idx_t)(mult*(pwgts[0]+pwgts[1]+pwgts[2]));
 
296
 
 
297
  IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
 
298
    printf("Partitions-N1: [%6"PRIDX" %6"PRIDX"] Nv-Nb[%6"PRIDX" %6"PRIDX"]. ISep: %6"PRIDX"\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
 
299
 
 
300
  to = (pwgts[0] < pwgts[1] ? 1 : 0);
 
301
  for (pass=0; pass<2*niter; pass++) {  /* the 2*niter is for the two sides */
 
302
    other = to; 
 
303
    to    = (to+1)%2;
 
304
 
 
305
    rpqReset(queue);
 
306
 
 
307
    mincutorder = -1;
 
308
    initcut = mincut = graph->mincut;
 
309
    nbnd = graph->nbnd;
 
310
 
 
311
    /* use the swaps array in place of the traditional perm array to save memory */
 
312
    irandArrayPermute(nbnd, swaps, nbnd, 1);
 
313
    for (ii=0; ii<nbnd; ii++) {
 
314
      i = bndind[swaps[ii]];
 
315
      ASSERT(where[i] == 2);
 
316
      rpqInsert(queue, i, vwgt[i]-rinfo[i].edegrees[other]);
 
317
    }
 
318
 
 
319
    ASSERT(CheckNodeBnd(graph, nbnd));
 
320
    ASSERT(CheckNodePartitionParams(graph));
 
321
 
 
322
    limit = (ctrl->compress ? gk_min(5*nbnd, 500) : gk_min(3*nbnd, 300));
 
323
 
 
324
    /******************************************************
 
325
    * Get into the FM loop
 
326
    *******************************************************/
 
327
    IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->Aux3Tmr));
 
328
    mptr[0] = nmind = 0;
 
329
    mindiff = iabs(pwgts[0]-pwgts[1]);
 
330
    for (nswaps=0; nswaps<nvtxs; nswaps++) {
 
331
      if ((higain = rpqGetTop(queue)) == -1)
 
332
        break;
 
333
 
 
334
      ASSERT(bndptr[higain] != -1);
 
335
 
 
336
      /* The following check is to ensure we break out if there is a posibility
 
337
         of over-running the mind array.  */
 
338
      if (nmind + xadj[higain+1]-xadj[higain] >= 2*nvtxs-1) 
 
339
        break;
 
340
 
 
341
      if (pwgts[to]+vwgt[higain] > badmaxpwgt) 
 
342
        break;  /* No point going any further. Balance will be bad */
 
343
 
 
344
      pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
 
345
 
 
346
      newdiff = iabs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
 
347
      if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
 
348
        mincut      = pwgts[2];
 
349
        mincutorder = nswaps;
 
350
        mindiff     = newdiff;
 
351
      }
 
352
      else {
 
353
        if (nswaps - mincutorder > 3*limit || 
 
354
            (nswaps - mincutorder > limit && pwgts[2] > 1.10*mincut)) {
 
355
          pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
 
356
          break; /* No further improvement, break out */
 
357
        }
 
358
      }
 
359
 
 
360
      BNDDelete(nbnd, bndind, bndptr, higain);
 
361
      pwgts[to]     += vwgt[higain];
 
362
      where[higain]  = to;
 
363
      swaps[nswaps]  = higain;  
 
364
 
 
365
 
 
366
      /**********************************************************
 
367
      * Update the degrees of the affected nodes
 
368
      ***********************************************************/
 
369
      IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->Aux1Tmr));
 
370
      for (j=xadj[higain]; j<xadj[higain+1]; j++) {
 
371
        k = adjncy[j];
 
372
 
 
373
        if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
 
374
          rinfo[k].edegrees[to] += vwgt[higain];
 
375
        }
 
376
        else if (where[k] == other) { /* This vertex is pulled into the separator */
 
377
          ASSERTP(bndptr[k] == -1, ("%"PRIDX" %"PRIDX" %"PRIDX"\n", k, bndptr[k], where[k]));
 
378
          BNDInsert(nbnd, bndind, bndptr, k);
 
379
 
 
380
          mind[nmind++] = k;  /* Keep track for rollback */
 
381
          where[k] = 2;
 
382
          pwgts[other] -= vwgt[k];
 
383
 
 
384
          edegrees = rinfo[k].edegrees;
 
385
          edegrees[0] = edegrees[1] = 0;
 
386
          for (jj=xadj[k], iend=xadj[k+1]; jj<iend; jj++) {
 
387
            kk = adjncy[jj];
 
388
            if (where[kk] != 2) 
 
389
              edegrees[where[kk]] += vwgt[kk];
 
390
            else {
 
391
              rinfo[kk].edegrees[other] -= vwgt[k];
 
392
 
 
393
              /* Since the moves are one-sided this vertex has not been moved yet */
 
394
              rpqUpdate(queue, kk, vwgt[kk]-rinfo[kk].edegrees[other]); 
 
395
            }
 
396
          }
 
397
 
 
398
          /* Insert the new vertex into the priority queue. Safe due to one-sided moves */
 
399
          rpqInsert(queue, k, vwgt[k]-edegrees[other]);
 
400
        }
 
401
      }
 
402
      mptr[nswaps+1] = nmind;
 
403
      IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux1Tmr));
 
404
 
 
405
 
 
406
      IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
 
407
            printf("Moved %6"PRIDX" to %3"PRIDX", Gain: %5"PRIDX" [%5"PRIDX"] \t[%5"PRIDX" %5"PRIDX" %5"PRIDX"] [%3"PRIDX" %2"PRIDX"]\n", 
 
408
                higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], 
 
409
                pwgts[0], pwgts[1], pwgts[2], nswaps, limit));
 
410
    }
 
411
    IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux3Tmr));
 
412
 
 
413
 
 
414
    /****************************************************************
 
415
    * Roll back computation 
 
416
    *****************************************************************/
 
417
    IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->Aux2Tmr));
 
418
    for (nswaps--; nswaps>mincutorder; nswaps--) {
 
419
      higain = swaps[nswaps];
 
420
 
 
421
      ASSERT(CheckNodePartitionParams(graph));
 
422
      ASSERT(where[higain] == to);
 
423
 
 
424
      INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
 
425
      where[higain] = 2;
 
426
      BNDInsert(nbnd, bndind, bndptr, higain);
 
427
 
 
428
      edegrees = rinfo[higain].edegrees;
 
429
      edegrees[0] = edegrees[1] = 0;
 
430
      for (j=xadj[higain]; j<xadj[higain+1]; j++) {
 
431
        k = adjncy[j];
 
432
        if (where[k] == 2) 
 
433
          rinfo[k].edegrees[to] -= vwgt[higain];
 
434
        else
 
435
          edegrees[where[k]] += vwgt[k];
 
436
      }
 
437
 
 
438
      /* Push nodes out of the separator */
 
439
      for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
 
440
        k = mind[j];
 
441
        ASSERT(where[k] == 2);
 
442
        where[k] = other;
 
443
        INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
 
444
        BNDDelete(nbnd, bndind, bndptr, k);
 
445
        for (jj=xadj[k], iend=xadj[k+1]; jj<iend; jj++) {
 
446
          kk = adjncy[jj];
 
447
          if (where[kk] == 2) 
 
448
            rinfo[kk].edegrees[other] += vwgt[k];
 
449
        }
 
450
      }
 
451
    }
 
452
    IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux2Tmr));
 
453
 
 
454
    ASSERT(mincut == pwgts[2]);
 
455
 
 
456
    IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
 
457
      printf("\tMinimum sep: %6"PRIDX" at %5"PRIDX", PWGTS: [%6"PRIDX" %6"PRIDX"], NBND: %6"PRIDX"\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
 
458
 
 
459
    graph->mincut = mincut;
 
460
    graph->nbnd   = nbnd;
 
461
 
 
462
    if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut))
 
463
      break;
 
464
  }
 
465
 
 
466
  rpqDestroy(queue);
 
467
 
 
468
  WCOREPOP;
 
469
}
 
470
 
 
471
 
 
472
/*************************************************************************/
 
473
/*! This function balances the left/right partitions of a separator 
 
474
    tri-section */
 
475
/*************************************************************************/
 
476
void FM_2WayNodeBalance(ctrl_t *ctrl, graph_t *graph)
 
477
{
 
478
  idx_t i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, gain;
 
479
  idx_t badmaxpwgt, higain, oldgain, pass, to, other;
 
480
  idx_t *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
 
481
  idx_t *perm, *moved;
 
482
  rpq_t *queue; 
 
483
  nrinfo_t *rinfo;
 
484
  real_t mult;
 
485
 
 
486
  nvtxs  = graph->nvtxs;
 
487
  xadj   = graph->xadj;
 
488
  adjncy = graph->adjncy;
 
489
  vwgt   = graph->vwgt;
 
490
 
 
491
  bndind = graph->bndind;
 
492
  bndptr = graph->bndptr;
 
493
  where  = graph->where;
 
494
  pwgts  = graph->pwgts;
 
495
  rinfo  = graph->nrinfo;
 
496
 
 
497
  mult = 0.5*ctrl->ubfactors[0];
 
498
 
 
499
  badmaxpwgt = (idx_t)(mult*(pwgts[0]+pwgts[1]));
 
500
  if (gk_max(pwgts[0], pwgts[1]) < badmaxpwgt)
 
501
    return;
 
502
  if (iabs(pwgts[0]-pwgts[1]) < 3*graph->tvwgt[0]/nvtxs)
 
503
    return;
 
504
 
 
505
  WCOREPUSH;
 
506
 
 
507
  to    = (pwgts[0] < pwgts[1] ? 0 : 1); 
 
508
  other = (to+1)%2;
 
509
 
 
510
  queue = rpqCreate(nvtxs);
 
511
 
 
512
  perm  = iwspacemalloc(ctrl, nvtxs);
 
513
  moved = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs));
 
514
 
 
515
  IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
 
516
    printf("Partitions: [%6"PRIDX" %6"PRIDX"] Nv-Nb[%6"PRIDX" %6"PRIDX"]. ISep: %6"PRIDX" [B]\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
 
517
 
 
518
  nbnd = graph->nbnd;
 
519
  irandArrayPermute(nbnd, perm, nbnd, 1);
 
520
  for (ii=0; ii<nbnd; ii++) {
 
521
    i = bndind[perm[ii]];
 
522
    ASSERT(where[i] == 2);
 
523
    rpqInsert(queue, i, vwgt[i]-rinfo[i].edegrees[other]);
 
524
  }
 
525
 
 
526
  ASSERT(CheckNodeBnd(graph, nbnd));
 
527
  ASSERT(CheckNodePartitionParams(graph));
 
528
 
 
529
  /******************************************************
 
530
  * Get into the FM loop
 
531
  *******************************************************/
 
532
  for (nswaps=0; nswaps<nvtxs; nswaps++) {
 
533
    if ((higain = rpqGetTop(queue)) == -1)
 
534
      break;
 
535
 
 
536
    moved[higain] = 1;
 
537
 
 
538
    gain = vwgt[higain]-rinfo[higain].edegrees[other];
 
539
    badmaxpwgt = (idx_t)(mult*(pwgts[0]+pwgts[1]));
 
540
 
 
541
    /* break if other is now underwight */
 
542
    if (pwgts[to] > pwgts[other])
 
543
      break;
 
544
 
 
545
    /* break if balance is achieved and no +ve or zero gain */
 
546
    if (gain < 0 && pwgts[other] < badmaxpwgt) 
 
547
      break;
 
548
 
 
549
    /* skip this vertex if it will violate balance on the other side */
 
550
    if (pwgts[to]+vwgt[higain] > badmaxpwgt) 
 
551
      continue;
 
552
 
 
553
    ASSERT(bndptr[higain] != -1);
 
554
 
 
555
    pwgts[2] -= gain;
 
556
 
 
557
    BNDDelete(nbnd, bndind, bndptr, higain);
 
558
    pwgts[to] += vwgt[higain];
 
559
    where[higain] = to;
 
560
 
 
561
    IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
 
562
          printf("Moved %6"PRIDX" to %3"PRIDX", Gain: %3"PRIDX", \t[%5"PRIDX" %5"PRIDX" %5"PRIDX"]\n", higain, to, vwgt[higain]-rinfo[higain].edegrees[other], pwgts[0], pwgts[1], pwgts[2]));
 
563
 
 
564
 
 
565
    /**********************************************************
 
566
    * Update the degrees of the affected nodes
 
567
    ***********************************************************/
 
568
    for (j=xadj[higain]; j<xadj[higain+1]; j++) {
 
569
      k = adjncy[j];
 
570
      if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
 
571
        rinfo[k].edegrees[to] += vwgt[higain];
 
572
      }
 
573
      else if (where[k] == other) { /* This vertex is pulled into the separator */
 
574
        ASSERTP(bndptr[k] == -1, ("%"PRIDX" %"PRIDX" %"PRIDX"\n", k, bndptr[k], where[k]));
 
575
        BNDInsert(nbnd, bndind, bndptr, k);
 
576
 
 
577
        where[k] = 2;
 
578
        pwgts[other] -= vwgt[k];
 
579
 
 
580
        edegrees = rinfo[k].edegrees;
 
581
        edegrees[0] = edegrees[1] = 0;
 
582
        for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
 
583
          kk = adjncy[jj];
 
584
          if (where[kk] != 2) 
 
585
            edegrees[where[kk]] += vwgt[kk];
 
586
          else {
 
587
            ASSERT(bndptr[kk] != -1);
 
588
            oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
 
589
            rinfo[kk].edegrees[other] -= vwgt[k];
 
590
 
 
591
            if (moved[kk] == -1)
 
592
              rpqUpdate(queue, kk, oldgain+vwgt[k]);
 
593
          }
 
594
        }
 
595
 
 
596
        /* Insert the new vertex into the priority queue */
 
597
        rpqInsert(queue, k, vwgt[k]-edegrees[other]);
 
598
      }
 
599
    }
 
600
  }
 
601
 
 
602
  IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
 
603
    printf("\tBalanced sep: %6"PRIDX" at %4"PRIDX", PWGTS: [%6"PRIDX" %6"PRIDX"], NBND: %6"PRIDX"\n", pwgts[2], nswaps, pwgts[0], pwgts[1], nbnd));
 
604
 
 
605
  graph->mincut = pwgts[2];
 
606
  graph->nbnd   = nbnd;
 
607
 
 
608
  rpqDestroy(queue);
 
609
 
 
610
  WCOREPOP;
 
611
}
 
612