Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/fm.c
3206 views
1
/*!
2
\file
3
\brief Functions for the edge-based FM refinement
4
5
\date Started 7/23/97
6
\author George
7
\author Copyright 1997-2011, Regents of the University of Minnesota
8
\version\verbatim $Id: fm.c 10187 2011-06-13 13:46:57Z karypis $ \endverbatim
9
*/
10
11
#include "metislib.h"
12
13
14
/*************************************************************************
15
* This function performs an edge-based FM refinement
16
**************************************************************************/
17
void FM_2WayRefine(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niter)
18
{
19
if (graph->ncon == 1)
20
FM_2WayCutRefine(ctrl, graph, ntpwgts, niter);
21
else
22
FM_Mc2WayCutRefine(ctrl, graph, ntpwgts, niter);
23
}
24
25
26
/*************************************************************************/
27
/*! This function performs a cut-focused FM refinement */
28
/*************************************************************************/
29
void FM_2WayCutRefine(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niter)
30
{
31
idx_t i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, me, limit, tmp;
32
idx_t *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
33
idx_t *moved, *swaps, *perm;
34
rpq_t *queues[2];
35
idx_t higain, mincut, mindiff, origdiff, initcut, newcut, mincutorder, avgvwgt;
36
idx_t tpwgts[2];
37
38
WCOREPUSH;
39
40
nvtxs = graph->nvtxs;
41
xadj = graph->xadj;
42
vwgt = graph->vwgt;
43
adjncy = graph->adjncy;
44
adjwgt = graph->adjwgt;
45
where = graph->where;
46
id = graph->id;
47
ed = graph->ed;
48
pwgts = graph->pwgts;
49
bndptr = graph->bndptr;
50
bndind = graph->bndind;
51
52
moved = iwspacemalloc(ctrl, nvtxs);
53
swaps = iwspacemalloc(ctrl, nvtxs);
54
perm = iwspacemalloc(ctrl, nvtxs);
55
56
tpwgts[0] = graph->tvwgt[0]*ntpwgts[0];
57
tpwgts[1] = graph->tvwgt[0]-tpwgts[0];
58
59
limit = gk_min(gk_max(0.01*nvtxs, 15), 100);
60
avgvwgt = gk_min((pwgts[0]+pwgts[1])/20, 2*(pwgts[0]+pwgts[1])/nvtxs);
61
62
queues[0] = rpqCreate(nvtxs);
63
queues[1] = rpqCreate(nvtxs);
64
65
IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
66
Print2WayRefineStats(ctrl, graph, ntpwgts, 0, -2));
67
68
origdiff = iabs(tpwgts[0]-pwgts[0]);
69
iset(nvtxs, -1, moved);
70
for (pass=0; pass<niter; pass++) { /* Do a number of passes */
71
rpqReset(queues[0]);
72
rpqReset(queues[1]);
73
74
mincutorder = -1;
75
newcut = mincut = initcut = graph->mincut;
76
mindiff = iabs(tpwgts[0]-pwgts[0]);
77
78
ASSERT(ComputeCut(graph, where) == graph->mincut);
79
ASSERT(CheckBnd(graph));
80
81
/* Insert boundary nodes in the priority queues */
82
nbnd = graph->nbnd;
83
irandArrayPermute(nbnd, perm, nbnd, 1);
84
for (ii=0; ii<nbnd; ii++) {
85
i = perm[ii];
86
ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0);
87
ASSERT(bndptr[bndind[i]] != -1);
88
rpqInsert(queues[where[bndind[i]]], bndind[i], ed[bndind[i]]-id[bndind[i]]);
89
}
90
91
for (nswaps=0; nswaps<nvtxs; nswaps++) {
92
from = (tpwgts[0]-pwgts[0] < tpwgts[1]-pwgts[1] ? 0 : 1);
93
to = (from+1)%2;
94
95
if ((higain = rpqGetTop(queues[from])) == -1)
96
break;
97
ASSERT(bndptr[higain] != -1);
98
99
newcut -= (ed[higain]-id[higain]);
100
INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
101
102
if ((newcut < mincut && iabs(tpwgts[0]-pwgts[0]) <= origdiff+avgvwgt) ||
103
(newcut == mincut && iabs(tpwgts[0]-pwgts[0]) < mindiff)) {
104
mincut = newcut;
105
mindiff = iabs(tpwgts[0]-pwgts[0]);
106
mincutorder = nswaps;
107
}
108
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
109
newcut += (ed[higain]-id[higain]);
110
INC_DEC(pwgts[from], pwgts[to], vwgt[higain]);
111
break;
112
}
113
114
where[higain] = to;
115
moved[higain] = nswaps;
116
swaps[nswaps] = higain;
117
118
IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO,
119
printf("Moved %6"PRIDX" from %"PRIDX". [%3"PRIDX" %3"PRIDX"] %5"PRIDX" [%4"PRIDX" %4"PRIDX"]\n", higain, from, ed[higain]-id[higain], vwgt[higain], newcut, pwgts[0], pwgts[1]));
120
121
/**************************************************************
122
* Update the id[i]/ed[i] values of the affected nodes
123
***************************************************************/
124
SWAP(id[higain], ed[higain], tmp);
125
if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
126
BNDDelete(nbnd, bndind, bndptr, higain);
127
128
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
129
k = adjncy[j];
130
131
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
132
INC_DEC(id[k], ed[k], kwgt);
133
134
/* Update its boundary information and queue position */
135
if (bndptr[k] != -1) { /* If k was a boundary vertex */
136
if (ed[k] == 0) { /* Not a boundary vertex any more */
137
BNDDelete(nbnd, bndind, bndptr, k);
138
if (moved[k] == -1) /* Remove it if in the queues */
139
rpqDelete(queues[where[k]], k);
140
}
141
else { /* If it has not been moved, update its position in the queue */
142
if (moved[k] == -1)
143
rpqUpdate(queues[where[k]], k, ed[k]-id[k]);
144
}
145
}
146
else {
147
if (ed[k] > 0) { /* It will now become a boundary vertex */
148
BNDInsert(nbnd, bndind, bndptr, k);
149
if (moved[k] == -1)
150
rpqInsert(queues[where[k]], k, ed[k]-id[k]);
151
}
152
}
153
}
154
155
}
156
157
158
/****************************************************************
159
* Roll back computations
160
*****************************************************************/
161
for (i=0; i<nswaps; i++)
162
moved[swaps[i]] = -1; /* reset moved array */
163
for (nswaps--; nswaps>mincutorder; nswaps--) {
164
higain = swaps[nswaps];
165
166
to = where[higain] = (where[higain]+1)%2;
167
SWAP(id[higain], ed[higain], tmp);
168
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
169
BNDDelete(nbnd, bndind, bndptr, higain);
170
else if (ed[higain] > 0 && bndptr[higain] == -1)
171
BNDInsert(nbnd, bndind, bndptr, higain);
172
173
INC_DEC(pwgts[to], pwgts[(to+1)%2], vwgt[higain]);
174
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
175
k = adjncy[j];
176
177
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
178
INC_DEC(id[k], ed[k], kwgt);
179
180
if (bndptr[k] != -1 && ed[k] == 0)
181
BNDDelete(nbnd, bndind, bndptr, k);
182
if (bndptr[k] == -1 && ed[k] > 0)
183
BNDInsert(nbnd, bndind, bndptr, k);
184
}
185
}
186
187
graph->mincut = mincut;
188
graph->nbnd = nbnd;
189
190
IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
191
Print2WayRefineStats(ctrl, graph, ntpwgts, 0, mincutorder));
192
193
if (mincutorder <= 0 || mincut == initcut)
194
break;
195
}
196
197
rpqDestroy(queues[0]);
198
rpqDestroy(queues[1]);
199
200
WCOREPOP;
201
}
202
203
204
/*************************************************************************/
205
/*! This function performs a cut-focused multi-constraint FM refinement */
206
/*************************************************************************/
207
void FM_Mc2WayCutRefine(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t niter)
208
{
209
idx_t i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass,
210
me, limit, tmp, cnum;
211
idx_t *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *id, *ed,
212
*bndptr, *bndind;
213
idx_t *moved, *swaps, *perm, *qnum;
214
idx_t higain, mincut, initcut, newcut, mincutorder;
215
real_t *invtvwgt, *ubfactors, *minbalv, *newbalv;
216
real_t origbal, minbal, newbal, rgain, ffactor;
217
rpq_t **queues;
218
219
WCOREPUSH;
220
221
nvtxs = graph->nvtxs;
222
ncon = graph->ncon;
223
xadj = graph->xadj;
224
vwgt = graph->vwgt;
225
adjncy = graph->adjncy;
226
adjwgt = graph->adjwgt;
227
invtvwgt = graph->invtvwgt;
228
where = graph->where;
229
id = graph->id;
230
ed = graph->ed;
231
pwgts = graph->pwgts;
232
bndptr = graph->bndptr;
233
bndind = graph->bndind;
234
235
moved = iwspacemalloc(ctrl, nvtxs);
236
swaps = iwspacemalloc(ctrl, nvtxs);
237
perm = iwspacemalloc(ctrl, nvtxs);
238
qnum = iwspacemalloc(ctrl, nvtxs);
239
ubfactors = rwspacemalloc(ctrl, ncon);
240
newbalv = rwspacemalloc(ctrl, ncon);
241
minbalv = rwspacemalloc(ctrl, ncon);
242
243
limit = gk_min(gk_max(0.01*nvtxs, 25), 150);
244
245
246
/* Determine a fudge factor to allow the refinement routines to get out
247
of tight balancing constraints. */
248
ffactor = .5/gk_max(20, nvtxs);
249
250
/* Initialize the queues */
251
queues = (rpq_t **)wspacemalloc(ctrl, 2*ncon*sizeof(rpq_t *));
252
for (i=0; i<2*ncon; i++)
253
queues[i] = rpqCreate(nvtxs);
254
for (i=0; i<nvtxs; i++)
255
qnum[i] = iargmax_nrm(ncon, vwgt+i*ncon, invtvwgt);
256
257
/* Determine the unbalance tolerance for each constraint. The tolerance is
258
equal to the maximum of the original load imbalance and the user-supplied
259
allowed tolerance. The rationale behind this approach is to allow the
260
refinement routine to improve the cut, without having to worry about fixing
261
load imbalance problems. The load imbalance is addressed by the balancing
262
routines. */
263
origbal = ComputeLoadImbalanceDiffVec(graph, 2, ctrl->pijbm, ctrl->ubfactors, ubfactors);
264
for (i=0; i<ncon; i++)
265
ubfactors[i] = (ubfactors[i] > 0 ? ctrl->ubfactors[i]+ubfactors[i] : ctrl->ubfactors[i]);
266
267
268
IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
269
Print2WayRefineStats(ctrl, graph, ntpwgts, origbal, -2));
270
271
iset(nvtxs, -1, moved);
272
for (pass=0; pass<niter; pass++) { /* Do a number of passes */
273
for (i=0; i<2*ncon; i++)
274
rpqReset(queues[i]);
275
276
mincutorder = -1;
277
newcut = mincut = initcut = graph->mincut;
278
279
minbal = ComputeLoadImbalanceDiffVec(graph, 2, ctrl->pijbm, ubfactors, minbalv);
280
281
ASSERT(ComputeCut(graph, where) == graph->mincut);
282
ASSERT(CheckBnd(graph));
283
284
/* Insert boundary nodes in the priority queues */
285
nbnd = graph->nbnd;
286
irandArrayPermute(nbnd, perm, nbnd/5, 1);
287
for (ii=0; ii<nbnd; ii++) {
288
i = bndind[perm[ii]];
289
ASSERT(ed[i] > 0 || id[i] == 0);
290
ASSERT(bndptr[i] != -1);
291
//rgain = 1.0*(ed[i]-id[i])/sqrt(vwgt[i*ncon+qnum[i]]+1);
292
//rgain = (ed[i]-id[i] > 0 ? 1.0*(ed[i]-id[i])/sqrt(vwgt[i*ncon+qnum[i]]+1) : ed[i]-id[i]);
293
rgain = ed[i]-id[i];
294
rpqInsert(queues[2*qnum[i]+where[i]], i, rgain);
295
}
296
297
for (nswaps=0; nswaps<nvtxs; nswaps++) {
298
SelectQueue(graph, ctrl->pijbm, ubfactors, queues, &from, &cnum);
299
300
to = (from+1)%2;
301
302
if (from == -1 || (higain = rpqGetTop(queues[2*cnum+from])) == -1)
303
break;
304
ASSERT(bndptr[higain] != -1);
305
306
newcut -= (ed[higain]-id[higain]);
307
308
iaxpy(ncon, 1, vwgt+higain*ncon, 1, pwgts+to*ncon, 1);
309
iaxpy(ncon, -1, vwgt+higain*ncon, 1, pwgts+from*ncon, 1);
310
newbal = ComputeLoadImbalanceDiffVec(graph, 2, ctrl->pijbm, ubfactors, newbalv);
311
312
if ((newcut < mincut && newbal <= ffactor) ||
313
(newcut == mincut && (newbal < minbal ||
314
(newbal == minbal && BetterBalance2Way(ncon, minbalv, newbalv))))) {
315
mincut = newcut;
316
minbal = newbal;
317
mincutorder = nswaps;
318
rcopy(ncon, newbalv, minbalv);
319
}
320
else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
321
newcut += (ed[higain]-id[higain]);
322
iaxpy(ncon, 1, vwgt+higain*ncon, 1, pwgts+from*ncon, 1);
323
iaxpy(ncon, -1, vwgt+higain*ncon, 1, pwgts+to*ncon, 1);
324
break;
325
}
326
327
where[higain] = to;
328
moved[higain] = nswaps;
329
swaps[nswaps] = higain;
330
331
if (ctrl->dbglvl&METIS_DBG_MOVEINFO) {
332
printf("Moved%6"PRIDX" from %"PRIDX"(%"PRIDX") Gain:%5"PRIDX", "
333
"Cut:%5"PRIDX", NPwgts:", higain, from, cnum, ed[higain]-id[higain], newcut);
334
for (l=0; l<ncon; l++)
335
printf("(%.3"PRREAL" %.3"PRREAL")", pwgts[l]*invtvwgt[l], pwgts[ncon+l]*invtvwgt[l]);
336
printf(" %+.3"PRREAL" LB: %.3"PRREAL"(%+.3"PRREAL")\n",
337
minbal, ComputeLoadImbalance(graph, 2, ctrl->pijbm), newbal);
338
}
339
340
341
/**************************************************************
342
* Update the id[i]/ed[i] values of the affected nodes
343
***************************************************************/
344
SWAP(id[higain], ed[higain], tmp);
345
if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
346
BNDDelete(nbnd, bndind, bndptr, higain);
347
348
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
349
k = adjncy[j];
350
351
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
352
INC_DEC(id[k], ed[k], kwgt);
353
354
/* Update its boundary information and queue position */
355
if (bndptr[k] != -1) { /* If k was a boundary vertex */
356
if (ed[k] == 0) { /* Not a boundary vertex any more */
357
BNDDelete(nbnd, bndind, bndptr, k);
358
if (moved[k] == -1) /* Remove it if in the queues */
359
rpqDelete(queues[2*qnum[k]+where[k]], k);
360
}
361
else { /* If it has not been moved, update its position in the queue */
362
if (moved[k] == -1) {
363
//rgain = 1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1);
364
//rgain = (ed[k]-id[k] > 0 ?
365
// 1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1) : ed[k]-id[k]);
366
rgain = ed[k]-id[k];
367
rpqUpdate(queues[2*qnum[k]+where[k]], k, rgain);
368
}
369
}
370
}
371
else {
372
if (ed[k] > 0) { /* It will now become a boundary vertex */
373
BNDInsert(nbnd, bndind, bndptr, k);
374
if (moved[k] == -1) {
375
//rgain = 1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1);
376
//rgain = (ed[k]-id[k] > 0 ?
377
// 1.0*(ed[k]-id[k])/sqrt(vwgt[k*ncon+qnum[k]]+1) : ed[k]-id[k]);
378
rgain = ed[k]-id[k];
379
rpqInsert(queues[2*qnum[k]+where[k]], k, rgain);
380
}
381
}
382
}
383
}
384
385
}
386
387
388
/****************************************************************
389
* Roll back computations
390
*****************************************************************/
391
for (i=0; i<nswaps; i++)
392
moved[swaps[i]] = -1; /* reset moved array */
393
for (nswaps--; nswaps>mincutorder; nswaps--) {
394
higain = swaps[nswaps];
395
396
to = where[higain] = (where[higain]+1)%2;
397
SWAP(id[higain], ed[higain], tmp);
398
if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
399
BNDDelete(nbnd, bndind, bndptr, higain);
400
else if (ed[higain] > 0 && bndptr[higain] == -1)
401
BNDInsert(nbnd, bndind, bndptr, higain);
402
403
iaxpy(ncon, 1, vwgt+higain*ncon, 1, pwgts+to*ncon, 1);
404
iaxpy(ncon, -1, vwgt+higain*ncon, 1, pwgts+((to+1)%2)*ncon, 1);
405
for (j=xadj[higain]; j<xadj[higain+1]; j++) {
406
k = adjncy[j];
407
408
kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
409
INC_DEC(id[k], ed[k], kwgt);
410
411
if (bndptr[k] != -1 && ed[k] == 0)
412
BNDDelete(nbnd, bndind, bndptr, k);
413
if (bndptr[k] == -1 && ed[k] > 0)
414
BNDInsert(nbnd, bndind, bndptr, k);
415
}
416
}
417
418
graph->mincut = mincut;
419
graph->nbnd = nbnd;
420
421
IFSET(ctrl->dbglvl, METIS_DBG_REFINE,
422
Print2WayRefineStats(ctrl, graph, ntpwgts, minbal, mincutorder));
423
424
if (mincutorder <= 0 || mincut == initcut)
425
break;
426
}
427
428
for (i=0; i<2*ncon; i++)
429
rpqDestroy(queues[i]);
430
431
WCOREPOP;
432
}
433
434
435
/*************************************************************************/
436
/*! This function selects the partition number and the queue from which
437
we will move vertices out. */
438
/*************************************************************************/
439
void SelectQueue(graph_t *graph, real_t *pijbm, real_t *ubfactors,
440
rpq_t **queues, idx_t *from, idx_t *cnum)
441
{
442
idx_t ncon, i, part;
443
real_t max, tmp;
444
445
ncon = graph->ncon;
446
447
*from = -1;
448
*cnum = -1;
449
450
/* First determine the side and the queue, irrespective of the presence of nodes.
451
The side & queue is determined based on the most violated balancing constraint. */
452
for (max=0.0, part=0; part<2; part++) {
453
for (i=0; i<ncon; i++) {
454
tmp = graph->pwgts[part*ncon+i]*pijbm[part*ncon+i] - ubfactors[i];
455
/* the '=' in the test bellow is to ensure that under tight constraints
456
the partition that is at the max is selected */
457
if (tmp >= max) {
458
max = tmp;
459
*from = part;
460
*cnum = i;
461
}
462
}
463
}
464
465
466
if (*from != -1) {
467
/* in case the desired queue is empty, select a queue from the same side */
468
if (rpqLength(queues[2*(*cnum)+(*from)]) == 0) {
469
for (i=0; i<ncon; i++) {
470
if (rpqLength(queues[2*i+(*from)]) > 0) {
471
max = graph->pwgts[(*from)*ncon+i]*pijbm[(*from)*ncon+i] - ubfactors[i];
472
*cnum = i;
473
break;
474
}
475
}
476
477
for (i++; i<ncon; i++) {
478
tmp = graph->pwgts[(*from)*ncon+i]*pijbm[(*from)*ncon+i] - ubfactors[i];
479
if (tmp > max && rpqLength(queues[2*i+(*from)]) > 0) {
480
max = tmp;
481
*cnum = i;
482
}
483
}
484
}
485
486
/*
487
printf("Selected1 %"PRIDX"(%"PRIDX") -> %"PRIDX" [%5"PRREAL"]\n",
488
*from, *cnum, rpqLength(queues[2*(*cnum)+(*from)]), max);
489
*/
490
}
491
else {
492
/* the partitioning does not violate balancing constraints, in which case select
493
a queue based on cut criteria */
494
for (part=0; part<2; part++) {
495
for (i=0; i<ncon; i++) {
496
if (rpqLength(queues[2*i+part]) > 0 &&
497
(*from == -1 || rpqSeeTopKey(queues[2*i+part]) > max)) {
498
max = rpqSeeTopKey(queues[2*i+part]);
499
*from = part;
500
*cnum = i;
501
}
502
}
503
}
504
/*
505
printf("Selected2 %"PRIDX"(%"PRIDX") -> %"PRIDX"\n",
506
*from, *cnum, rpqLength(queues[2*(*cnum)+(*from)]), max);
507
*/
508
}
509
}
510
511
512
/*************************************************************************/
513
/*! Prints statistics about the refinement */
514
/*************************************************************************/
515
void Print2WayRefineStats(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts,
516
real_t deltabal, idx_t mincutorder)
517
{
518
int i;
519
520
if (mincutorder == -2) {
521
printf("Parts: ");
522
printf("Nv-Nb[%5"PRIDX" %5"PRIDX"] ICut: %6"PRIDX,
523
graph->nvtxs, graph->nbnd, graph->mincut);
524
printf(" [");
525
for (i=0; i<graph->ncon; i++)
526
printf("(%.3"PRREAL" %.3"PRREAL" T:%.3"PRREAL" %.3"PRREAL")",
527
graph->pwgts[i]*graph->invtvwgt[i],
528
graph->pwgts[graph->ncon+i]*graph->invtvwgt[i],
529
ntpwgts[i], ntpwgts[graph->ncon+i]);
530
printf("] LB: %.3"PRREAL"(%+.3"PRREAL")\n",
531
ComputeLoadImbalance(graph, 2, ctrl->pijbm), deltabal);
532
}
533
else {
534
printf("\tMincut: %6"PRIDX" at %5"PRIDX" NBND %6"PRIDX" NPwgts: [",
535
graph->mincut, mincutorder, graph->nbnd);
536
for (i=0; i<graph->ncon; i++)
537
printf("(%.3"PRREAL" %.3"PRREAL")",
538
graph->pwgts[i]*graph->invtvwgt[i], graph->pwgts[graph->ncon+i]*graph->invtvwgt[i]);
539
printf("] LB: %.3"PRREAL"(%+.3"PRREAL")\n",
540
ComputeLoadImbalance(graph, 2, ctrl->pijbm), deltabal);
541
}
542
}
543
544
545