ADflow  v1.0
ADflow is a finite volume RANS solver tailored for gradient-based aerodynamic design optimization.
metis.c
Go to the documentation of this file.
1 /*
2  * Copyright 1997, Regents of the University of Minnesota
3  *
4  * balance.c
5  *
6  * This file contains code that is used to forcefully balance either
7  * bisections or k-sections
8  *
9  * Started 7/29/97
10  * George
11  *
12  * $Id$
13  *
14  */
15 
16 #include <metis.h>
17 
18 /*************************************************************************
19 * This function is the entry point of the bisection balancing algorithms.
20 **************************************************************************/
21 void Balance2Way(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
22 {
23  int mindiff;
24 
25  /* Return right away if the balance is OK */
26  mindiff = abs(tpwgts[0]-graph->pwgts[0]);
27  if (mindiff < 3*(graph->pwgts[0]+graph->pwgts[1])/graph->nvtxs)
28  return;
29  if (graph->pwgts[0] > tpwgts[0] && graph->pwgts[0] < (int)(ubfactor*tpwgts[0]))
30  return;
31  if (graph->pwgts[1] > tpwgts[1] && graph->pwgts[1] < (int)(ubfactor*tpwgts[1]))
32  return;
33 
34  if (graph->nbnd > 0)
35  Bnd2WayBalance(ctrl, graph, tpwgts);
36  else
37  General2WayBalance(ctrl, graph, tpwgts);
38 
39 }
40 
41 
42 
43 /*************************************************************************
44 * This function balances two partitions by moving boundary nodes
45 * from the domain that is overweight to the one that is underweight.
46 **************************************************************************/
47 void Bnd2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts)
48 {
49  int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, tmp;
50  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
51  idxtype *moved, *perm;
52  PQueueType parts;
53  int higain, oldgain, mincut, mindiff;
54 
55  nvtxs = graph->nvtxs;
56  xadj = graph->xadj;
57  vwgt = graph->vwgt;
58  adjncy = graph->adjncy;
59  adjwgt = graph->adjwgt;
60  where = graph->where;
61  id = graph->id;
62  ed = graph->ed;
63  pwgts = graph->pwgts;
64  bndptr = graph->bndptr;
65  bndind = graph->bndind;
66 
67  moved = idxwspacemalloc(ctrl, nvtxs);
68  perm = idxwspacemalloc(ctrl, nvtxs);
69 
70  /* Determine from which domain you will be moving data */
71  mindiff = abs(tpwgts[0]-pwgts[0]);
72  from = (pwgts[0] < tpwgts[0] ? 1 : 0);
73  to = (from+1)%2;
74 
75  IFSET(ctrl->dbglvl, DBG_REFINE,
76  printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n",
77  pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
78 
79  tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)];
80  PQueueInit(ctrl, &parts, nvtxs, tmp);
81 
82  idxset(nvtxs, -1, moved);
83 
84  ASSERT(ComputeCut(graph, where) == graph->mincut);
85  ASSERT(CheckBnd(graph));
86 
87  /* Insert the boundary nodes of the proper partition whose size is OK in the priority queue */
88  nbnd = graph->nbnd;
89  RandomPermute(nbnd, perm, 1);
90  for (ii=0; ii<nbnd; ii++) {
91  i = perm[ii];
92  ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0);
93  ASSERT(bndptr[bndind[i]] != -1);
94  if (where[bndind[i]] == from && vwgt[bndind[i]] <= mindiff)
95  PQueueInsert(&parts, bndind[i], ed[bndind[i]]-id[bndind[i]]);
96  }
97 
98  mincut = graph->mincut;
99  for (nswaps=0; nswaps<nvtxs; nswaps++) {
100  if ((higain = PQueueGetMax(&parts)) == -1)
101  break;
102  ASSERT(bndptr[higain] != -1);
103 
104  if (pwgts[to]+vwgt[higain] > tpwgts[to])
105  break;
106 
107  mincut -= (ed[higain]-id[higain]);
108  INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
109 
110  where[higain] = to;
111  moved[higain] = nswaps;
112 
113  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
114  printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1]));
115 
116  /**************************************************************
117  * Update the id[i]/ed[i] values of the affected nodes
118  ***************************************************************/
119  SWAP(id[higain], ed[higain], tmp);
120  if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
121  BNDDelete(nbnd, bndind, bndptr, higain);
122 
123  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
124  k = adjncy[j];
125  oldgain = ed[k]-id[k];
126 
127  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
128  INC_DEC(id[k], ed[k], kwgt);
129 
130  /* Update its boundary information and queue position */
131  if (bndptr[k] != -1) { /* If k was a boundary vertex */
132  if (ed[k] == 0) { /* Not a boundary vertex any more */
133  BNDDelete(nbnd, bndind, bndptr, k);
134  if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff) /* Remove it if in the queues */
135  PQueueDelete(&parts, k, oldgain);
136  }
137  else { /* If it has not been moved, update its position in the queue */
138  if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff)
139  PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]);
140  }
141  }
142  else {
143  if (ed[k] > 0) { /* It will now become a boundary vertex */
144  BNDInsert(nbnd, bndind, bndptr, k);
145  if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff)
146  PQueueInsert(&parts, k, ed[k]-id[k]);
147  }
148  }
149  }
150  }
151 
152  IFSET(ctrl->dbglvl, DBG_REFINE,
153  printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd));
154 
155  graph->mincut = mincut;
156  graph->nbnd = nbnd;
157 
158  PQueueFree(ctrl, &parts);
159 
160  idxwspacefree(ctrl, nvtxs);
161  idxwspacefree(ctrl, nvtxs);
162 }
163 
164 
165 /*************************************************************************
166 * This function balances two partitions by moving the highest gain
167 * (including negative gain) vertices to the other domain.
168 * It is used only when tha unbalance is due to non contigous
169 * subdomains. That is, the are no boundary vertices.
170 * It moves vertices from the domain that is overweight to the one that
171 * is underweight.
172 **************************************************************************/
173 void General2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts)
174 {
175  int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, tmp;
176  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
177  idxtype *moved, *perm;
178  PQueueType parts;
179  int higain, oldgain, mincut, mindiff;
180 
181  nvtxs = graph->nvtxs;
182  xadj = graph->xadj;
183  vwgt = graph->vwgt;
184  adjncy = graph->adjncy;
185  adjwgt = graph->adjwgt;
186  where = graph->where;
187  id = graph->id;
188  ed = graph->ed;
189  pwgts = graph->pwgts;
190  bndptr = graph->bndptr;
191  bndind = graph->bndind;
192 
193  moved = idxwspacemalloc(ctrl, nvtxs);
194  perm = idxwspacemalloc(ctrl, nvtxs);
195 
196  /* Determine from which domain you will be moving data */
197  mindiff = abs(tpwgts[0]-pwgts[0]);
198  from = (pwgts[0] < tpwgts[0] ? 1 : 0);
199  to = (from+1)%2;
200 
201  IFSET(ctrl->dbglvl, DBG_REFINE,
202  printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d [B]\n",
203  pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
204 
205  tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)];
206  PQueueInit(ctrl, &parts, nvtxs, tmp);
207 
208  idxset(nvtxs, -1, moved);
209 
210  ASSERT(ComputeCut(graph, where) == graph->mincut);
211  ASSERT(CheckBnd(graph));
212 
213  /* Insert the nodes of the proper partition whose size is OK in the priority queue */
214  RandomPermute(nvtxs, perm, 1);
215  for (ii=0; ii<nvtxs; ii++) {
216  i = perm[ii];
217  if (where[i] == from && vwgt[i] <= mindiff)
218  PQueueInsert(&parts, i, ed[i]-id[i]);
219  }
220 
221  mincut = graph->mincut;
222  nbnd = graph->nbnd;
223  for (nswaps=0; nswaps<nvtxs; nswaps++) {
224  if ((higain = PQueueGetMax(&parts)) == -1)
225  break;
226 
227  if (pwgts[to]+vwgt[higain] > tpwgts[to])
228  break;
229 
230  mincut -= (ed[higain]-id[higain]);
231  INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
232 
233  where[higain] = to;
234  moved[higain] = nswaps;
235 
236  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
237  printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], mincut, pwgts[0], pwgts[1]));
238 
239  /**************************************************************
240  * Update the id[i]/ed[i] values of the affected nodes
241  ***************************************************************/
242  SWAP(id[higain], ed[higain], tmp);
243  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
244  BNDDelete(nbnd, bndind, bndptr, higain);
245  if (ed[higain] > 0 && bndptr[higain] == -1)
246  BNDInsert(nbnd, bndind, bndptr, higain);
247 
248  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
249  k = adjncy[j];
250  oldgain = ed[k]-id[k];
251 
252  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
253  INC_DEC(id[k], ed[k], kwgt);
254 
255  /* Update the queue position */
256  if (moved[k] == -1 && where[k] == from && vwgt[k] <= mindiff)
257  PQueueUpdate(&parts, k, oldgain, ed[k]-id[k]);
258 
259  /* Update its boundary information */
260  if (ed[k] == 0 && bndptr[k] != -1)
261  BNDDelete(nbnd, bndind, bndptr, k);
262  else if (ed[k] > 0 && bndptr[k] == -1)
263  BNDInsert(nbnd, bndind, bndptr, k);
264  }
265  }
266 
267  IFSET(ctrl->dbglvl, DBG_REFINE,
268  printf("\tMinimum cut: %6d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, pwgts[0], pwgts[1], nbnd));
269 
270  graph->mincut = mincut;
271  graph->nbnd = nbnd;
272 
273  PQueueFree(ctrl, &parts);
274 
275  idxwspacefree(ctrl, nvtxs);
276  idxwspacefree(ctrl, nvtxs);
277 }
278 /*
279  * Copyright 1997, Regents of the University of Minnesota
280  *
281  * bucketsort.c
282  *
283  * This file contains code that implement a variety of counting sorting
284  * algorithms
285  *
286  * Started 7/25/97
287  * George
288  *
289  * $Id$
290  *
291  */
292 
293 
294 
295 
296 
297 /*************************************************************************
298 * This function uses simple counting sort to return a permutation array
299 * corresponding to the sorted order. The keys are assumed to start from
300 * 0 and they are positive. This sorting is used during matching.
301 **************************************************************************/
302 void BucketSortKeysInc(int n, int max, idxtype *keys, idxtype *tperm, idxtype *perm)
303 {
304  int i, ii;
305  idxtype *counts;
306 
307  counts = idxsmalloc(max+2, 0, "BucketSortKeysInc: counts");
308 
309  for (i=0; i<n; i++)
310  counts[keys[i]]++;
311  MAKECSR(i, max+1, counts);
312 
313  for (ii=0; ii<n; ii++) {
314  i = tperm[ii];
315  perm[counts[keys[i]]++] = i;
316  }
317 
318  free(counts);
319 }
320 
321 /*
322  * Copyright 1997, Regents of the University of Minnesota
323  *
324  * ccgraph.c
325  *
326  * This file contains the functions that create the coarse graph
327  *
328  * Started 8/11/97
329  * George
330  *
331  * $Id$
332  *
333  */
334 
335 
336 
337 
338 
339 /*************************************************************************
340 * This function creates the coarser graph
341 **************************************************************************/
342 void CreateCoarseGraph(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
343 {
344  int i, j, jj, k, kk, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask, dovsize;
345  idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj;
346  idxtype *cmap, *htable;
347  idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum;
348  float *nvwgt, *cnvwgt;
349  GraphType *cgraph;
350 
351  dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0);
352 
353  mask = HTLENGTH;
354  if (cnvtxs < 8*mask || graph->nedges/graph->nvtxs > 15) {
355  CreateCoarseGraphNoMask(ctrl, graph, cnvtxs, match, perm);
356  return;
357  }
358 
359  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
360 
361  nvtxs = graph->nvtxs;
362  ncon = graph->ncon;
363  xadj = graph->xadj;
364  vwgt = graph->vwgt;
365  vsize = graph->vsize;
366  nvwgt = graph->nvwgt;
367  adjncy = graph->adjncy;
368  adjwgt = graph->adjwgt;
369  adjwgtsum = graph->adjwgtsum;
370  cmap = graph->cmap;
371 
372  /* Initialize the coarser graph */
373  cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize);
374  cxadj = cgraph->xadj;
375  cvwgt = cgraph->vwgt;
376  cvsize = cgraph->vsize;
377  cnvwgt = cgraph->nvwgt;
378  cadjwgtsum = cgraph->adjwgtsum;
379  cadjncy = cgraph->adjncy;
380  cadjwgt = cgraph->adjwgt;
381 
382 
383  iend = xadj[nvtxs];
384  auxadj = ctrl->wspace.auxcore;
385  memcpy(auxadj, adjncy, iend*sizeof(idxtype));
386  for (i=0; i<iend; i++)
387  auxadj[i] = cmap[auxadj[i]];
388 
389  htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1));
390 
391  cxadj[0] = cnvtxs = cnedges = 0;
392  for (i=0; i<nvtxs; i++) {
393  v = perm[i];
394  if (cmap[v] != cnvtxs)
395  continue;
396 
397  u = match[v];
398  if (ncon == 1)
399  cvwgt[cnvtxs] = vwgt[v];
400  else
401  scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon);
402 
403  if (dovsize)
404  cvsize[cnvtxs] = vsize[v];
405 
406  cadjwgtsum[cnvtxs] = adjwgtsum[v];
407  nedges = 0;
408 
409  istart = xadj[v];
410  iend = xadj[v+1];
411  for (j=istart; j<iend; j++) {
412  k = auxadj[j];
413  kk = k&mask;
414  if ((m = htable[kk]) == -1) {
415  cadjncy[nedges] = k;
416  cadjwgt[nedges] = adjwgt[j];
417  htable[kk] = nedges++;
418  }
419  else if (cadjncy[m] == k) {
420  cadjwgt[m] += adjwgt[j];
421  }
422  else {
423  for (jj=0; jj<nedges; jj++) {
424  if (cadjncy[jj] == k) {
425  cadjwgt[jj] += adjwgt[j];
426  break;
427  }
428  }
429  if (jj == nedges) {
430  cadjncy[nedges] = k;
431  cadjwgt[nedges++] = adjwgt[j];
432  }
433  }
434  }
435 
436  if (v != u) {
437  if (ncon == 1)
438  cvwgt[cnvtxs] += vwgt[u];
439  else
440  saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1);
441 
442  if (dovsize)
443  cvsize[cnvtxs] += vsize[u];
444 
445  cadjwgtsum[cnvtxs] += adjwgtsum[u];
446 
447  istart = xadj[u];
448  iend = xadj[u+1];
449  for (j=istart; j<iend; j++) {
450  k = auxadj[j];
451  kk = k&mask;
452  if ((m = htable[kk]) == -1) {
453  cadjncy[nedges] = k;
454  cadjwgt[nedges] = adjwgt[j];
455  htable[kk] = nedges++;
456  }
457  else if (cadjncy[m] == k) {
458  cadjwgt[m] += adjwgt[j];
459  }
460  else {
461  for (jj=0; jj<nedges; jj++) {
462  if (cadjncy[jj] == k) {
463  cadjwgt[jj] += adjwgt[j];
464  break;
465  }
466  }
467  if (jj == nedges) {
468  cadjncy[nedges] = k;
469  cadjwgt[nedges++] = adjwgt[j];
470  }
471  }
472  }
473 
474  /* Remove the contracted adjacency weight */
475  jj = htable[cnvtxs&mask];
476  if (jj >= 0 && cadjncy[jj] != cnvtxs) {
477  for (jj=0; jj<nedges; jj++) {
478  if (cadjncy[jj] == cnvtxs)
479  break;
480  }
481  }
482  if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */
483  cadjwgtsum[cnvtxs] -= cadjwgt[jj];
484  cadjncy[jj] = cadjncy[--nedges];
485  cadjwgt[jj] = cadjwgt[nedges];
486  }
487  }
488 
489  ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v]));
490 
491  for (j=0; j<nedges; j++)
492  htable[cadjncy[j]&mask] = -1; /* Zero out the htable */
493  htable[cnvtxs&mask] = -1;
494 
495  cnedges += nedges;
496  cxadj[++cnvtxs] = cnedges;
497  cadjncy += nedges;
498  cadjwgt += nedges;
499  }
500 
501  cgraph->nedges = cnedges;
502 
503  ReAdjustMemory(graph, cgraph, dovsize);
504 
505  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
506 
507  idxwspacefree(ctrl, mask+1);
508 
509 }
510 
511 
512 /*************************************************************************
513 * This function creates the coarser graph
514 **************************************************************************/
515 void CreateCoarseGraphNoMask(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
516 {
517  int i, j, k, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, dovsize;
518  idxtype *xadj, *vwgt, *vsize, *adjncy, *adjwgt, *adjwgtsum, *auxadj;
519  idxtype *cmap, *htable;
520  idxtype *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt, *cadjwgtsum;
521  float *nvwgt, *cnvwgt;
522  GraphType *cgraph;
523 
524  dovsize = (ctrl->optype == OP_KVMETIS ? 1 : 0);
525 
526  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
527 
528  nvtxs = graph->nvtxs;
529  ncon = graph->ncon;
530  xadj = graph->xadj;
531  vwgt = graph->vwgt;
532  vsize = graph->vsize;
533  nvwgt = graph->nvwgt;
534  adjncy = graph->adjncy;
535  adjwgt = graph->adjwgt;
536  adjwgtsum = graph->adjwgtsum;
537  cmap = graph->cmap;
538 
539 
540  /* Initialize the coarser graph */
541  cgraph = SetUpCoarseGraph(graph, cnvtxs, dovsize);
542  cxadj = cgraph->xadj;
543  cvwgt = cgraph->vwgt;
544  cvsize = cgraph->vsize;
545  cnvwgt = cgraph->nvwgt;
546  cadjwgtsum = cgraph->adjwgtsum;
547  cadjncy = cgraph->adjncy;
548  cadjwgt = cgraph->adjwgt;
549 
550 
551  htable = idxset(cnvtxs, -1, idxwspacemalloc(ctrl, cnvtxs));
552 
553  iend = xadj[nvtxs];
554  auxadj = ctrl->wspace.auxcore;
555  memcpy(auxadj, adjncy, iend*sizeof(idxtype));
556  for (i=0; i<iend; i++)
557  auxadj[i] = cmap[auxadj[i]];
558 
559  cxadj[0] = cnvtxs = cnedges = 0;
560  for (i=0; i<nvtxs; i++) {
561  v = perm[i];
562  if (cmap[v] != cnvtxs)
563  continue;
564 
565  u = match[v];
566  if (ncon == 1)
567  cvwgt[cnvtxs] = vwgt[v];
568  else
569  scopy(ncon, nvwgt+v*ncon, cnvwgt+cnvtxs*ncon);
570 
571  if (dovsize)
572  cvsize[cnvtxs] = vsize[v];
573 
574  cadjwgtsum[cnvtxs] = adjwgtsum[v];
575  nedges = 0;
576 
577  istart = xadj[v];
578  iend = xadj[v+1];
579  for (j=istart; j<iend; j++) {
580  k = auxadj[j];
581  if ((m = htable[k]) == -1) {
582  cadjncy[nedges] = k;
583  cadjwgt[nedges] = adjwgt[j];
584  htable[k] = nedges++;
585  }
586  else {
587  cadjwgt[m] += adjwgt[j];
588  }
589  }
590 
591  if (v != u) {
592  if (ncon == 1)
593  cvwgt[cnvtxs] += vwgt[u];
594  else
595  saxpy(ncon, 1.0, nvwgt+u*ncon, 1, cnvwgt+cnvtxs*ncon, 1);
596 
597  if (dovsize)
598  cvsize[cnvtxs] += vsize[u];
599 
600  cadjwgtsum[cnvtxs] += adjwgtsum[u];
601 
602  istart = xadj[u];
603  iend = xadj[u+1];
604  for (j=istart; j<iend; j++) {
605  k = auxadj[j];
606  if ((m = htable[k]) == -1) {
607  cadjncy[nedges] = k;
608  cadjwgt[nedges] = adjwgt[j];
609  htable[k] = nedges++;
610  }
611  else {
612  cadjwgt[m] += adjwgt[j];
613  }
614  }
615 
616  /* Remove the contracted adjacency weight */
617  if ((j = htable[cnvtxs]) != -1) {
618  ASSERT(cadjncy[j] == cnvtxs);
619  cadjwgtsum[cnvtxs] -= cadjwgt[j];
620  cadjncy[j] = cadjncy[--nedges];
621  cadjwgt[j] = cadjwgt[nedges];
622  htable[cnvtxs] = -1;
623  }
624  }
625 
626  ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d\n", cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt)));
627 
628  for (j=0; j<nedges; j++)
629  htable[cadjncy[j]] = -1; /* Zero out the htable */
630 
631  cnedges += nedges;
632  cxadj[++cnvtxs] = cnedges;
633  cadjncy += nedges;
634  cadjwgt += nedges;
635  }
636 
637  cgraph->nedges = cnedges;
638 
639  ReAdjustMemory(graph, cgraph, dovsize);
640 
641  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
642 
643  idxwspacefree(ctrl, cnvtxs);
644 }
645 
646 
647 /*************************************************************************
648 * This function creates the coarser graph
649 **************************************************************************/
650 void CreateCoarseGraph_NVW(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
651 {
652  int i, j, jj, k, kk, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, mask;
653  idxtype *xadj, *adjncy, *adjwgtsum, *auxadj;
654  idxtype *cmap, *htable;
655  idxtype *cxadj, *cvwgt, *cadjncy, *cadjwgt, *cadjwgtsum;
656  float *nvwgt, *cnvwgt;
657  GraphType *cgraph;
658 
659 
660  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ContractTmr));
661 
662  nvtxs = graph->nvtxs;
663  ncon = graph->ncon;
664  xadj = graph->xadj;
665  nvwgt = graph->nvwgt;
666  adjncy = graph->adjncy;
667  adjwgtsum = graph->adjwgtsum;
668  cmap = graph->cmap;
669 
670  /* Initialize the coarser graph */
671  cgraph = SetUpCoarseGraph(graph, cnvtxs, 0);
672  cxadj = cgraph->xadj;
673  cvwgt = cgraph->vwgt;
674  cnvwgt = cgraph->nvwgt;
675  cadjwgtsum = cgraph->adjwgtsum;
676  cadjncy = cgraph->adjncy;
677  cadjwgt = cgraph->adjwgt;
678 
679 
680  iend = xadj[nvtxs];
681  auxadj = ctrl->wspace.auxcore;
682  memcpy(auxadj, adjncy, iend*sizeof(idxtype));
683  for (i=0; i<iend; i++)
684  auxadj[i] = cmap[auxadj[i]];
685 
686  mask = HTLENGTH;
687  htable = idxset(mask+1, -1, idxwspacemalloc(ctrl, mask+1));
688 
689  cxadj[0] = cnvtxs = cnedges = 0;
690  for (i=0; i<nvtxs; i++) {
691  v = perm[i];
692  if (cmap[v] != cnvtxs)
693  continue;
694 
695  u = match[v];
696  cvwgt[cnvtxs] = 1;
697  cadjwgtsum[cnvtxs] = adjwgtsum[v];
698  nedges = 0;
699 
700  istart = xadj[v];
701  iend = xadj[v+1];
702  for (j=istart; j<iend; j++) {
703  k = auxadj[j];
704  kk = k&mask;
705  if ((m = htable[kk]) == -1) {
706  cadjncy[nedges] = k;
707  cadjwgt[nedges] = 1;
708  htable[kk] = nedges++;
709  }
710  else if (cadjncy[m] == k) {
711  cadjwgt[m]++;
712  }
713  else {
714  for (jj=0; jj<nedges; jj++) {
715  if (cadjncy[jj] == k) {
716  cadjwgt[jj]++;
717  break;
718  }
719  }
720  if (jj == nedges) {
721  cadjncy[nedges] = k;
722  cadjwgt[nedges++] = 1;
723  }
724  }
725  }
726 
727  if (v != u) {
728  cvwgt[cnvtxs]++;
729  cadjwgtsum[cnvtxs] += adjwgtsum[u];
730 
731  istart = xadj[u];
732  iend = xadj[u+1];
733  for (j=istart; j<iend; j++) {
734  k = auxadj[j];
735  kk = k&mask;
736  if ((m = htable[kk]) == -1) {
737  cadjncy[nedges] = k;
738  cadjwgt[nedges] = 1;
739  htable[kk] = nedges++;
740  }
741  else if (cadjncy[m] == k) {
742  cadjwgt[m]++;
743  }
744  else {
745  for (jj=0; jj<nedges; jj++) {
746  if (cadjncy[jj] == k) {
747  cadjwgt[jj]++;
748  break;
749  }
750  }
751  if (jj == nedges) {
752  cadjncy[nedges] = k;
753  cadjwgt[nedges++] = 1;
754  }
755  }
756  }
757 
758  /* Remove the contracted adjacency weight */
759  jj = htable[cnvtxs&mask];
760  if (jj >= 0 && cadjncy[jj] != cnvtxs) {
761  for (jj=0; jj<nedges; jj++) {
762  if (cadjncy[jj] == cnvtxs)
763  break;
764  }
765  }
766  if (jj >= 0 && cadjncy[jj] == cnvtxs) { /* This 2nd check is needed for non-adjacent matchings */
767  cadjwgtsum[cnvtxs] -= cadjwgt[jj];
768  cadjncy[jj] = cadjncy[--nedges];
769  cadjwgt[jj] = cadjwgt[nedges];
770  }
771  }
772 
773  ASSERTP(cadjwgtsum[cnvtxs] == idxsum(nedges, cadjwgt), ("%d %d %d %d %d\n", cnvtxs, cadjwgtsum[cnvtxs], idxsum(nedges, cadjwgt), adjwgtsum[u], adjwgtsum[v]));
774 
775  for (j=0; j<nedges; j++)
776  htable[cadjncy[j]&mask] = -1; /* Zero out the htable */
777  htable[cnvtxs&mask] = -1;
778 
779  cnedges += nedges;
780  cxadj[++cnvtxs] = cnedges;
781  cadjncy += nedges;
782  cadjwgt += nedges;
783  }
784 
785  cgraph->nedges = cnedges;
786 
787  ReAdjustMemory(graph, cgraph, 0);
788 
789  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ContractTmr));
790 
791  idxwspacefree(ctrl, mask+1);
792 
793 }
794 
795 
796 /*************************************************************************
797 * Setup the various arrays for the coarse graph
798 **************************************************************************/
799 GraphType *SetUpCoarseGraph(GraphType *graph, int cnvtxs, int dovsize)
800 {
801  GraphType *cgraph;
802 
803  cgraph = CreateGraph();
804  cgraph->nvtxs = cnvtxs;
805  cgraph->ncon = graph->ncon;
806 
807  cgraph->finer = graph;
808  graph->coarser = cgraph;
809 
810 
811  /* Allocate memory for the coarser graph */
812  if (graph->ncon == 1) {
813  if (dovsize) {
814  cgraph->gdata = idxmalloc(5*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
815  cgraph->xadj = cgraph->gdata;
816  cgraph->vwgt = cgraph->gdata + cnvtxs+1;
817  cgraph->vsize = cgraph->gdata + 2*cnvtxs+1;
818  cgraph->adjwgtsum = cgraph->gdata + 3*cnvtxs+1;
819  cgraph->cmap = cgraph->gdata + 4*cnvtxs+1;
820  cgraph->adjncy = cgraph->gdata + 5*cnvtxs+1;
821  cgraph->adjwgt = cgraph->gdata + 5*cnvtxs+1 + graph->nedges;
822  }
823  else {
824  cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
825  cgraph->xadj = cgraph->gdata;
826  cgraph->vwgt = cgraph->gdata + cnvtxs+1;
827  cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1;
828  cgraph->cmap = cgraph->gdata + 3*cnvtxs+1;
829  cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1;
830  cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges;
831  }
832  }
833  else {
834  if (dovsize) {
835  cgraph->gdata = idxmalloc(4*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
836  cgraph->xadj = cgraph->gdata;
837  cgraph->vsize = cgraph->gdata + cnvtxs+1;
838  cgraph->adjwgtsum = cgraph->gdata + 2*cnvtxs+1;
839  cgraph->cmap = cgraph->gdata + 3*cnvtxs+1;
840  cgraph->adjncy = cgraph->gdata + 4*cnvtxs+1;
841  cgraph->adjwgt = cgraph->gdata + 4*cnvtxs+1 + graph->nedges;
842  }
843  else {
844  cgraph->gdata = idxmalloc(3*cnvtxs+1 + 2*graph->nedges, "SetUpCoarseGraph: gdata");
845  cgraph->xadj = cgraph->gdata;
846  cgraph->adjwgtsum = cgraph->gdata + cnvtxs+1;
847  cgraph->cmap = cgraph->gdata + 2*cnvtxs+1;
848  cgraph->adjncy = cgraph->gdata + 3*cnvtxs+1;
849  cgraph->adjwgt = cgraph->gdata + 3*cnvtxs+1 + graph->nedges;
850  }
851 
852  cgraph->nvwgt = fmalloc(graph->ncon*cnvtxs, "SetUpCoarseGraph: nvwgt");
853  }
854 
855  return cgraph;
856 }
857 
858 
859 /*************************************************************************
860 * This function re-adjusts the amount of memory that was allocated if
861 * it will lead to significant savings
862 **************************************************************************/
863 void ReAdjustMemory(GraphType *graph, GraphType *cgraph, int dovsize)
864 {
865 
866  if (cgraph->nedges > 100000 && graph->nedges < 0.7*graph->nedges) {
867  idxcopy(cgraph->nedges, cgraph->adjwgt, cgraph->adjncy+cgraph->nedges);
868 
869  if (graph->ncon == 1) {
870  if (dovsize) {
871  cgraph->gdata = realloc(cgraph->gdata, (5*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
872 
873  /* Do this, in case everything was copied into new space */
874  cgraph->xadj = cgraph->gdata;
875  cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1;
876  cgraph->vsize = cgraph->gdata + 2*cgraph->nvtxs+1;
877  cgraph->adjwgtsum = cgraph->gdata + 3*cgraph->nvtxs+1;
878  cgraph->cmap = cgraph->gdata + 4*cgraph->nvtxs+1;
879  cgraph->adjncy = cgraph->gdata + 5*cgraph->nvtxs+1;
880  cgraph->adjwgt = cgraph->gdata + 5*cgraph->nvtxs+1 + cgraph->nedges;
881  }
882  else {
883  cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
884 
885  /* Do this, in case everything was copied into new space */
886  cgraph->xadj = cgraph->gdata;
887  cgraph->vwgt = cgraph->gdata + cgraph->nvtxs+1;
888  cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1;
889  cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1;
890  cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1;
891  cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges;
892  }
893  }
894  else {
895  if (dovsize) {
896  cgraph->gdata = realloc(cgraph->gdata, (4*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
897 
898  /* Do this, in case everything was copied into new space */
899  cgraph->xadj = cgraph->gdata;
900  cgraph->vsize = cgraph->gdata + cgraph->nvtxs+1;
901  cgraph->adjwgtsum = cgraph->gdata + 2*cgraph->nvtxs+1;
902  cgraph->cmap = cgraph->gdata + 3*cgraph->nvtxs+1;
903  cgraph->adjncy = cgraph->gdata + 4*cgraph->nvtxs+1;
904  cgraph->adjwgt = cgraph->gdata + 4*cgraph->nvtxs+1 + cgraph->nedges;
905  }
906  else {
907  cgraph->gdata = realloc(cgraph->gdata, (3*cgraph->nvtxs+1 + 2*cgraph->nedges)*sizeof(idxtype));
908 
909  /* Do this, in case everything was copied into new space */
910  cgraph->xadj = cgraph->gdata;
911  cgraph->adjwgtsum = cgraph->gdata + cgraph->nvtxs+1;
912  cgraph->cmap = cgraph->gdata + 2*cgraph->nvtxs+1;
913  cgraph->adjncy = cgraph->gdata + 3*cgraph->nvtxs+1;
914  cgraph->adjwgt = cgraph->gdata + 3*cgraph->nvtxs+1 + cgraph->nedges;
915  }
916  }
917  }
918 
919 }
920 /*
921  * coarsen.c
922  *
923  * This file contains the driving routines for the coarsening process
924  *
925  * Started 7/23/97
926  * George
927  *
928  * $Id$
929  *
930  */
931 
932 
933 
934 
935 /*************************************************************************
936 * This function takes a graph and creates a sequence of coarser graphs
937 **************************************************************************/
939 {
940  int clevel;
941  GraphType *cgraph;
942 
943  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr));
944 
945  cgraph = graph;
946 
947  /* The following is ahack to allow the multiple bisections to go through with correct
948  coarsening */
949  if (ctrl->CType > 20) {
950  clevel = 1;
951  ctrl->CType -= 20;
952  }
953  else
954  clevel = 0;
955 
956  do {
957  IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n",
958  cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt,
959  (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs)));
960 
961  if (cgraph->adjwgt) {
962  switch (ctrl->CType) {
963  case MATCH_RM:
964  Match_RM(ctrl, cgraph);
965  break;
966  case MATCH_HEM:
967  if (clevel < 1)
968  Match_RM(ctrl, cgraph);
969  else
970  Match_HEM(ctrl, cgraph);
971  break;
972  case MATCH_SHEM:
973  if (clevel < 1)
974  Match_RM(ctrl, cgraph);
975  else
976  Match_SHEM(ctrl, cgraph);
977  break;
978  case MATCH_SHEMKWAY:
979  Match_SHEM(ctrl, cgraph);
980  break;
981  default:
982  errexit("Unknown CType: %d\n", ctrl->CType);
983  }
984  }
985  else {
986  Match_RM_NVW(ctrl, cgraph);
987  }
988 
989  cgraph = cgraph->coarser;
990  clevel++;
991 
992  } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2);
993 
994  IFSET(ctrl->dbglvl, DBG_COARSEN, printf("%6d %7d [%d] [%d %d]\n",
995  cgraph->nvtxs, cgraph->nedges, ctrl->CoarsenTo, ctrl->maxvwgt,
996  (cgraph->vwgt ? idxsum(cgraph->nvtxs, cgraph->vwgt) : cgraph->nvtxs)));
997 
998  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr));
999 
1000  return cgraph;
1001 }
1002 
1003 /*
1004  * Copyright 1997, Regents of the University of Minnesota
1005  *
1006  * compress.c
1007  *
1008  * This file contains code for compressing nodes with identical adjacency
1009  * structure and for prunning dense columns
1010  *
1011  * Started 9/17/97
1012  * George
1013  *
1014  * $Id$
1015  */
1016 
1017 
1018 
1019 /*************************************************************************
1020 * This function compresses a graph by merging identical vertices
1021 * The compression should lead to at least 10% reduction.
1022 **************************************************************************/
1023 void CompressGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *cptr, idxtype *cind)
1024 {
1025  int i, ii, iii, j, jj, k, l, cnvtxs, cnedges;
1026  idxtype *cxadj, *cadjncy, *cvwgt, *mark, *map;
1027  KeyValueType *keys;
1028 
1029  mark = idxsmalloc(nvtxs, -1, "CompressGraph: mark");
1030  map = idxsmalloc(nvtxs, -1, "CompressGraph: map");
1031  keys = (KeyValueType *)GKmalloc(nvtxs*sizeof(KeyValueType), "CompressGraph: keys");
1032 
1033  /* Compute a key for each adjacency list */
1034  for (i=0; i<nvtxs; i++) {
1035  k = 0;
1036  for (j=xadj[i]; j<xadj[i+1]; j++)
1037  k += adjncy[j];
1038  keys[i].key = k+i; /* Add the diagonal entry as well */
1039  keys[i].val = i;
1040  }
1041 
1042  ikeysort(nvtxs, keys);
1043 
1044  l = cptr[0] = 0;
1045  for (cnvtxs=i=0; i<nvtxs; i++) {
1046  ii = keys[i].val;
1047  if (map[ii] == -1) {
1048  mark[ii] = i; /* Add the diagonal entry */
1049  for (j=xadj[ii]; j<xadj[ii+1]; j++)
1050  mark[adjncy[j]] = i;
1051 
1052  cind[l++] = ii;
1053  map[ii] = cnvtxs;
1054 
1055  for (j=i+1; j<nvtxs; j++) {
1056  iii = keys[j].val;
1057 
1058  if (keys[i].key != keys[j].key || xadj[ii+1]-xadj[ii] != xadj[iii+1]-xadj[iii])
1059  break; /* Break if keys or degrees are different */
1060 
1061  if (map[iii] == -1) { /* Do a comparison if iii has not been mapped */
1062  for (jj=xadj[iii]; jj<xadj[iii+1]; jj++) {
1063  if (mark[adjncy[jj]] != i)
1064  break;
1065  }
1066 
1067  if (jj == xadj[iii+1]) { /* Identical adjacency structure */
1068  map[iii] = cnvtxs;
1069  cind[l++] = iii;
1070  }
1071  }
1072  }
1073 
1074  cptr[++cnvtxs] = l;
1075  }
1076  }
1077 
1078  /* printf("Original: %6d, Compressed: %6d\n", nvtxs, cnvtxs); */
1079 
1080 
1081  InitGraph(graph);
1082 
1083  if (cnvtxs >= COMPRESSION_FRACTION*nvtxs) {
1084  graph->nvtxs = nvtxs;
1085  graph->nedges = xadj[nvtxs];
1086  graph->ncon = 1;
1087  graph->xadj = xadj;
1088  graph->adjncy = adjncy;
1089 
1090  graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata");
1091  graph->vwgt = graph->gdata;
1092  graph->adjwgtsum = graph->gdata+nvtxs;
1093  graph->cmap = graph->gdata+2*nvtxs;
1094  graph->adjwgt = graph->gdata+3*nvtxs;
1095 
1096  idxset(nvtxs, 1, graph->vwgt);
1097  idxset(graph->nedges, 1, graph->adjwgt);
1098  for (i=0; i<nvtxs; i++)
1099  graph->adjwgtsum[i] = xadj[i+1]-xadj[i];
1100 
1101  graph->label = idxmalloc(nvtxs, "CompressGraph: label");
1102  for (i=0; i<nvtxs; i++)
1103  graph->label[i] = i;
1104  }
1105  else { /* Ok, form the compressed graph */
1106  cnedges = 0;
1107  for (i=0; i<cnvtxs; i++) {
1108  ii = cind[cptr[i]];
1109  cnedges += xadj[ii+1]-xadj[ii];
1110  }
1111 
1112  /* Allocate memory for the compressed graph*/
1113  graph->gdata = idxmalloc(4*cnvtxs+1 + 2*cnedges, "CompressGraph: gdata");
1114  cxadj = graph->xadj = graph->gdata;
1115  cvwgt = graph->vwgt = graph->gdata + cnvtxs+1;
1116  graph->adjwgtsum = graph->gdata + 2*cnvtxs+1;
1117  graph->cmap = graph->gdata + 3*cnvtxs+1;
1118  cadjncy = graph->adjncy = graph->gdata + 4*cnvtxs+1;
1119  graph->adjwgt = graph->gdata + 4*cnvtxs+1 + cnedges;
1120 
1121  /* Now go and compress the graph */
1122  idxset(nvtxs, -1, mark);
1123  l = cxadj[0] = 0;
1124  for (i=0; i<cnvtxs; i++) {
1125  cvwgt[i] = cptr[i+1]-cptr[i];
1126  mark[i] = i; /* Remove any dioganal entries in the compressed graph */
1127  for (j=cptr[i]; j<cptr[i+1]; j++) {
1128  ii = cind[j];
1129  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
1130  k = map[adjncy[jj]];
1131  if (mark[k] != i)
1132  cadjncy[l++] = k;
1133  mark[k] = i;
1134  }
1135  }
1136  cxadj[i+1] = l;
1137  }
1138 
1139  graph->nvtxs = cnvtxs;
1140  graph->nedges = l;
1141  graph->ncon = 1;
1142 
1143  idxset(graph->nedges, 1, graph->adjwgt);
1144  for (i=0; i<cnvtxs; i++)
1145  graph->adjwgtsum[i] = cxadj[i+1]-cxadj[i];
1146 
1147  graph->label = idxmalloc(cnvtxs, "CompressGraph: label");
1148  for (i=0; i<cnvtxs; i++)
1149  graph->label[i] = i;
1150 
1151  }
1152 
1153  GKfree((void **) &keys, (void **) &map, (void **) &mark, LTERM);
1154 }
1155 
1156 
1157 
1158 /*************************************************************************
1159 * This function prunes all the vertices in a graph with degree greater
1160 * than factor*average
1161 **************************************************************************/
1162 void PruneGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *iperm, float factor)
1163 {
1164  int i, j, k, l, nlarge, pnvtxs, pnedges;
1165  idxtype *pxadj, *padjncy;
1166  idxtype *perm;
1167 
1168  perm = idxmalloc(nvtxs, "PruneGraph: perm");
1169 
1170  factor = factor*xadj[nvtxs]/nvtxs;
1171 
1172  pnvtxs = pnedges = nlarge = 0;
1173  for (i=0; i<nvtxs; i++) {
1174  if (xadj[i+1]-xadj[i] < factor) {
1175  perm[i] = pnvtxs;
1176  iperm[pnvtxs++] = i;
1177  pnedges += xadj[i+1]-xadj[i];
1178  }
1179  else {
1180  perm[i] = nvtxs - ++nlarge;
1181  iperm[nvtxs-nlarge] = i;
1182  }
1183  }
1184 
1185  /* printf("Pruned %d vertices\n", nlarge); */
1186 
1187  InitGraph(graph);
1188 
1189  if (nlarge == 0) { /* No prunning */
1190  graph->nvtxs = nvtxs;
1191  graph->nedges = xadj[nvtxs];
1192  graph->ncon = 1;
1193  graph->xadj = xadj;
1194  graph->adjncy = adjncy;
1195 
1196  graph->gdata = idxmalloc(3*nvtxs+graph->nedges, "CompressGraph: gdata");
1197  graph->vwgt = graph->gdata;
1198  graph->adjwgtsum = graph->gdata+nvtxs;
1199  graph->cmap = graph->gdata+2*nvtxs;
1200  graph->adjwgt = graph->gdata+3*nvtxs;
1201 
1202  idxset(nvtxs, 1, graph->vwgt);
1203  idxset(graph->nedges, 1, graph->adjwgt);
1204  for (i=0; i<nvtxs; i++)
1205  graph->adjwgtsum[i] = xadj[i+1]-xadj[i];
1206 
1207  graph->label = idxmalloc(nvtxs, "CompressGraph: label");
1208  for (i=0; i<nvtxs; i++)
1209  graph->label[i] = i;
1210  }
1211  else { /* Prune the graph */
1212  /* Allocate memory for the compressed graph*/
1213  graph->gdata = idxmalloc(4*pnvtxs+1 + 2*pnedges, "PruneGraph: gdata");
1214  pxadj = graph->xadj = graph->gdata;
1215  graph->vwgt = graph->gdata + pnvtxs+1;
1216  graph->adjwgtsum = graph->gdata + 2*pnvtxs+1;
1217  graph->cmap = graph->gdata + 3*pnvtxs+1;
1218  padjncy = graph->adjncy = graph->gdata + 4*pnvtxs+1;
1219  graph->adjwgt = graph->gdata + 4*pnvtxs+1 + pnedges;
1220 
1221  pxadj[0] = pnedges = l = 0;
1222  for (i=0; i<nvtxs; i++) {
1223  if (xadj[i+1]-xadj[i] < factor) {
1224  for (j=xadj[i]; j<xadj[i+1]; j++) {
1225  k = perm[adjncy[j]];
1226  if (k < pnvtxs)
1227  padjncy[pnedges++] = k;
1228  }
1229  pxadj[++l] = pnedges;
1230  }
1231  }
1232 
1233  graph->nvtxs = pnvtxs;
1234  graph->nedges = pnedges;
1235  graph->ncon = 1;
1236 
1237  idxset(pnvtxs, 1, graph->vwgt);
1238  idxset(pnedges, 1, graph->adjwgt);
1239  for (i=0; i<pnvtxs; i++)
1240  graph->adjwgtsum[i] = pxadj[i+1]-pxadj[i];
1241 
1242  graph->label = idxmalloc(pnvtxs, "CompressGraph: label");
1243  for (i=0; i<pnvtxs; i++)
1244  graph->label[i] = i;
1245  }
1246 
1247  free(perm);
1248 
1249 }
1250 
1251 
1252 
1253 
1254 
1255 
1256 
1257 
1258 
1259 /*
1260  * Copyright 1997, Regents of the University of Minnesota
1261  *
1262  * debug.c
1263  *
1264  * This file contains code that performs self debuging
1265  *
1266  * Started 7/24/97
1267  * George
1268  *
1269  * $Id$
1270  *
1271  */
1272 
1273 
1274 
1275 /*************************************************************************
1276 * This function computes the cut given the graph and a where vector
1277 **************************************************************************/
1278 int ComputeCut(GraphType *graph, idxtype *where)
1279 {
1280  int i, j, cut;
1281 
1282  if (graph->adjwgt == NULL) {
1283  for (cut=0, i=0; i<graph->nvtxs; i++) {
1284  for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
1285  if (where[i] != where[graph->adjncy[j]])
1286  cut++;
1287  }
1288  }
1289  else {
1290  for (cut=0, i=0; i<graph->nvtxs; i++) {
1291  for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++)
1292  if (where[i] != where[graph->adjncy[j]])
1293  cut += graph->adjwgt[j];
1294  }
1295  }
1296 
1297  return cut/2;
1298 }
1299 
1300 
1301 /*************************************************************************
1302 * This function checks whether or not the boundary information is correct
1303 **************************************************************************/
1304 int CheckBnd(GraphType *graph)
1305 {
1306  int i, j, nvtxs, nbnd;
1307  idxtype *xadj, *adjncy, *where, *bndptr, *bndind;
1308 
1309  nvtxs = graph->nvtxs;
1310  xadj = graph->xadj;
1311  adjncy = graph->adjncy;
1312  where = graph->where;
1313  bndptr = graph->bndptr;
1314  bndind = graph->bndind;
1315 
1316  for (nbnd=0, i=0; i<nvtxs; i++) {
1317  if (xadj[i+1]-xadj[i] == 0)
1318  nbnd++; /* Islands are considered to be boundary vertices */
1319 
1320  for (j=xadj[i]; j<xadj[i+1]; j++) {
1321  if (where[i] != where[adjncy[j]]) {
1322  nbnd++;
1323  ASSERT(bndptr[i] != -1);
1324  ASSERT(bndind[bndptr[i]] == i);
1325  break;
1326  }
1327  }
1328  }
1329 
1330  ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd));
1331 
1332  return 1;
1333 }
1334 
1335 
1336 
1337 /*************************************************************************
1338 * This function checks whether or not the boundary information is correct
1339 **************************************************************************/
1341 {
1342  int i, j, nvtxs, nbnd, id, ed;
1343  idxtype *xadj, *adjncy, *where, *bndptr, *bndind;
1344 
1345  nvtxs = graph->nvtxs;
1346  xadj = graph->xadj;
1347  adjncy = graph->adjncy;
1348  where = graph->where;
1349  bndptr = graph->bndptr;
1350  bndind = graph->bndind;
1351 
1352  for (nbnd=0, i=0; i<nvtxs; i++) {
1353  id = ed = 0;
1354  for (j=xadj[i]; j<xadj[i+1]; j++) {
1355  if (where[i] != where[adjncy[j]])
1356  ed += graph->adjwgt[j];
1357  else
1358  id += graph->adjwgt[j];
1359  }
1360  if (ed - id >= 0 && xadj[i] < xadj[i+1]) {
1361  nbnd++;
1362  ASSERTP(bndptr[i] != -1, ("%d %d %d\n", i, id, ed));
1363  ASSERT(bndind[bndptr[i]] == i);
1364  }
1365  }
1366 
1367  ASSERTP(nbnd == graph->nbnd, ("%d %d\n", nbnd, graph->nbnd));
1368 
1369  return 1;
1370 }
1371 
1372 /*************************************************************************
1373 * This function checks whether or not the boundary information is correct
1374 **************************************************************************/
1375 int CheckNodeBnd(GraphType *graph, int onbnd)
1376 {
1377  int i, nvtxs, nbnd;
1378  idxtype *xadj, *adjncy, *where, *bndptr, *bndind;
1379 
1380  nvtxs = graph->nvtxs;
1381  xadj = graph->xadj;
1382  adjncy = graph->adjncy;
1383  where = graph->where;
1384  bndptr = graph->bndptr;
1385  bndind = graph->bndind;
1386 
1387  for (nbnd=0, i=0; i<nvtxs; i++) {
1388  if (where[i] == 2)
1389  nbnd++;
1390  }
1391 
1392  ASSERTP(nbnd == onbnd, ("%d %d\n", nbnd, onbnd));
1393 
1394  for (i=0; i<nvtxs; i++) {
1395  if (where[i] != 2) {
1396  ASSERTP(bndptr[i] == -1, ("%d %d\n", i, bndptr[i]));
1397  }
1398  else {
1399  ASSERTP(bndptr[i] != -1, ("%d %d\n", i, bndptr[i]));
1400  }
1401  }
1402 
1403  return 1;
1404 }
1405 
1406 
1407 
1408 /*************************************************************************
1409 * This function checks whether or not the rinfo of a vertex is consistent
1410 **************************************************************************/
1412 {
1413  int i, j;
1414 
1415  for (i=0; i<rinfo->ndegrees; i++) {
1416  for (j=i+1; j<rinfo->ndegrees; j++)
1417  ASSERTP(rinfo->edegrees[i].pid != rinfo->edegrees[j].pid, ("%d %d %d %d\n", i, j, rinfo->edegrees[i].pid, rinfo->edegrees[j].pid));
1418  }
1419 
1420  return 1;
1421 }
1422 
1423 
1424 
1425 /*************************************************************************
1426 * This function checks the correctness of the NodeFM data structures
1427 **************************************************************************/
1429 {
1430  int i, j, nvtxs, me, other;
1431  idxtype *xadj, *adjncy, *adjwgt, *vwgt, *where;
1432  idxtype edegrees[2], pwgts[3];
1433 
1434  nvtxs = graph->nvtxs;
1435  xadj = graph->xadj;
1436  vwgt = graph->vwgt;
1437  adjncy = graph->adjncy;
1438  adjwgt = graph->adjwgt;
1439 
1440  where = graph->where;
1441 
1442  /*------------------------------------------------------------
1443  / Compute now the separator external degrees
1444  /------------------------------------------------------------*/
1445  pwgts[0] = pwgts[1] = pwgts[2] = 0;
1446  for (i=0; i<nvtxs; i++) {
1447  me = where[i];
1448  pwgts[me] += vwgt[i];
1449 
1450  if (me == 2) { /* If it is on the separator do some computations */
1451  edegrees[0] = edegrees[1] = 0;
1452 
1453  for (j=xadj[i]; j<xadj[i+1]; j++) {
1454  other = where[adjncy[j]];
1455  if (other != 2)
1456  edegrees[other] += vwgt[adjncy[j]];
1457  }
1458  if (edegrees[0] != graph->nrinfo[i].edegrees[0] || edegrees[1] != graph->nrinfo[i].edegrees[1]) {
1459  printf("Something wrong with edegrees: %d %d %d %d %d\n", i, edegrees[0], edegrees[1], graph->nrinfo[i].edegrees[0], graph->nrinfo[i].edegrees[1]);
1460  return 0;
1461  }
1462  }
1463  }
1464 
1465  if (pwgts[0] != graph->pwgts[0] || pwgts[1] != graph->pwgts[1] || pwgts[2] != graph->pwgts[2])
1466  printf("Something wrong with part-weights: %d %d %d %d %d %d\n", pwgts[0], pwgts[1], pwgts[2], graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]);
1467 
1468  return 1;
1469 }
1470 
1471 
1472 /*************************************************************************
1473 * This function checks if the separator is indeed a separator
1474 **************************************************************************/
1476 {
1477  int i, j, nvtxs, other;
1478  idxtype *xadj, *adjncy, *where;
1479 
1480  nvtxs = graph->nvtxs;
1481  xadj = graph->xadj;
1482  adjncy = graph->adjncy;
1483  where = graph->where;
1484 
1485  for (i=0; i<nvtxs; i++) {
1486  if (where[i] == 2)
1487  continue;
1488  other = (where[i]+1)%2;
1489  for (j=xadj[i]; j<xadj[i+1]; j++) {
1490  ASSERTP(where[adjncy[j]] != other, ("%d %d %d %d %d %d\n", i, where[i], adjncy[j], where[adjncy[j]], xadj[i+1]-xadj[i], xadj[adjncy[j]+1]-xadj[adjncy[j]]));
1491  }
1492  }
1493 
1494  return 1;
1495 }
1496 
1497 
1498 /*
1499  * Copyright 1997, Regents of the University of Minnesota
1500  *
1501  * estmem.c
1502  *
1503  * This file contains code for estimating the amount of memory required by
1504  * the various routines in METIS
1505  *
1506  * Started 11/4/97
1507  * George
1508  *
1509  * $Id$
1510  *
1511  */
1512 
1513 
1514 
1515 /*************************************************************************
1516 * This function computes how much memory will be required by the various
1517 * routines in METIS
1518 **************************************************************************/
1519 void METIS_EstimateMemory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
1520 {
1521  int nedges, nlevels;
1522  float vfraction, efraction, vmult, emult;
1523  int coresize, gdata, rdata;
1524 
1525  if (*numflag == 1)
1526  Change2CNumbering(*nvtxs, xadj, adjncy);
1527 
1528  nedges = xadj[*nvtxs];
1529 
1530  InitRandom(-1);
1531  EstimateCFraction(*nvtxs, xadj, adjncy, &vfraction, &efraction);
1532 
1533  /* Estimate the amount of memory for coresize */
1534  if (*optype == 2)
1535  coresize = nedges;
1536  else
1537  coresize = 0;
1538  coresize += nedges + 11*(*nvtxs) + 4*1024 + 2*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype));
1539  coresize += 2*(*nvtxs); /* add some more fore other vectors */
1540 
1541  gdata = nedges; /* Assume that the user does not pass weights */
1542 
1543  nlevels = (int)(log(100.0/(*nvtxs))/log(vfraction) + .5);
1544  vmult = 0.5 + (1.0 - pow(vfraction, nlevels))/(1.0 - vfraction);
1545  emult = 1.0 + (1.0 - pow(efraction, nlevels+1))/(1.0 - efraction);
1546 
1547  gdata += vmult*4*(*nvtxs) + emult*2*nedges;
1548  if ((vmult-1.0)*4*(*nvtxs) + (emult-1.0)*2*nedges < 5*(*nvtxs))
1549  rdata = 0;
1550  else
1551  rdata = 5*(*nvtxs);
1552 
1553  *nbytes = sizeof(idxtype)*(coresize+gdata+rdata+(*nvtxs));
1554 
1555  if (*numflag == 1)
1556  Change2FNumbering2(*nvtxs, xadj, adjncy);
1557 }
1558 
1559 
1560 /*************************************************************************
1561 * This function finds a matching using the HEM heuristic
1562 **************************************************************************/
1563 void EstimateCFraction(int nvtxs, idxtype *xadj, idxtype *adjncy, float *vfraction, float *efraction)
1564 {
1565  int i, ii, j, cnvtxs, cnedges, maxidx;
1566  idxtype *match, *cmap, *perm;
1567 
1568  cmap = idxmalloc(nvtxs, "cmap");
1569  match = idxsmalloc(nvtxs, UNMATCHED, "match");
1570  perm = idxmalloc(nvtxs, "perm");
1571  RandomPermute(nvtxs, perm, 1);
1572 
1573  cnvtxs = 0;
1574  for (ii=0; ii<nvtxs; ii++) {
1575  i = perm[ii];
1576 
1577  if (match[i] == UNMATCHED) { /* Unmatched */
1578  maxidx = i;
1579 
1580  /* Find a random matching, subject to maxvwgt constraints */
1581  for (j=xadj[i]; j<xadj[i+1]; j++) {
1582  if (match[adjncy[j]] == UNMATCHED) {
1583  maxidx = adjncy[j];
1584  break;
1585  }
1586  }
1587 
1588  cmap[i] = cmap[maxidx] = cnvtxs++;
1589  match[i] = maxidx;
1590  match[maxidx] = i;
1591  }
1592  }
1593 
1594  cnedges = ComputeCoarseGraphSize(nvtxs, xadj, adjncy, cnvtxs, cmap, match, perm);
1595 
1596  *vfraction = (1.0*cnvtxs)/(1.0*nvtxs);
1597  *efraction = (1.0*cnedges)/(1.0*xadj[nvtxs]);
1598 
1599  GKfree((void **) &cmap, (void **) &match, (void **) &perm, LTERM);
1600 }
1601 
1602 
1603 
1604 
1605 /*************************************************************************
1606 * This function computes the size of the coarse graph
1607 **************************************************************************/
1608 int ComputeCoarseGraphSize(int nvtxs, idxtype *xadj, idxtype *adjncy, int cnvtxs, idxtype *cmap, idxtype *match, idxtype *perm)
1609 {
1610  int i, j, k, istart, iend, cnedges, v, u;
1611  idxtype *htable;
1612 
1613  htable = idxsmalloc(cnvtxs, -1, "htable");
1614 
1615  cnvtxs = cnedges = 0;
1616  for (i=0; i<nvtxs; i++) {
1617  v = perm[i];
1618  if (cmap[v] != cnvtxs)
1619  continue;
1620 
1621  htable[cnvtxs] = cnvtxs;
1622 
1623  u = match[v];
1624 
1625  istart = xadj[v];
1626  iend = xadj[v+1];
1627  for (j=istart; j<iend; j++) {
1628  k = cmap[adjncy[j]];
1629  if (htable[k] != cnvtxs) {
1630  htable[k] = cnvtxs;
1631  cnedges++;
1632  }
1633  }
1634 
1635  if (v != u) {
1636  istart = xadj[u];
1637  iend = xadj[u+1];
1638  for (j=istart; j<iend; j++) {
1639  k = cmap[adjncy[j]];
1640  if (htable[k] != cnvtxs) {
1641  htable[k] = cnvtxs;
1642  cnedges++;
1643  }
1644  }
1645  }
1646  cnvtxs++;
1647  }
1648 
1649  GKfree((void **) &htable, LTERM);
1650 
1651  return cnedges;
1652 }
1653 
1654 
1655 /*
1656  * Copyright 1997, Regents of the University of Minnesota
1657  *
1658  * fm.c
1659  *
1660  * This file contains code that implements the edge-based FM refinement
1661  *
1662  * Started 7/23/97
1663  * George
1664  *
1665  * $Id$
1666  */
1667 
1668 
1669 
1670 
1671 /*************************************************************************
1672 * This function performs an edge-based FM refinement
1673 **************************************************************************/
1674 void FM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, int *tpwgts, int npasses)
1675 {
1676  int i, ii, j, k, kwgt, nvtxs, nbnd, nswaps, from, to, pass, limit, tmp;
1677  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind, *pwgts;
1678  idxtype *moved, *swaps, *perm;
1679  PQueueType parts[2];
1680  int higain, oldgain, mincut, mindiff, origdiff, initcut, newcut, mincutorder, avgvwgt;
1681 
1682  nvtxs = graph->nvtxs;
1683  xadj = graph->xadj;
1684  vwgt = graph->vwgt;
1685  adjncy = graph->adjncy;
1686  adjwgt = graph->adjwgt;
1687  where = graph->where;
1688  id = graph->id;
1689  ed = graph->ed;
1690  pwgts = graph->pwgts;
1691  bndptr = graph->bndptr;
1692  bndind = graph->bndind;
1693 
1694  moved = idxwspacemalloc(ctrl, nvtxs);
1695  swaps = idxwspacemalloc(ctrl, nvtxs);
1696  perm = idxwspacemalloc(ctrl, nvtxs);
1697 
1698  limit = amin(amax(0.01*nvtxs, 15), 100);
1699  avgvwgt = amin((pwgts[0]+pwgts[1])/20, 2*(pwgts[0]+pwgts[1])/nvtxs);
1700 
1701  tmp = graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)];
1702  PQueueInit(ctrl, &parts[0], nvtxs, tmp);
1703  PQueueInit(ctrl, &parts[1], nvtxs, tmp);
1704 
1705  IFSET(ctrl->dbglvl, DBG_REFINE,
1706  printf("Partitions: [%6d %6d] T[%6d %6d], Nv-Nb[%6d %6d]. ICut: %6d\n",
1707  pwgts[0], pwgts[1], tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
1708 
1709  origdiff = abs(tpwgts[0]-pwgts[0]);
1710  idxset(nvtxs, -1, moved);
1711  for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
1712  PQueueReset(&parts[0]);
1713  PQueueReset(&parts[1]);
1714 
1715  mincutorder = -1;
1716  newcut = mincut = initcut = graph->mincut;
1717  mindiff = abs(tpwgts[0]-pwgts[0]);
1718 
1719  ASSERT(ComputeCut(graph, where) == graph->mincut);
1720  ASSERT(CheckBnd(graph));
1721 
1722  /* Insert boundary nodes in the priority queues */
1723  nbnd = graph->nbnd;
1724  RandomPermute(nbnd, perm, 1);
1725  for (ii=0; ii<nbnd; ii++) {
1726  i = perm[ii];
1727  ASSERT(ed[bndind[i]] > 0 || id[bndind[i]] == 0);
1728  ASSERT(bndptr[bndind[i]] != -1);
1729  PQueueInsert(&parts[where[bndind[i]]], bndind[i], ed[bndind[i]]-id[bndind[i]]);
1730  }
1731 
1732  for (nswaps=0; nswaps<nvtxs; nswaps++) {
1733  from = (tpwgts[0]-pwgts[0] < tpwgts[1]-pwgts[1] ? 0 : 1);
1734  to = (from+1)%2;
1735 
1736  if ((higain = PQueueGetMax(&parts[from])) == -1)
1737  break;
1738  ASSERT(bndptr[higain] != -1);
1739 
1740  newcut -= (ed[higain]-id[higain]);
1741  INC_DEC(pwgts[to], pwgts[from], vwgt[higain]);
1742 
1743  if ((newcut < mincut && abs(tpwgts[0]-pwgts[0]) <= origdiff+avgvwgt) ||
1744  (newcut == mincut && abs(tpwgts[0]-pwgts[0]) < mindiff)) {
1745  mincut = newcut;
1746  mindiff = abs(tpwgts[0]-pwgts[0]);
1747  mincutorder = nswaps;
1748  }
1749  else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
1750  newcut += (ed[higain]-id[higain]);
1751  INC_DEC(pwgts[from], pwgts[to], vwgt[higain]);
1752  break;
1753  }
1754 
1755  where[higain] = to;
1756  moved[higain] = nswaps;
1757  swaps[nswaps] = higain;
1758 
1759  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
1760  printf("Moved %6d from %d. [%3d %3d] %5d [%4d %4d]\n", higain, from, ed[higain]-id[higain], vwgt[higain], newcut, pwgts[0], pwgts[1]));
1761 
1762  /**************************************************************
1763  * Update the id[i]/ed[i] values of the affected nodes
1764  ***************************************************************/
1765  SWAP(id[higain], ed[higain], tmp);
1766  if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
1767  BNDDelete(nbnd, bndind, bndptr, higain);
1768 
1769  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
1770  k = adjncy[j];
1771  oldgain = ed[k]-id[k];
1772 
1773  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
1774  INC_DEC(id[k], ed[k], kwgt);
1775 
1776  /* Update its boundary information and queue position */
1777  if (bndptr[k] != -1) { /* If k was a boundary vertex */
1778  if (ed[k] == 0) { /* Not a boundary vertex any more */
1779  BNDDelete(nbnd, bndind, bndptr, k);
1780  if (moved[k] == -1) /* Remove it if in the queues */
1781  PQueueDelete(&parts[where[k]], k, oldgain);
1782  }
1783  else { /* If it has not been moved, update its position in the queue */
1784  if (moved[k] == -1)
1785  PQueueUpdate(&parts[where[k]], k, oldgain, ed[k]-id[k]);
1786  }
1787  }
1788  else {
1789  if (ed[k] > 0) { /* It will now become a boundary vertex */
1790  BNDInsert(nbnd, bndind, bndptr, k);
1791  if (moved[k] == -1)
1792  PQueueInsert(&parts[where[k]], k, ed[k]-id[k]);
1793  }
1794  }
1795  }
1796 
1797  }
1798 
1799 
1800  /****************************************************************
1801  * Roll back computations
1802  *****************************************************************/
1803  for (i=0; i<nswaps; i++)
1804  moved[swaps[i]] = -1; /* reset moved array */
1805  for (nswaps--; nswaps>mincutorder; nswaps--) {
1806  higain = swaps[nswaps];
1807 
1808  to = where[higain] = (where[higain]+1)%2;
1809  SWAP(id[higain], ed[higain], tmp);
1810  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
1811  BNDDelete(nbnd, bndind, bndptr, higain);
1812  else if (ed[higain] > 0 && bndptr[higain] == -1)
1813  BNDInsert(nbnd, bndind, bndptr, higain);
1814 
1815  INC_DEC(pwgts[to], pwgts[(to+1)%2], vwgt[higain]);
1816  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
1817  k = adjncy[j];
1818 
1819  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
1820  INC_DEC(id[k], ed[k], kwgt);
1821 
1822  if (bndptr[k] != -1 && ed[k] == 0)
1823  BNDDelete(nbnd, bndind, bndptr, k);
1824  if (bndptr[k] == -1 && ed[k] > 0)
1825  BNDInsert(nbnd, bndind, bndptr, k);
1826  }
1827  }
1828 
1829  IFSET(ctrl->dbglvl, DBG_REFINE,
1830  printf("\tMinimum cut: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
1831 
1832  graph->mincut = mincut;
1833  graph->nbnd = nbnd;
1834 
1835  if (mincutorder == -1 || mincut == initcut)
1836  break;
1837  }
1838 
1839  PQueueFree(ctrl, &parts[0]);
1840  PQueueFree(ctrl, &parts[1]);
1841 
1842  idxwspacefree(ctrl, nvtxs);
1843  idxwspacefree(ctrl, nvtxs);
1844  idxwspacefree(ctrl, nvtxs);
1845 
1846 }
1847 
1848 
1849 /*
1850  * Copyright 1997, Regents of the University of Minnesota
1851  *
1852  * fortran.c
1853  *
1854  * This file contains code for the fortran to C interface
1855  *
1856  * Started 8/19/97
1857  * George
1858  *
1859  * $Id$
1860  *
1861  */
1862 
1863 
1864 
1865 
1866 /*************************************************************************
1867 * This function changes the numbering to start from 0 instead of 1
1868 **************************************************************************/
1869 void Change2CNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy)
1870 {
1871  int i, nedges;
1872 
1873  for (i=0; i<=nvtxs; i++)
1874  xadj[i]--;
1875 
1876  nedges = xadj[nvtxs];
1877  for (i=0; i<nedges; i++)
1878  adjncy[i]--;
1879 }
1880 
1881 /*************************************************************************
1882 * This function changes the numbering to start from 1 instead of 0
1883 **************************************************************************/
1884 void Change2FNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vector)
1885 {
1886  int i, nedges;
1887 
1888  for (i=0; i<nvtxs; i++)
1889  vector[i]++;
1890 
1891  nedges = xadj[nvtxs];
1892  for (i=0; i<nedges; i++)
1893  adjncy[i]++;
1894 
1895  for (i=0; i<=nvtxs; i++)
1896  xadj[i]++;
1897 }
1898 
1899 /*************************************************************************
1900 * This function changes the numbering to start from 1 instead of 0
1901 **************************************************************************/
1902 void Change2FNumbering2(int nvtxs, idxtype *xadj, idxtype *adjncy)
1903 {
1904  int i, nedges;
1905 
1906  nedges = xadj[nvtxs];
1907  for (i=0; i<nedges; i++)
1908  adjncy[i]++;
1909 
1910  for (i=0; i<=nvtxs; i++)
1911  xadj[i]++;
1912 }
1913 
1914 
1915 
1916 /*************************************************************************
1917 * This function changes the numbering to start from 1 instead of 0
1918 **************************************************************************/
1919 void Change2FNumberingOrder(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *v1, idxtype *v2)
1920 {
1921  int i, nedges;
1922 
1923  for (i=0; i<nvtxs; i++) {
1924  v1[i]++;
1925  v2[i]++;
1926  }
1927 
1928  nedges = xadj[nvtxs];
1929  for (i=0; i<nedges; i++)
1930  adjncy[i]++;
1931 
1932  for (i=0; i<=nvtxs; i++)
1933  xadj[i]++;
1934 
1935 }
1936 
1937 
1938 
1939 /*************************************************************************
1940 * This function changes the numbering to start from 0 instead of 1
1941 **************************************************************************/
1942 void ChangeMesh2CNumbering(int n, idxtype *mesh)
1943 {
1944  int i;
1945 
1946  for (i=0; i<n; i++)
1947  mesh[i]--;
1948 
1949 }
1950 
1951 
1952 /*************************************************************************
1953 * This function changes the numbering to start from 1 instead of 0
1954 **************************************************************************/
1955 void ChangeMesh2FNumbering(int n, idxtype *mesh, int nvtxs, idxtype *xadj, idxtype *adjncy)
1956 {
1957  int i, nedges;
1958 
1959  for (i=0; i<n; i++)
1960  mesh[i]++;
1961 
1962  nedges = xadj[nvtxs];
1963  for (i=0; i<nedges; i++)
1964  adjncy[i]++;
1965 
1966  for (i=0; i<=nvtxs; i++)
1967  xadj[i]++;
1968 
1969 }
1970 
1971 
1972 /*************************************************************************
1973 * This function changes the numbering to start from 1 instead of 0
1974 **************************************************************************/
1975 void ChangeMesh2FNumbering2(int n, idxtype *mesh, int ne, int nn, idxtype *epart, idxtype *npart)
1976 {
1977  int i;
1978 
1979  for (i=0; i<n; i++)
1980  mesh[i]++;
1981 
1982  for (i=0; i<ne; i++)
1983  epart[i]++;
1984 
1985  for (i=0; i<nn; i++)
1986  npart[i]++;
1987 
1988 }
1989 
1990 /*
1991  * Copyright 1997, Regents of the University of Minnesota
1992  *
1993  * frename.c
1994  *
1995  * This file contains some renaming routines to deal with different Fortran compilers
1996  *
1997  * Started 9/15/97
1998  * George
1999  *
2000  * $Id$
2001  *
2002  */
2003 
2004 
2005 
2006 
2007 void METIS_PARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2008 {
2009  METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2010 }
2011 void metis_partgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2012 {
2013  METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2014 }
2015 void metis_partgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2016 {
2017  METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2018 }
2019 void metis_partgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2020 {
2021  METIS_PartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2022 }
2023 
2024 
2025 void METIS_WPARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2026 {
2027  METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2028 }
2029 void metis_wpartgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2030 {
2031  METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2032 }
2033 void metis_wpartgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2034 {
2035  METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2036 }
2037 void metis_wpartgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2038 {
2039  METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2040 }
2041 
2042 
2043 
2044 void METIS_PARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2045 {
2046  METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2047 }
2048 void metis_partgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2049 {
2050  METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2051 }
2052 void metis_partgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2053 {
2054  METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2055 }
2056 void metis_partgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2057 {
2058  METIS_PartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2059 }
2060 
2061 
2062 
2063 void METIS_WPARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2064 {
2065  METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2066 }
2067 void metis_wpartgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2068 {
2069  METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2070 }
2071 void metis_wpartgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2072 {
2073  METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2074 }
2075 void metis_wpartgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
2076 {
2077  METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, tpwgts, options, edgecut, part);
2078 }
2079 
2080 
2081 
2082 void METIS_EDGEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2083 {
2084  METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2085 }
2086 void metis_edgend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2087 {
2088  METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2089 }
2090 void metis_edgend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2091 {
2092  METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2093 }
2094 void metis_edgend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2095 {
2096  METIS_EdgeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2097 }
2098 
2099 
2100 
2101 void METIS_NODEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2102 {
2103  METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2104 }
2105 void metis_nodend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2106 {
2107  METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2108 }
2109 void metis_nodend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2110 {
2111  METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2112 }
2113 void metis_nodend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2114 {
2115  METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
2116 }
2117 
2118 
2119 
2120 void METIS_NODEWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2121 {
2122  METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
2123 }
2124 void metis_nodewnd(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2125 {
2126  METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
2127 }
2128 void metis_nodewnd_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2129 {
2130  METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
2131 }
2132 void metis_nodewnd__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
2133 {
2134  METIS_NodeWND(nvtxs, xadj, adjncy, vwgt, numflag, options, perm, iperm);
2135 }
2136 
2137 
2138 
2139 void METIS_PARTMESHNODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2140 {
2141  METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2142 }
2143 void metis_partmeshnodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2144 {
2145  METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2146 }
2147 void metis_partmeshnodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2148 {
2149  METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2150 }
2151 void metis_partmeshnodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2152 {
2153  METIS_PartMeshNodal(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2154 }
2155 
2156 
2157 void METIS_PARTMESHDUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2158 {
2159  METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2160 }
2161 void metis_partmeshdual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2162 {
2163  METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2164 }
2165 void metis_partmeshdual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2166 {
2167  METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2168 }
2169 void metis_partmeshdual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
2170 {
2171  METIS_PartMeshDual(ne, nn, elmnts, etype, numflag, nparts, edgecut, epart, npart);
2172 }
2173 
2174 
2175 void METIS_MESHTONODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2176 {
2177  METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2178 }
2179 void metis_meshtonodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2180 {
2181  METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2182 }
2183 void metis_meshtonodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2184 {
2185  METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2186 }
2187 void metis_meshtonodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2188 {
2189  METIS_MeshToNodal(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2190 }
2191 
2192 
2193 void METIS_MESHTODUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2194 {
2195  METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2196 }
2197 void metis_meshtodual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2198 {
2199  METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2200 }
2201 void metis_meshtodual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2202 {
2203  METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2204 }
2205 void metis_meshtodual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
2206 {
2207  METIS_MeshToDual(ne, nn, elmnts, etype, numflag, dxadj, dadjncy);
2208 }
2209 
2210 
2211 void METIS_ESTIMATEMEMORY(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
2212 {
2213  METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
2214 }
2215 void metis_estimatememory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
2216 {
2217  METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
2218 }
2219 void metis_estimatememory_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
2220 {
2221  METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
2222 }
2223 void metis_estimatememory__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
2224 {
2225  METIS_EstimateMemory(nvtxs, xadj, adjncy, numflag, optype, nbytes);
2226 }
2227 
2228 
2229 
2230 void METIS_MCPARTGRAPHRECURSIVE(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2231 {
2232  METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2233 }
2234 void metis_mcpartgraphrecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2235 {
2236  METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2237 }
2238 void metis_mcpartgraphrecursive_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2239 {
2240  METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2241 }
2242 void metis_mcpartgraphrecursive__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
2243 {
2244  METIS_mCPartGraphRecursive(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, options, edgecut, part);
2245 }
2246 
2247 
2248 void METIS_MCPARTGRAPHKWAY(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
2249 {
2250  METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
2251 }
2252 void metis_mcpartgraphkway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
2253 {
2254  METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
2255 }
2256 void metis_mcpartgraphkway_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
2257 {
2258  METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
2259 }
2260 void metis_mcpartgraphkway__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
2261 {
2262  METIS_mCPartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts, rubvec, options, edgecut, part);
2263 }
2264 
2265 
2266 void METIS_PARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
2267 {
2268  METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
2269 }
2270 void metis_partgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
2271 {
2272  METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
2273 }
2274 void metis_partgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
2275 {
2276  METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
2277 }
2278 void metis_partgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
2279 {
2280  METIS_PartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, options, volume, part);
2281 }
2282 
2283 void METIS_WPARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
2284 {
2285  METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
2286 }
2287 void metis_wpartgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
2288 {
2289  METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
2290 }
2291 void metis_wpartgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
2292 {
2293  METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
2294 }
2295 void metis_wpartgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
2296 {
2297  METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts, tpwgts, options, volume, part);
2298 }
2299 
2300 
2301 
2302 /*
2303  * Copyright 1997, Regents of the University of Minnesota
2304  *
2305  * graph.c
2306  *
2307  * This file contains functions that deal with setting up the graphs
2308  * for METIS.
2309  *
2310  * Started 7/25/97
2311  * George
2312  *
2313  * $Id$
2314  *
2315  */
2316 
2317 
2318 
2319 /*************************************************************************
2320 * This function sets up the graph from the user input
2321 **************************************************************************/
2322 void SetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon,
2323  idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int wgtflag)
2324 {
2325  int i, j, sum, gsize;
2326  float *nvwgt;
2327  idxtype tvwgt[MAXNCON];
2328 
2329  if (OpType == OP_KMETIS && ncon == 1 && (wgtflag&2) == 0 && (wgtflag&1) == 0) {
2330  SetUpGraphKway(graph, nvtxs, xadj, adjncy);
2331  return;
2332  }
2333 
2334  InitGraph(graph);
2335 
2336  graph->nvtxs = nvtxs;
2337  graph->nedges = xadj[nvtxs];
2338  graph->ncon = ncon;
2339  graph->xadj = xadj;
2340  graph->adjncy = adjncy;
2341 
2342  if (ncon == 1) { /* We are in the non mC mode */
2343  gsize = 0;
2344  if ((wgtflag&2) == 0)
2345  gsize += nvtxs;
2346  if ((wgtflag&1) == 0)
2347  gsize += graph->nedges;
2348 
2349  gsize += 2*nvtxs;
2350 
2351  graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
2352 
2353  /* Create the vertex/edge weight vectors if they are not supplied */
2354  gsize = 0;
2355  if ((wgtflag&2) == 0) {
2356  vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata);
2357  gsize += nvtxs;
2358  }
2359  else
2360  graph->vwgt = vwgt;
2361 
2362  if ((wgtflag&1) == 0) {
2363  adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize);
2364  gsize += graph->nedges;
2365  }
2366  else
2367  graph->adjwgt = adjwgt;
2368 
2369 
2370  /* Compute the initial values of the adjwgtsum */
2371  graph->adjwgtsum = graph->gdata + gsize;
2372  gsize += nvtxs;
2373 
2374  for (i=0; i<nvtxs; i++) {
2375  sum = 0;
2376  for (j=xadj[i]; j<xadj[i+1]; j++)
2377  sum += adjwgt[j];
2378  graph->adjwgtsum[i] = sum;
2379  }
2380 
2381  graph->cmap = graph->gdata + gsize;
2382  gsize += nvtxs;
2383 
2384  }
2385  else { /* Set up the graph in MOC mode */
2386  gsize = 0;
2387  if ((wgtflag&1) == 0)
2388  gsize += graph->nedges;
2389 
2390  gsize += 2*nvtxs;
2391 
2392  graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
2393  gsize = 0;
2394 
2395  for (i=0; i<ncon; i++)
2396  tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon);
2397 
2398  nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt");
2399 
2400  for (i=0; i<nvtxs; i++) {
2401  for (j=0; j<ncon; j++)
2402  nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]);
2403  }
2404 
2405 
2406  /* Create the edge weight vectors if they are not supplied */
2407  if ((wgtflag&1) == 0) {
2408  adjwgt = graph->adjwgt = idxset(graph->nedges, 1, graph->gdata+gsize);
2409  gsize += graph->nedges;
2410  }
2411  else
2412  graph->adjwgt = adjwgt;
2413 
2414  /* Compute the initial values of the adjwgtsum */
2415  graph->adjwgtsum = graph->gdata + gsize;
2416  gsize += nvtxs;
2417 
2418  for (i=0; i<nvtxs; i++) {
2419  sum = 0;
2420  for (j=xadj[i]; j<xadj[i+1]; j++)
2421  sum += adjwgt[j];
2422  graph->adjwgtsum[i] = sum;
2423  }
2424 
2425  graph->cmap = graph->gdata + gsize;
2426  gsize += nvtxs;
2427 
2428  }
2429 
2430  if (OpType != OP_KMETIS && OpType != OP_KVMETIS) {
2431  graph->label = idxmalloc(nvtxs, "SetUpGraph: label");
2432 
2433  for (i=0; i<nvtxs; i++)
2434  graph->label[i] = i;
2435  }
2436 
2437 }
2438 
2439 
2440 /*************************************************************************
2441 * This function sets up the graph from the user input
2442 **************************************************************************/
2443 void SetUpGraphKway(GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy)
2444 {
2445  int i;
2446 
2447  InitGraph(graph);
2448 
2449  graph->nvtxs = nvtxs;
2450  graph->nedges = xadj[nvtxs];
2451  graph->ncon = 1;
2452  graph->xadj = xadj;
2453  graph->vwgt = NULL;
2454  graph->adjncy = adjncy;
2455  graph->adjwgt = NULL;
2456 
2457  graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata");
2458  graph->adjwgtsum = graph->gdata;
2459  graph->cmap = graph->gdata + nvtxs;
2460 
2461  /* Compute the initial values of the adjwgtsum */
2462  for (i=0; i<nvtxs; i++)
2463  graph->adjwgtsum[i] = xadj[i+1]-xadj[i];
2464 
2465 }
2466 
2467 
2468 
2469 /*************************************************************************
2470 * This function sets up the graph from the user input
2471 **************************************************************************/
2472 void SetUpGraph2(GraphType *graph, int nvtxs, int ncon, idxtype *xadj,
2473  idxtype *adjncy, float *nvwgt, idxtype *adjwgt)
2474 {
2475  int i, j, sum;
2476 
2477  InitGraph(graph);
2478 
2479  graph->nvtxs = nvtxs;
2480  graph->nedges = xadj[nvtxs];
2481  graph->ncon = ncon;
2482  graph->xadj = xadj;
2483  graph->adjncy = adjncy;
2484  graph->adjwgt = adjwgt;
2485 
2486  graph->nvwgt = fmalloc(nvtxs*ncon, "SetUpGraph2: graph->nvwgt");
2487  scopy(nvtxs*ncon, nvwgt, graph->nvwgt);
2488 
2489  graph->gdata = idxmalloc(2*nvtxs, "SetUpGraph: gdata");
2490 
2491  /* Compute the initial values of the adjwgtsum */
2492  graph->adjwgtsum = graph->gdata;
2493  for (i=0; i<nvtxs; i++) {
2494  sum = 0;
2495  for (j=xadj[i]; j<xadj[i+1]; j++)
2496  sum += adjwgt[j];
2497  graph->adjwgtsum[i] = sum;
2498  }
2499 
2500  graph->cmap = graph->gdata+nvtxs;
2501 
2502  graph->label = idxmalloc(nvtxs, "SetUpGraph: label");
2503  for (i=0; i<nvtxs; i++)
2504  graph->label[i] = i;
2505 
2506 }
2507 
2508 
2509 /*************************************************************************
2510 * This function sets up the graph from the user input
2511 **************************************************************************/
2512 void VolSetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, idxtype *xadj,
2513  idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int wgtflag)
2514 {
2515  int i, j, sum, gsize;
2516  idxtype *adjwgt;
2517  float *nvwgt;
2518  idxtype tvwgt[MAXNCON];
2519 
2520  InitGraph(graph);
2521 
2522  graph->nvtxs = nvtxs;
2523  graph->nedges = xadj[nvtxs];
2524  graph->ncon = ncon;
2525  graph->xadj = xadj;
2526  graph->adjncy = adjncy;
2527 
2528  if (ncon == 1) { /* We are in the non mC mode */
2529  gsize = graph->nedges; /* This is for the edge weights */
2530  if ((wgtflag&2) == 0)
2531  gsize += nvtxs; /* vwgts */
2532  if ((wgtflag&1) == 0)
2533  gsize += nvtxs; /* vsize */
2534 
2535  gsize += 2*nvtxs;
2536 
2537  graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
2538 
2539  /* Create the vertex/edge weight vectors if they are not supplied */
2540  gsize = 0;
2541  if ((wgtflag&2) == 0) {
2542  vwgt = graph->vwgt = idxset(nvtxs, 1, graph->gdata);
2543  gsize += nvtxs;
2544  }
2545  else
2546  graph->vwgt = vwgt;
2547 
2548  if ((wgtflag&1) == 0) {
2549  vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata);
2550  gsize += nvtxs;
2551  }
2552  else
2553  graph->vsize = vsize;
2554 
2555  /* Allocate memory for edge weights and initialize them to the sum of the vsize */
2556  adjwgt = graph->adjwgt = graph->gdata+gsize;
2557  gsize += graph->nedges;
2558 
2559  for (i=0; i<nvtxs; i++) {
2560  for (j=xadj[i]; j<xadj[i+1]; j++)
2561  adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]];
2562  }
2563 
2564 
2565  /* Compute the initial values of the adjwgtsum */
2566  graph->adjwgtsum = graph->gdata + gsize;
2567  gsize += nvtxs;
2568 
2569  for (i=0; i<nvtxs; i++) {
2570  sum = 0;
2571  for (j=xadj[i]; j<xadj[i+1]; j++)
2572  sum += adjwgt[j];
2573  graph->adjwgtsum[i] = sum;
2574  }
2575 
2576  graph->cmap = graph->gdata + gsize;
2577  gsize += nvtxs;
2578 
2579  }
2580  else { /* Set up the graph in MOC mode */
2581  gsize = graph->nedges;
2582  if ((wgtflag&1) == 0)
2583  gsize += nvtxs;
2584 
2585  gsize += 2*nvtxs;
2586 
2587  graph->gdata = idxmalloc(gsize, "SetUpGraph: gdata");
2588  gsize = 0;
2589 
2590  /* Create the normalized vertex weights along each constrain */
2591  if ((wgtflag&2) == 0)
2592  vwgt = idxsmalloc(nvtxs, 1, "SetUpGraph: vwgt");
2593 
2594  for (i=0; i<ncon; i++)
2595  tvwgt[i] = idxsum_strd(nvtxs, vwgt+i, ncon);
2596 
2597  nvwgt = graph->nvwgt = fmalloc(ncon*nvtxs, "SetUpGraph: nvwgt");
2598 
2599  for (i=0; i<nvtxs; i++) {
2600  for (j=0; j<ncon; j++)
2601  nvwgt[i*ncon+j] = (1.0*vwgt[i*ncon+j])/(1.0*tvwgt[j]);
2602  }
2603  if ((wgtflag&2) == 0)
2604  free(vwgt);
2605 
2606 
2607  /* Create the vsize vector if it is not supplied */
2608  if ((wgtflag&1) == 0) {
2609  vsize = graph->vsize = idxset(nvtxs, 1, graph->gdata);
2610  gsize += nvtxs;
2611  }
2612  else
2613  graph->vsize = vsize;
2614 
2615  /* Allocate memory for edge weights and initialize them to the sum of the vsize */
2616  adjwgt = graph->adjwgt = graph->gdata+gsize;
2617  gsize += graph->nedges;
2618 
2619  for (i=0; i<nvtxs; i++) {
2620  for (j=xadj[i]; j<xadj[i+1]; j++)
2621  adjwgt[j] = 1+vsize[i]+vsize[adjncy[j]];
2622  }
2623 
2624  /* Compute the initial values of the adjwgtsum */
2625  graph->adjwgtsum = graph->gdata + gsize;
2626  gsize += nvtxs;
2627 
2628  for (i=0; i<nvtxs; i++) {
2629  sum = 0;
2630  for (j=xadj[i]; j<xadj[i+1]; j++)
2631  sum += adjwgt[j];
2632  graph->adjwgtsum[i] = sum;
2633  }
2634 
2635  graph->cmap = graph->gdata + gsize;
2636  gsize += nvtxs;
2637 
2638  }
2639 
2640  if (OpType != OP_KVMETIS) {
2641  graph->label = idxmalloc(nvtxs, "SetUpGraph: label");
2642 
2643  for (i=0; i<nvtxs; i++)
2644  graph->label[i] = i;
2645  }
2646 
2647 }
2648 
2649 
2650 /*************************************************************************
2651 * This function randomly permutes the adjacency lists of a graph
2652 **************************************************************************/
2654 {
2655  int i, j, k, l, tmp, nvtxs;
2656  idxtype *xadj, *adjncy, *adjwgt;
2657 
2658  nvtxs = graph->nvtxs;
2659  xadj = graph->xadj;
2660  adjncy = graph->adjncy;
2661  adjwgt = graph->adjwgt;
2662 
2663  for (i=0; i<nvtxs; i++) {
2664  l = xadj[i+1]-xadj[i];
2665  for (j=xadj[i]; j<xadj[i+1]; j++) {
2666  k = xadj[i] + RandomInRange(l);
2667  SWAP(adjncy[j], adjncy[k], tmp);
2668  SWAP(adjwgt[j], adjwgt[k], tmp);
2669  }
2670  }
2671 }
2672 
2673 
2674 /*************************************************************************
2675 * This function checks whether or not partition pid is contigous
2676 **************************************************************************/
2677 int IsConnectedSubdomain(CtrlType *ctrl, GraphType *graph, int pid, int report)
2678 {
2679  int i, j, k, nvtxs, first, last, nleft, ncmps, wgt;
2680  idxtype *xadj, *adjncy, *where, *touched, *queue;
2681  idxtype *cptr;
2682 
2683  nvtxs = graph->nvtxs;
2684  xadj = graph->xadj;
2685  adjncy = graph->adjncy;
2686  where = graph->where;
2687 
2688  touched = idxsmalloc(nvtxs, 0, "IsConnected: touched");
2689  queue = idxmalloc(nvtxs, "IsConnected: queue");
2690  cptr = idxmalloc(nvtxs, "IsConnected: cptr");
2691 
2692  nleft = 0;
2693  for (i=0; i<nvtxs; i++) {
2694  if (where[i] == pid)
2695  nleft++;
2696  }
2697 
2698  for (i=0; i<nvtxs; i++) {
2699  if (where[i] == pid)
2700  break;
2701  }
2702 
2703  touched[i] = 1;
2704  queue[0] = i;
2705  first = 0; last = 1;
2706 
2707  cptr[0] = 0; /* This actually points to queue */
2708  ncmps = 0;
2709  while (first != nleft) {
2710  if (first == last) { /* Find another starting vertex */
2711  cptr[++ncmps] = first;
2712  for (i=0; i<nvtxs; i++) {
2713  if (where[i] == pid && !touched[i])
2714  break;
2715  }
2716  queue[last++] = i;
2717  touched[i] = 1;
2718  }
2719 
2720  i = queue[first++];
2721  for (j=xadj[i]; j<xadj[i+1]; j++) {
2722  k = adjncy[j];
2723  if (where[k] == pid && !touched[k]) {
2724  queue[last++] = k;
2725  touched[k] = 1;
2726  }
2727  }
2728  }
2729  cptr[++ncmps] = first;
2730 
2731  if (ncmps > 1 && report) {
2732  printf("The graph has %d connected components in partition %d:\t", ncmps, pid);
2733  for (i=0; i<ncmps; i++) {
2734  wgt = 0;
2735  for (j=cptr[i]; j<cptr[i+1]; j++)
2736  wgt += graph->vwgt[queue[j]];
2737  printf("[%5d %5d] ", cptr[i+1]-cptr[i], wgt);
2738  /*
2739  if (cptr[i+1]-cptr[i] == 1)
2740  printf("[%d %d] ", queue[cptr[i]], xadj[queue[cptr[i]]+1]-xadj[queue[cptr[i]]]);
2741  */
2742  }
2743  printf("\n");
2744  }
2745 
2746  GKfree((void **) &touched, (void **) &queue, (void **) &cptr, LTERM);
2747 
2748  return (ncmps == 1 ? 1 : 0);
2749 }
2750 
2751 
2752 /*************************************************************************
2753 * This function checks whether a graph is contigous or not
2754 **************************************************************************/
2755 int IsConnected(CtrlType *ctrl, GraphType *graph, int report)
2756 {
2757  int i, j, k, nvtxs, first, last;
2758  idxtype *xadj, *adjncy, *touched, *queue;
2759 
2760  nvtxs = graph->nvtxs;
2761  xadj = graph->xadj;
2762  adjncy = graph->adjncy;
2763 
2764  touched = idxsmalloc(nvtxs, 0, "IsConnected: touched");
2765  queue = idxmalloc(nvtxs, "IsConnected: queue");
2766 
2767  touched[0] = 1;
2768  queue[0] = 0;
2769  first = 0; last = 1;
2770 
2771  while (first < last) {
2772  i = queue[first++];
2773  for (j=xadj[i]; j<xadj[i+1]; j++) {
2774  k = adjncy[j];
2775  if (!touched[k]) {
2776  queue[last++] = k;
2777  touched[k] = 1;
2778  }
2779  }
2780  }
2781 
2782  if (first != nvtxs && report)
2783  printf("The graph is not connected. It has %d disconnected vertices!\n", nvtxs-first);
2784 
2785  return (first == nvtxs ? 1 : 0);
2786 }
2787 
2788 
2789 /*************************************************************************
2790 * This function checks whether or not partition pid is contigous
2791 **************************************************************************/
2792 int IsConnected2(GraphType *graph, int report)
2793 {
2794  int i, j, k, nvtxs, first, last, nleft, ncmps;
2795  idxtype *xadj, *adjncy, *where, *touched, *queue;
2796  idxtype *cptr;
2797 
2798  nvtxs = graph->nvtxs;
2799  xadj = graph->xadj;
2800  adjncy = graph->adjncy;
2801  where = graph->where;
2802 
2803  touched = idxsmalloc(nvtxs, 0, "IsConnected: touched");
2804  queue = idxmalloc(nvtxs, "IsConnected: queue");
2805  cptr = idxmalloc(nvtxs, "IsConnected: cptr");
2806 
2807  nleft = nvtxs;
2808  touched[0] = 1;
2809  queue[0] = 0;
2810  first = 0; last = 1;
2811 
2812  cptr[0] = 0; /* This actually points to queue */
2813  ncmps = 0;
2814  while (first != nleft) {
2815  if (first == last) { /* Find another starting vertex */
2816  cptr[++ncmps] = first;
2817  for (i=0; i<nvtxs; i++) {
2818  if (!touched[i])
2819  break;
2820  }
2821  queue[last++] = i;
2822  touched[i] = 1;
2823  }
2824 
2825  i = queue[first++];
2826  for (j=xadj[i]; j<xadj[i+1]; j++) {
2827  k = adjncy[j];
2828  if (!touched[k]) {
2829  queue[last++] = k;
2830  touched[k] = 1;
2831  }
2832  }
2833  }
2834  cptr[++ncmps] = first;
2835 
2836  if (ncmps > 1 && report) {
2837  printf("%d connected components:\t", ncmps);
2838  for (i=0; i<ncmps; i++) {
2839  if (cptr[i+1]-cptr[i] > 200)
2840  printf("[%5d] ", cptr[i+1]-cptr[i]);
2841  }
2842  printf("\n");
2843  }
2844 
2845  GKfree((void **) &touched, (void **) &queue, (void **) &cptr, LTERM);
2846 
2847  return (ncmps == 1 ? 1 : 0);
2848 }
2849 
2850 
2851 /*************************************************************************
2852 * This function returns the number of connected components in cptr,cind
2853 * The separator of the graph is used to split it and then find its components.
2854 **************************************************************************/
2855 int FindComponents(CtrlType *ctrl, GraphType *graph, idxtype *cptr, idxtype *cind)
2856 {
2857  int i, j, k, nvtxs, first, last, nleft, ncmps;
2858  idxtype *xadj, *adjncy, *where, *touched, *queue;
2859 
2860  nvtxs = graph->nvtxs;
2861  xadj = graph->xadj;
2862  adjncy = graph->adjncy;
2863  where = graph->where;
2864 
2865  touched = idxsmalloc(nvtxs, 0, "IsConnected: queue");
2866 
2867  for (i=0; i<graph->nbnd; i++)
2868  touched[graph->bndind[i]] = 1;
2869 
2870  queue = cind;
2871 
2872  nleft = 0;
2873  for (i=0; i<nvtxs; i++) {
2874  if (where[i] != 2)
2875  nleft++;
2876  }
2877 
2878  for (i=0; i<nvtxs; i++) {
2879  if (where[i] != 2)
2880  break;
2881  }
2882 
2883  touched[i] = 1;
2884  queue[0] = i;
2885  first = 0; last = 1;
2886 
2887  cptr[0] = 0; /* This actually points to queue */
2888  ncmps = 0;
2889  while (first != nleft) {
2890  if (first == last) { /* Find another starting vertex */
2891  cptr[++ncmps] = first;
2892  for (i=0; i<nvtxs; i++) {
2893  if (!touched[i])
2894  break;
2895  }
2896  queue[last++] = i;
2897  touched[i] = 1;
2898  }
2899 
2900  i = queue[first++];
2901  for (j=xadj[i]; j<xadj[i+1]; j++) {
2902  k = adjncy[j];
2903  if (!touched[k]) {
2904  queue[last++] = k;
2905  touched[k] = 1;
2906  }
2907  }
2908  }
2909  cptr[++ncmps] = first;
2910 
2911  free(touched);
2912 
2913  return ncmps;
2914 }
2915 
2916 
2917 
2918 /*
2919  * Copyright 1997, Regents of the University of Minnesota
2920  *
2921  * initpart.c
2922  *
2923  * This file contains code that performs the initial partition of the
2924  * coarsest graph
2925  *
2926  * Started 7/23/97
2927  * George
2928  *
2929  * $Id$
2930  *
2931  */
2932 
2933 
2934 
2935 /*************************************************************************
2936 * This function computes the initial bisection of the coarsest graph
2937 **************************************************************************/
2938 void Init2WayPartition(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
2939 {
2940  int dbglvl;
2941 
2942  dbglvl = ctrl->dbglvl;
2943  IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
2944  IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
2945 
2946  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
2947 
2948  switch (ctrl->IType) {
2949  case IPART_GGPKL:
2950  GrowBisection(ctrl, graph, tpwgts, ubfactor);
2951  break;
2952  case 3:
2953  RandomBisection(ctrl, graph, tpwgts, ubfactor);
2954  break;
2955  default:
2956  errexit("Unknown initial partition type: %d\n", ctrl->IType);
2957  }
2958 
2959  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut));
2960  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
2961  ctrl->dbglvl = dbglvl;
2962 
2963 /*
2964  IsConnectedSubdomain(ctrl, graph, 0);
2965  IsConnectedSubdomain(ctrl, graph, 1);
2966 */
2967 }
2968 
2969 /*************************************************************************
2970 * This function computes the initial bisection of the coarsest graph
2971 **************************************************************************/
2972 void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
2973 {
2974  int dbglvl;
2975 
2976  dbglvl = ctrl->dbglvl;
2977  IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
2978  IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
2979 
2980  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
2981 
2982  GrowBisectionNode(ctrl, graph, ubfactor);
2983  Compute2WayNodePartitionParams(ctrl, graph);
2984 
2985  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Sep: %d\n", graph->mincut));
2986  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
2987 
2988  ctrl->dbglvl = dbglvl;
2989 
2990 }
2991 
2992 
2993 
2994 /*************************************************************************
2995 * This function takes a graph and produces a bisection by using a region
2996 * growing algorithm. The resulting partition is returned in
2997 * graph->where
2998 **************************************************************************/
2999 void GrowBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
3000 {
3001  int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], minpwgt[2], maxpwgt[2], bestcut, nbfs;
3002  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where;
3003  idxtype *queue, *touched, *bestwhere;
3004 
3005 
3006  nvtxs = graph->nvtxs;
3007  xadj = graph->xadj;
3008  vwgt = graph->vwgt;
3009  adjncy = graph->adjncy;
3010  adjwgt = graph->adjwgt;
3011 
3012  Allocate2WayPartitionMemory(ctrl, graph);
3013  where = graph->where;
3014 
3015  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
3016  queue = idxmalloc(nvtxs, "BisectGraph: queue");
3017  touched = idxmalloc(nvtxs, "BisectGraph: touched");
3018 
3019  ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt)));
3020 
3021  maxpwgt[0] = ubfactor*tpwgts[0];
3022  maxpwgt[1] = ubfactor*tpwgts[1];
3023  minpwgt[0] = (1.0/ubfactor)*tpwgts[0];
3024  minpwgt[1] = (1.0/ubfactor)*tpwgts[1];
3025 
3026  nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
3027  bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */
3028  for (; nbfs>0; nbfs--) {
3029  idxset(nvtxs, 0, touched);
3030 
3031  pwgts[1] = tpwgts[0]+tpwgts[1];
3032  pwgts[0] = 0;
3033 
3034  idxset(nvtxs, 1, where);
3035 
3036  queue[0] = RandomInRange(nvtxs);
3037  touched[queue[0]] = 1;
3038  first = 0; last = 1;
3039  nleft = nvtxs-1;
3040  drain = 0;
3041 
3042  /* Start the BFS from queue to get a partition */
3043  for (;;) {
3044  if (first == last) { /* Empty. Disconnected graph! */
3045  if (nleft == 0 || drain)
3046  break;
3047 
3048  k = RandomInRange(nleft);
3049  for (i=0; i<nvtxs; i++) {
3050  if (touched[i] == 0) {
3051  if (k == 0)
3052  break;
3053  else
3054  k--;
3055  }
3056  }
3057 
3058  queue[0] = i;
3059  touched[i] = 1;
3060  first = 0; last = 1;;
3061  nleft--;
3062  }
3063 
3064  i = queue[first++];
3065  if (pwgts[0] > 0 && pwgts[1]-vwgt[i] < minpwgt[1]) {
3066  drain = 1;
3067  continue;
3068  }
3069 
3070  where[i] = 0;
3071  INC_DEC(pwgts[0], pwgts[1], vwgt[i]);
3072  if (pwgts[1] <= maxpwgt[1])
3073  break;
3074 
3075  drain = 0;
3076  for (j=xadj[i]; j<xadj[i+1]; j++) {
3077  k = adjncy[j];
3078  if (touched[k] == 0) {
3079  queue[last++] = k;
3080  touched[k] = 1;
3081  nleft--;
3082  }
3083  }
3084  }
3085 
3086  /* Check to see if we hit any bad limiting cases */
3087  if (pwgts[1] == 0) {
3088  i = RandomInRange(nvtxs);
3089  where[i] = 1;
3090  INC_DEC(pwgts[1], pwgts[0], vwgt[i]);
3091  }
3092 
3093  /*************************************************************
3094  * Do some partition refinement
3095  **************************************************************/
3096  Compute2WayPartitionParams(ctrl, graph);
3097  /*printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */
3098 
3099  Balance2Way(ctrl, graph, tpwgts, ubfactor);
3100  /*printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/
3101 
3102  FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
3103  /*printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut);*/
3104 
3105  if (bestcut > graph->mincut) {
3106  bestcut = graph->mincut;
3107  idxcopy(nvtxs, where, bestwhere);
3108  if (bestcut == 0)
3109  break;
3110  }
3111  }
3112 
3113  graph->mincut = bestcut;
3114  idxcopy(nvtxs, bestwhere, where);
3115 
3116  GKfree((void **) &bestwhere, (void **) &queue, (void **) &touched, LTERM);
3117 }
3118 
3119 
3120 
3121 
3122 /*************************************************************************
3123 * This function takes a graph and produces a bisection by using a region
3124 * growing algorithm. The resulting partition is returned in
3125 * graph->where
3126 **************************************************************************/
3127 void GrowBisectionNode(CtrlType *ctrl, GraphType *graph, float ubfactor)
3128 {
3129  int i, j, k, nvtxs, drain, nleft, first, last, pwgts[2], tpwgts[2], minpwgt[2], maxpwgt[2], bestcut, nbfs;
3130  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where, *bndind;
3131  idxtype *queue, *touched, *bestwhere;
3132 
3133  nvtxs = graph->nvtxs;
3134  xadj = graph->xadj;
3135  vwgt = graph->vwgt;
3136  adjncy = graph->adjncy;
3137  adjwgt = graph->adjwgt;
3138 
3139  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
3140  queue = idxmalloc(nvtxs, "BisectGraph: queue");
3141  touched = idxmalloc(nvtxs, "BisectGraph: touched");
3142 
3143  tpwgts[0] = idxsum(nvtxs, vwgt);
3144  tpwgts[1] = tpwgts[0]/2;
3145  tpwgts[0] -= tpwgts[1];
3146 
3147  maxpwgt[0] = ubfactor*tpwgts[0];
3148  maxpwgt[1] = ubfactor*tpwgts[1];
3149  minpwgt[0] = (1.0/ubfactor)*tpwgts[0];
3150  minpwgt[1] = (1.0/ubfactor)*tpwgts[1];
3151 
3152  /* Allocate memory for graph->rdata. Allocate sufficient memory for both edge and node */
3153  graph->rdata = idxmalloc(5*nvtxs+3, "GrowBisectionNode: graph->rdata");
3154  graph->pwgts = graph->rdata;
3155  graph->where = graph->rdata + 3;
3156  graph->bndptr = graph->rdata + nvtxs + 3;
3157  graph->bndind = graph->rdata + 2*nvtxs + 3;
3158  graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3);
3159  graph->id = graph->rdata + 3*nvtxs + 3;
3160  graph->ed = graph->rdata + 4*nvtxs + 3;
3161 
3162  where = graph->where;
3163  bndind = graph->bndind;
3164 
3165  nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
3166  bestcut = tpwgts[0]+tpwgts[1];
3167  for (nbfs++; nbfs>0; nbfs--) {
3168  idxset(nvtxs, 0, touched);
3169 
3170  pwgts[1] = tpwgts[0]+tpwgts[1];
3171  pwgts[0] = 0;
3172 
3173  idxset(nvtxs, 1, where);
3174 
3175  queue[0] = RandomInRange(nvtxs);
3176  touched[queue[0]] = 1;
3177  first = 0; last = 1;
3178  nleft = nvtxs-1;
3179  drain = 0;
3180 
3181  /* Start the BFS from queue to get a partition */
3182  if (nbfs >= 1) {
3183  for (;;) {
3184  if (first == last) { /* Empty. Disconnected graph! */
3185  if (nleft == 0 || drain)
3186  break;
3187 
3188  k = RandomInRange(nleft);
3189  for (i=0; i<nvtxs; i++) {
3190  if (touched[i] == 0) {
3191  if (k == 0)
3192  break;
3193  else
3194  k--;
3195  }
3196  }
3197 
3198  queue[0] = i;
3199  touched[i] = 1;
3200  first = 0; last = 1;;
3201  nleft--;
3202  }
3203 
3204  i = queue[first++];
3205  if (pwgts[1]-vwgt[i] < minpwgt[1]) {
3206  drain = 1;
3207  continue;
3208  }
3209 
3210  where[i] = 0;
3211  INC_DEC(pwgts[0], pwgts[1], vwgt[i]);
3212  if (pwgts[1] <= maxpwgt[1])
3213  break;
3214 
3215  drain = 0;
3216  for (j=xadj[i]; j<xadj[i+1]; j++) {
3217  k = adjncy[j];
3218  if (touched[k] == 0) {
3219  queue[last++] = k;
3220  touched[k] = 1;
3221  nleft--;
3222  }
3223  }
3224  }
3225  }
3226 
3227  /*************************************************************
3228  * Do some partition refinement
3229  **************************************************************/
3230  Compute2WayPartitionParams(ctrl, graph);
3231  Balance2Way(ctrl, graph, tpwgts, ubfactor);
3232  FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
3233 
3234  /* Construct and refine the vertex separator */
3235  for (i=0; i<graph->nbnd; i++)
3236  where[bndind[i]] = 2;
3237 
3238  Compute2WayNodePartitionParams(ctrl, graph);
3239  FM_2WayNodeRefine(ctrl, graph, ubfactor, 6);
3240 
3241  /* printf("ISep: [%d %d %d] %d\n", graph->pwgts[0], graph->pwgts[1], graph->pwgts[2], bestcut); */
3242 
3243  if (bestcut > graph->mincut) {
3244  bestcut = graph->mincut;
3245  idxcopy(nvtxs, where, bestwhere);
3246  }
3247  }
3248 
3249  graph->mincut = bestcut;
3250  idxcopy(nvtxs, bestwhere, where);
3251 
3252  Compute2WayNodePartitionParams(ctrl, graph);
3253 
3254  GKfree((void **) &bestwhere, (void **) &queue, (void **) &touched, LTERM);
3255 }
3256 
3257 
3258 /*************************************************************************
3259 * This function takes a graph and produces a bisection by using a region
3260 * growing algorithm. The resulting partition is returned in
3261 * graph->where
3262 **************************************************************************/
3263 void RandomBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
3264 {
3265  int i, ii, nvtxs, pwgts[2], minpwgt[2], maxpwgt[2], bestcut, nbfs;
3266  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *where;
3267  idxtype *perm, *bestwhere;
3268 
3269  nvtxs = graph->nvtxs;
3270  xadj = graph->xadj;
3271  vwgt = graph->vwgt;
3272  adjncy = graph->adjncy;
3273  adjwgt = graph->adjwgt;
3274 
3275  Allocate2WayPartitionMemory(ctrl, graph);
3276  where = graph->where;
3277 
3278  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
3279  perm = idxmalloc(nvtxs, "BisectGraph: queue");
3280 
3281  ASSERTP(tpwgts[0]+tpwgts[1] == idxsum(nvtxs, vwgt), ("%d %d\n", tpwgts[0]+tpwgts[1], idxsum(nvtxs, vwgt)));
3282 
3283  maxpwgt[0] = ubfactor*tpwgts[0];
3284  maxpwgt[1] = ubfactor*tpwgts[1];
3285  minpwgt[0] = (1.0/ubfactor)*tpwgts[0];
3286  minpwgt[1] = (1.0/ubfactor)*tpwgts[1];
3287 
3288  nbfs = (nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
3289  bestcut = idxsum(nvtxs, graph->adjwgtsum)+1; /* The +1 is for the 0 edges case */
3290  for (; nbfs>0; nbfs--) {
3291  RandomPermute(nvtxs, perm, 1);
3292 
3293  idxset(nvtxs, 1, where);
3294  pwgts[1] = tpwgts[0]+tpwgts[1];
3295  pwgts[0] = 0;
3296 
3297 
3298  if (nbfs != 1) {
3299  for (ii=0; ii<nvtxs; ii++) {
3300  i = perm[ii];
3301  if (pwgts[0]+vwgt[i] < maxpwgt[0]) {
3302  where[i] = 0;
3303  pwgts[0] += vwgt[i];
3304  pwgts[1] -= vwgt[i];
3305  if (pwgts[0] > minpwgt[0])
3306  break;
3307  }
3308  }
3309  }
3310 
3311  /*************************************************************
3312  * Do some partition refinement
3313  **************************************************************/
3314  Compute2WayPartitionParams(ctrl, graph);
3315  /* printf("IPART: %3d [%5d %5d] [%5d %5d] %5d\n", graph->nvtxs, pwgts[0], pwgts[1], graph->pwgts[0], graph->pwgts[1], graph->mincut); */
3316 
3317  Balance2Way(ctrl, graph, tpwgts, ubfactor);
3318  /* printf("BPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */
3319 
3320  FM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
3321  /* printf("RPART: [%5d %5d] %5d\n", graph->pwgts[0], graph->pwgts[1], graph->mincut); */
3322 
3323  if (bestcut > graph->mincut) {
3324  bestcut = graph->mincut;
3325  idxcopy(nvtxs, where, bestwhere);
3326  if (bestcut == 0)
3327  break;
3328  }
3329  }
3330 
3331  graph->mincut = bestcut;
3332  idxcopy(nvtxs, bestwhere, where);
3333 
3334  GKfree((void **) &bestwhere, (void **) &perm, LTERM);
3335 }
3336 
3337 
3338 
3339 
3340 /*
3341  * Copyright 1997, Regents of the University of Minnesota
3342  *
3343  * kmetis.c
3344  *
3345  * This file contains the top level routines for the multilevel k-way partitioning
3346  * algorithm KMETIS.
3347  *
3348  * Started 7/28/97
3349  * George
3350  *
3351  * $Id$
3352  *
3353  */
3354 
3355 
3356 
3357 
3358 /*************************************************************************
3359 * This function is the entry point for KMETIS
3360 **************************************************************************/
3361 void METIS_PartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
3362  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
3363  int *options, int *edgecut, idxtype *part)
3364 {
3365  int i;
3366  float *tpwgts;
3367 
3368  tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
3369  for (i=0; i<*nparts; i++)
3370  tpwgts[i] = 1.0/(1.0*(*nparts));
3371 
3372  METIS_WPartGraphKway(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
3373  tpwgts, options, edgecut, part);
3374 
3375  free(tpwgts);
3376 }
3377 
3378 
3379 /*************************************************************************
3380 * This function is the entry point for KWMETIS
3381 **************************************************************************/
3382 void METIS_WPartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
3383  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
3384  float *tpwgts, int *options, int *edgecut, idxtype *part)
3385 {
3386  GraphType graph;
3387  CtrlType ctrl;
3388 
3389  if (*numflag == 1)
3390  Change2CNumbering(*nvtxs, xadj, adjncy);
3391 
3392  SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag);
3393 
3394  if (options[0] == 0) { /* Use the default parameters */
3395  ctrl.CType = KMETIS_CTYPE;
3396  ctrl.IType = KMETIS_ITYPE;
3397  ctrl.RType = KMETIS_RTYPE;
3398  ctrl.dbglvl = KMETIS_DBGLVL;
3399  }
3400  else {
3401  ctrl.CType = options[OPTION_CTYPE];
3402  ctrl.IType = options[OPTION_ITYPE];
3403  ctrl.RType = options[OPTION_RTYPE];
3404  ctrl.dbglvl = options[OPTION_DBGLVL];
3405  }
3406  ctrl.optype = OP_KMETIS;
3407  ctrl.CoarsenTo = amax((*nvtxs)/(40*log2(*nparts)), 20*(*nparts));
3408  ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo);
3409 
3410  InitRandom(-1);
3411 
3412  AllocateWorkSpace(&ctrl, &graph, *nparts);
3413 
3414  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
3415  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
3416 
3417  *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03);
3418 
3419  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
3420  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
3421 
3422  FreeWorkSpace(&ctrl, &graph);
3423 
3424  if (*numflag == 1)
3425  Change2FNumbering(*nvtxs, xadj, adjncy, part);
3426 }
3427 
3428 
3429 /*************************************************************************
3430 * This function takes a graph and produces a bisection of it
3431 **************************************************************************/
3432 int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor)
3433 {
3434  GraphType *cgraph;
3435  int wgtflag=3, numflag=0, options[10], edgecut;
3436 
3437  cgraph = Coarsen2Way(ctrl, graph);
3438 
3439  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
3440  AllocateKWayPartitionMemory(ctrl, cgraph, nparts);
3441 
3442  options[0] = 1;
3443  options[OPTION_CTYPE] = MATCH_SHEMKWAY;
3444  options[OPTION_ITYPE] = IPART_GGPKL;
3445  options[OPTION_RTYPE] = RTYPE_FM;
3446  options[OPTION_DBGLVL] = 0;
3447 
3448  METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt,
3449  cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options,
3450  &edgecut, cgraph->where);
3451 
3452  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
3453  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut));
3454 
3455  IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where));
3456 
3457  RefineKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor);
3458 
3459  idxcopy(graph->nvtxs, graph->where, part);
3460 
3461  GKfree((void **) &graph->gdata, (void **) &graph->rdata, LTERM);
3462 
3463  return graph->mincut;
3464 
3465 }
3466 
3467 /*
3468  * Copyright 1997, Regents of the University of Minnesota
3469  *
3470  * kvmetis.c
3471  *
3472  * This file contains the top level routines for the multilevel k-way partitioning
3473  * algorithm KMETIS.
3474  *
3475  * Started 7/28/97
3476  * George
3477  *
3478  * $Id$
3479  *
3480  */
3481 
3482 
3483 
3484 
3485 /*************************************************************************
3486 * This function is the entry point for KMETIS
3487 **************************************************************************/
3488 void METIS_PartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
3489  idxtype *vsize, int *wgtflag, int *numflag, int *nparts,
3490  int *options, int *volume, idxtype *part)
3491 {
3492  int i;
3493  float *tpwgts;
3494 
3495  tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
3496  for (i=0; i<*nparts; i++)
3497  tpwgts[i] = 1.0/(1.0*(*nparts));
3498 
3499  METIS_WPartGraphVKway(nvtxs, xadj, adjncy, vwgt, vsize, wgtflag, numflag, nparts,
3500  tpwgts, options, volume, part);
3501 
3502  free(tpwgts);
3503 }
3504 
3505 
3506 /*************************************************************************
3507 * This function is the entry point for KWMETIS
3508 **************************************************************************/
3509 void METIS_WPartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
3510  idxtype *vsize, int *wgtflag, int *numflag, int *nparts,
3511  float *tpwgts, int *options, int *volume, idxtype *part)
3512 {
3513  GraphType graph;
3514  CtrlType ctrl;
3515 
3516  if (*numflag == 1)
3517  Change2CNumbering(*nvtxs, xadj, adjncy);
3518 
3519  VolSetUpGraph(&graph, OP_KVMETIS, *nvtxs, 1, xadj, adjncy, vwgt, vsize, *wgtflag);
3520 
3521  if (options[0] == 0) { /* Use the default parameters */
3522  ctrl.CType = KVMETIS_CTYPE;
3523  ctrl.IType = KVMETIS_ITYPE;
3524  ctrl.RType = KVMETIS_RTYPE;
3525  ctrl.dbglvl = KVMETIS_DBGLVL;
3526  }
3527  else {
3528  ctrl.CType = options[OPTION_CTYPE];
3529  ctrl.IType = options[OPTION_ITYPE];
3530  ctrl.RType = options[OPTION_RTYPE];
3531  ctrl.dbglvl = options[OPTION_DBGLVL];
3532  }
3533  ctrl.optype = OP_KVMETIS;
3534  ctrl.CoarsenTo = amax((*nvtxs)/(40*log2(*nparts)), 20*(*nparts));
3535  ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo);
3536 
3537  InitRandom(-1);
3538 
3539  AllocateWorkSpace(&ctrl, &graph, *nparts);
3540 
3541  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
3542  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
3543 
3544  *volume = MlevelVolKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03);
3545 
3546  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
3547  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
3548 
3549  FreeWorkSpace(&ctrl, &graph);
3550 
3551  if (*numflag == 1)
3552  Change2FNumbering(*nvtxs, xadj, adjncy, part);
3553 }
3554 
3555 
3556 /*************************************************************************
3557 * This function takes a graph and produces a bisection of it
3558 **************************************************************************/
3559 int MlevelVolKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part,
3560  float *tpwgts, float ubfactor)
3561 {
3562  GraphType *cgraph;
3563  int wgtflag=3, numflag=0, options[10], edgecut;
3564 
3565  cgraph = Coarsen2Way(ctrl, graph);
3566 
3567  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
3568  AllocateVolKWayPartitionMemory(ctrl, cgraph, nparts);
3569 
3570  options[0] = 1;
3571  options[OPTION_CTYPE] = MATCH_SHEMKWAY;
3572  options[OPTION_ITYPE] = IPART_GGPKL;
3573  options[OPTION_RTYPE] = RTYPE_FM;
3574  options[OPTION_DBGLVL] = 0;
3575 
3576  METIS_WPartGraphRecursive(&cgraph->nvtxs, cgraph->xadj, cgraph->adjncy, cgraph->vwgt,
3577  cgraph->adjwgt, &wgtflag, &numflag, &nparts, tpwgts, options,
3578  &edgecut, cgraph->where);
3579 
3580  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
3581  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut));
3582 
3583  IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where));
3584 
3585  RefineVolKWay(ctrl, graph, cgraph, nparts, tpwgts, ubfactor);
3586 
3587  idxcopy(graph->nvtxs, graph->where, part);
3588 
3589  GKfree((void **) &graph->gdata, (void **) &graph->rdata, LTERM);
3590 
3591  return graph->minvol;
3592 
3593 }
3594 
3595 /*
3596  * kwayfm.c
3597  *
3598  * This file contains code that implements the multilevel k-way refinement
3599  *
3600  * Started 7/28/97
3601  * George
3602  *
3603  * $Id$
3604  *
3605  */
3606 
3607 
3608 
3609 
3610 /*************************************************************************
3611 * This function performs k-way refinement
3612 **************************************************************************/
3613 void Random_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
3614 {
3615  int i, ii, iii, j, k, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees;
3616  int from, me, to, oldcut, vwgt, gain;
3617  idxtype *xadj, *adjncy, *adjwgt;
3618  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;
3619  EDegreeType *myedegrees;
3620  RInfoType *myrinfo;
3621 
3622  nvtxs = graph->nvtxs;
3623  xadj = graph->xadj;
3624  adjncy = graph->adjncy;
3625  adjwgt = graph->adjwgt;
3626 
3627  bndptr = graph->bndptr;
3628  bndind = graph->bndind;
3629 
3630  where = graph->where;
3631  pwgts = graph->pwgts;
3632 
3633  /* Setup the weight intervals of the various subdomains */
3634  minwgt = idxwspacemalloc(ctrl, nparts);
3635  maxwgt = idxwspacemalloc(ctrl, nparts);
3636  itpwgts = idxwspacemalloc(ctrl, nparts);
3637  tvwgt = idxsum(nparts, pwgts);
3638  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
3639 
3640  for (i=0; i<nparts; i++) {
3641  itpwgts[i] = tpwgts[i]*tvwgt;
3642  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
3643  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
3644  }
3645 
3646  perm = idxwspacemalloc(ctrl, nvtxs);
3647 
3648  IFSET(ctrl->dbglvl, DBG_REFINE,
3649  printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n",
3650  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
3651  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
3652  graph->mincut));
3653 
3654  for (pass=0; pass<npasses; pass++) {
3655  ASSERT(ComputeCut(graph, where) == graph->mincut);
3656 
3657  oldcut = graph->mincut;
3658  nbnd = graph->nbnd;
3659 
3660  RandomPermute(nbnd, perm, 1);
3661  for (nmoves=iii=0; iii<graph->nbnd; iii++) {
3662  ii = perm[iii];
3663  if (ii >= nbnd)
3664  continue;
3665  i = bndind[ii];
3666 
3667  myrinfo = graph->rinfo+i;
3668 
3669  if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */
3670  from = where[i];
3671  vwgt = graph->vwgt[i];
3672 
3673  if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
3674  continue; /* This cannot be moved! */
3675 
3676  myedegrees = myrinfo->edegrees;
3677  myndegrees = myrinfo->ndegrees;
3678 
3679  j = myrinfo->id;
3680  for (k=0; k<myndegrees; k++) {
3681  to = myedegrees[k].pid;
3682  gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */
3683  if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0)
3684  break;
3685  }
3686  if (k == myndegrees)
3687  continue; /* break out if you did not find a candidate */
3688 
3689  for (j=k+1; j<myndegrees; j++) {
3690  to = myedegrees[j].pid;
3691  if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) ||
3692  (myedegrees[j].ed == myedegrees[k].ed &&
3693  itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
3694  k = j;
3695  }
3696 
3697  to = myedegrees[k].pid;
3698 
3699  j = 0;
3700  if (myedegrees[k].ed-myrinfo->id > 0)
3701  j = 1;
3702  else if (myedegrees[k].ed-myrinfo->id == 0) {
3703  if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
3704  j = 1;
3705  }
3706  if (j == 0)
3707  continue;
3708 
3709  /*=====================================================================
3710  * If we got here, we can now move the vertex from 'from' to 'to'
3711  *======================================================================*/
3712  graph->mincut -= myedegrees[k].ed-myrinfo->id;
3713 
3714  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
3715 
3716  /* Update where, weight, and ID/ED information of the vertex you moved */
3717  where[i] = to;
3718  INC_DEC(pwgts[to], pwgts[from], vwgt);
3719  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
3720  SWAP(myrinfo->id, myedegrees[k].ed, j);
3721  if (myedegrees[k].ed == 0)
3722  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
3723  else
3724  myedegrees[k].pid = from;
3725 
3726  if (myrinfo->ed-myrinfo->id < 0)
3727  BNDDelete(nbnd, bndind, bndptr, i);
3728 
3729  /* Update the degrees of adjacent vertices */
3730  for (j=xadj[i]; j<xadj[i+1]; j++) {
3731  ii = adjncy[j];
3732  me = where[ii];
3733 
3734  myrinfo = graph->rinfo+ii;
3735  if (myrinfo->edegrees == NULL) {
3736  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
3737  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
3738  }
3739  myedegrees = myrinfo->edegrees;
3740 
3741  ASSERT(CheckRInfo(myrinfo));
3742 
3743  if (me == from) {
3744  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
3745 
3746  if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
3747  BNDInsert(nbnd, bndind, bndptr, ii);
3748  }
3749  else if (me == to) {
3750  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
3751 
3752  if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
3753  BNDDelete(nbnd, bndind, bndptr, ii);
3754  }
3755 
3756  /* Remove contribution from the .ed of 'from' */
3757  if (me != from) {
3758  for (k=0; k<myrinfo->ndegrees; k++) {
3759  if (myedegrees[k].pid == from) {
3760  if (myedegrees[k].ed == adjwgt[j])
3761  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
3762  else
3763  myedegrees[k].ed -= adjwgt[j];
3764  break;
3765  }
3766  }
3767  }
3768 
3769  /* Add contribution to the .ed of 'to' */
3770  if (me != to) {
3771  for (k=0; k<myrinfo->ndegrees; k++) {
3772  if (myedegrees[k].pid == to) {
3773  myedegrees[k].ed += adjwgt[j];
3774  break;
3775  }
3776  }
3777  if (k == myrinfo->ndegrees) {
3778  myedegrees[myrinfo->ndegrees].pid = to;
3779  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
3780  }
3781  }
3782 
3783  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
3784  ASSERT(CheckRInfo(myrinfo));
3785 
3786  }
3787  nmoves++;
3788  }
3789  }
3790 
3791  graph->nbnd = nbnd;
3792 
3793  IFSET(ctrl->dbglvl, DBG_REFINE,
3794  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n",
3795  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
3796  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut, ComputeVolume(graph, where)));
3797 
3798  if (graph->mincut == oldcut)
3799  break;
3800  }
3801 
3802  idxwspacefree(ctrl, nparts);
3803  idxwspacefree(ctrl, nparts);
3804  idxwspacefree(ctrl, nparts);
3805  idxwspacefree(ctrl, nvtxs);
3806 }
3807 
3808 
3809 
3810 
3811 
3812 
3813 /*************************************************************************
3814 * This function performs k-way refinement
3815 **************************************************************************/
3816 void Greedy_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
3817 {
3818  int i, ii, iii, j, k, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain;
3819  int from, me, to, oldcut, vwgt;
3820  idxtype *xadj, *adjncy, *adjwgt;
3821  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts;
3822  EDegreeType *myedegrees;
3823  RInfoType *myrinfo;
3824  PQueueType queue;
3825 
3826  nvtxs = graph->nvtxs;
3827  xadj = graph->xadj;
3828  adjncy = graph->adjncy;
3829  adjwgt = graph->adjwgt;
3830 
3831  bndind = graph->bndind;
3832  bndptr = graph->bndptr;
3833 
3834  where = graph->where;
3835  pwgts = graph->pwgts;
3836 
3837  /* Setup the weight intervals of the various subdomains */
3838  minwgt = idxwspacemalloc(ctrl, nparts);
3839  maxwgt = idxwspacemalloc(ctrl, nparts);
3840  itpwgts = idxwspacemalloc(ctrl, nparts);
3841  tvwgt = idxsum(nparts, pwgts);
3842  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
3843 
3844  for (i=0; i<nparts; i++) {
3845  itpwgts[i] = tpwgts[i]*tvwgt;
3846  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
3847  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
3848  }
3849 
3850  perm = idxwspacemalloc(ctrl, nvtxs);
3851  moved = idxwspacemalloc(ctrl, nvtxs);
3852 
3853  PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
3854 
3855  IFSET(ctrl->dbglvl, DBG_REFINE,
3856  printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n",
3857  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
3858  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
3859  graph->mincut));
3860 
3861  for (pass=0; pass<npasses; pass++) {
3862  ASSERT(ComputeCut(graph, where) == graph->mincut);
3863 
3864  PQueueReset(&queue);
3865  idxset(nvtxs, -1, moved);
3866 
3867  oldcut = graph->mincut;
3868  nbnd = graph->nbnd;
3869 
3870  RandomPermute(nbnd, perm, 1);
3871  for (ii=0; ii<nbnd; ii++) {
3872  i = bndind[perm[ii]];
3873  PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
3874  moved[i] = 2;
3875  }
3876 
3877  for (iii=0;;iii++) {
3878  if ((i = PQueueGetMax(&queue)) == -1)
3879  break;
3880  moved[i] = 1;
3881 
3882  myrinfo = graph->rinfo+i;
3883  from = where[i];
3884  vwgt = graph->vwgt[i];
3885 
3886  if (pwgts[from]-vwgt < minwgt[from])
3887  continue; /* This cannot be moved! */
3888 
3889  myedegrees = myrinfo->edegrees;
3890  myndegrees = myrinfo->ndegrees;
3891 
3892  j = myrinfo->id;
3893  for (k=0; k<myndegrees; k++) {
3894  to = myedegrees[k].pid;
3895  gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */
3896  if (pwgts[to]+vwgt <= maxwgt[to]+gain && gain >= 0)
3897  break;
3898  }
3899  if (k == myndegrees)
3900  continue; /* break out if you did not find a candidate */
3901 
3902  for (j=k+1; j<myndegrees; j++) {
3903  to = myedegrees[j].pid;
3904  if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) ||
3905  (myedegrees[j].ed == myedegrees[k].ed &&
3906  itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
3907  k = j;
3908  }
3909 
3910  to = myedegrees[k].pid;
3911 
3912  j = 0;
3913  if (myedegrees[k].ed-myrinfo->id > 0)
3914  j = 1;
3915  else if (myedegrees[k].ed-myrinfo->id == 0) {
3916  if ((iii&7) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
3917  j = 1;
3918  }
3919  if (j == 0)
3920  continue;
3921 
3922  /*=====================================================================
3923  * If we got here, we can now move the vertex from 'from' to 'to'
3924  *======================================================================*/
3925  graph->mincut -= myedegrees[k].ed-myrinfo->id;
3926 
3927  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
3928 
3929  /* Update where, weight, and ID/ED information of the vertex you moved */
3930  where[i] = to;
3931  INC_DEC(pwgts[to], pwgts[from], vwgt);
3932  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
3933  SWAP(myrinfo->id, myedegrees[k].ed, j);
3934  if (myedegrees[k].ed == 0)
3935  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
3936  else
3937  myedegrees[k].pid = from;
3938 
3939  if (myrinfo->ed < myrinfo->id)
3940  BNDDelete(nbnd, bndind, bndptr, i);
3941 
3942  /* Update the degrees of adjacent vertices */
3943  for (j=xadj[i]; j<xadj[i+1]; j++) {
3944  ii = adjncy[j];
3945  me = where[ii];
3946 
3947  myrinfo = graph->rinfo+ii;
3948  if (myrinfo->edegrees == NULL) {
3949  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
3950  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
3951  }
3952  myedegrees = myrinfo->edegrees;
3953 
3954  ASSERT(CheckRInfo(myrinfo));
3955 
3956  oldgain = (myrinfo->ed-myrinfo->id);
3957 
3958  if (me == from) {
3959  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
3960 
3961  if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
3962  BNDInsert(nbnd, bndind, bndptr, ii);
3963  }
3964  else if (me == to) {
3965  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
3966 
3967  if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
3968  BNDDelete(nbnd, bndind, bndptr, ii);
3969  }
3970 
3971  /* Remove contribution from the .ed of 'from' */
3972  if (me != from) {
3973  for (k=0; k<myrinfo->ndegrees; k++) {
3974  if (myedegrees[k].pid == from) {
3975  if (myedegrees[k].ed == adjwgt[j])
3976  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
3977  else
3978  myedegrees[k].ed -= adjwgt[j];
3979  break;
3980  }
3981  }
3982  }
3983 
3984  /* Add contribution to the .ed of 'to' */
3985  if (me != to) {
3986  for (k=0; k<myrinfo->ndegrees; k++) {
3987  if (myedegrees[k].pid == to) {
3988  myedegrees[k].ed += adjwgt[j];
3989  break;
3990  }
3991  }
3992  if (k == myrinfo->ndegrees) {
3993  myedegrees[myrinfo->ndegrees].pid = to;
3994  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
3995  }
3996  }
3997 
3998  /* Update the queue */
3999  if (me == to || me == from) {
4000  gain = myrinfo->ed-myrinfo->id;
4001  if (moved[ii] == 2) {
4002  if (gain >= 0)
4003  PQueueUpdate(&queue, ii, oldgain, gain);
4004  else {
4005  PQueueDelete(&queue, ii, oldgain);
4006  moved[ii] = -1;
4007  }
4008  }
4009  else if (moved[ii] == -1 && gain >= 0) {
4010  PQueueInsert(&queue, ii, gain);
4011  moved[ii] = 2;
4012  }
4013  }
4014 
4015  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
4016  ASSERT(CheckRInfo(myrinfo));
4017 
4018  }
4019  }
4020 
4021  graph->nbnd = nbnd;
4022 
4023  IFSET(ctrl->dbglvl, DBG_REFINE,
4024  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Cut: %6d\n",
4025  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
4026  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, graph->mincut));
4027 
4028  if (graph->mincut == oldcut)
4029  break;
4030  }
4031 
4032  PQueueFree(ctrl, &queue);
4033 
4034  idxwspacefree(ctrl, nparts);
4035  idxwspacefree(ctrl, nparts);
4036  idxwspacefree(ctrl, nparts);
4037  idxwspacefree(ctrl, nvtxs);
4038  idxwspacefree(ctrl, nvtxs);
4039 
4040 }
4041 
4042 
4043 /*************************************************************************
4044 * This function performs k-way refinement
4045 **************************************************************************/
4046 void Greedy_KWayEdgeBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
4047 {
4048  int i, ii, j, k, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves;
4049  int from, me, to, oldcut, vwgt;
4050  idxtype *xadj, *adjncy, *adjwgt;
4051  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts;
4052  EDegreeType *myedegrees;
4053  RInfoType *myrinfo;
4054  PQueueType queue;
4055 
4056  nvtxs = graph->nvtxs;
4057  xadj = graph->xadj;
4058  adjncy = graph->adjncy;
4059  adjwgt = graph->adjwgt;
4060 
4061  bndind = graph->bndind;
4062  bndptr = graph->bndptr;
4063 
4064  where = graph->where;
4065  pwgts = graph->pwgts;
4066 
4067  /* Setup the weight intervals of the various subdomains */
4068  minwgt = idxwspacemalloc(ctrl, nparts);
4069  maxwgt = idxwspacemalloc(ctrl, nparts);
4070  itpwgts = idxwspacemalloc(ctrl, nparts);
4071  tvwgt = idxsum(nparts, pwgts);
4072  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
4073 
4074  for (i=0; i<nparts; i++) {
4075  itpwgts[i] = tpwgts[i]*tvwgt;
4076  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
4077  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
4078  }
4079 
4080  perm = idxwspacemalloc(ctrl, nvtxs);
4081  moved = idxwspacemalloc(ctrl, nvtxs);
4082 
4083  PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
4084 
4085  IFSET(ctrl->dbglvl, DBG_REFINE,
4086  printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n",
4087  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
4088  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
4089  graph->mincut));
4090 
4091  for (pass=0; pass<npasses; pass++) {
4092  ASSERT(ComputeCut(graph, where) == graph->mincut);
4093 
4094  /* Check to see if things are out of balance, given the tolerance */
4095  for (i=0; i<nparts; i++) {
4096  if (pwgts[i] > maxwgt[i])
4097  break;
4098  }
4099  if (i == nparts) /* Things are balanced. Return right away */
4100  break;
4101 
4102  PQueueReset(&queue);
4103  idxset(nvtxs, -1, moved);
4104 
4105  oldcut = graph->mincut;
4106  nbnd = graph->nbnd;
4107 
4108  RandomPermute(nbnd, perm, 1);
4109  for (ii=0; ii<nbnd; ii++) {
4110  i = bndind[perm[ii]];
4111  PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
4112  moved[i] = 2;
4113  }
4114 
4115  nmoves = 0;
4116  for (;;) {
4117  if ((i = PQueueGetMax(&queue)) == -1)
4118  break;
4119  moved[i] = 1;
4120 
4121  myrinfo = graph->rinfo+i;
4122  from = where[i];
4123  vwgt = graph->vwgt[i];
4124 
4125  if (pwgts[from]-vwgt < minwgt[from])
4126  continue; /* This cannot be moved! */
4127 
4128  myedegrees = myrinfo->edegrees;
4129  myndegrees = myrinfo->ndegrees;
4130 
4131  for (k=0; k<myndegrees; k++) {
4132  to = myedegrees[k].pid;
4133  if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
4134  break;
4135  }
4136  if (k == myndegrees)
4137  continue; /* break out if you did not find a candidate */
4138 
4139  for (j=k+1; j<myndegrees; j++) {
4140  to = myedegrees[j].pid;
4141  if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])
4142  k = j;
4143  }
4144 
4145  to = myedegrees[k].pid;
4146 
4147  if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0)
4148  continue;
4149 
4150  /*=====================================================================
4151  * If we got here, we can now move the vertex from 'from' to 'to'
4152  *======================================================================*/
4153  graph->mincut -= myedegrees[k].ed-myrinfo->id;
4154 
4155  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
4156 
4157  /* Update where, weight, and ID/ED information of the vertex you moved */
4158  where[i] = to;
4159  INC_DEC(pwgts[to], pwgts[from], vwgt);
4160  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
4161  SWAP(myrinfo->id, myedegrees[k].ed, j);
4162  if (myedegrees[k].ed == 0)
4163  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
4164  else
4165  myedegrees[k].pid = from;
4166 
4167  if (myrinfo->ed == 0)
4168  BNDDelete(nbnd, bndind, bndptr, i);
4169 
4170  /* Update the degrees of adjacent vertices */
4171  for (j=xadj[i]; j<xadj[i+1]; j++) {
4172  ii = adjncy[j];
4173  me = where[ii];
4174 
4175  myrinfo = graph->rinfo+ii;
4176  if (myrinfo->edegrees == NULL) {
4177  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
4178  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
4179  }
4180  myedegrees = myrinfo->edegrees;
4181 
4182  ASSERT(CheckRInfo(myrinfo));
4183 
4184  oldgain = (myrinfo->ed-myrinfo->id);
4185 
4186  if (me == from) {
4187  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
4188 
4189  if (myrinfo->ed > 0 && bndptr[ii] == -1)
4190  BNDInsert(nbnd, bndind, bndptr, ii);
4191  }
4192  else if (me == to) {
4193  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
4194 
4195  if (myrinfo->ed == 0 && bndptr[ii] != -1)
4196  BNDDelete(nbnd, bndind, bndptr, ii);
4197  }
4198 
4199  /* Remove contribution from the .ed of 'from' */
4200  if (me != from) {
4201  for (k=0; k<myrinfo->ndegrees; k++) {
4202  if (myedegrees[k].pid == from) {
4203  if (myedegrees[k].ed == adjwgt[j])
4204  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
4205  else
4206  myedegrees[k].ed -= adjwgt[j];
4207  break;
4208  }
4209  }
4210  }
4211 
4212  /* Add contribution to the .ed of 'to' */
4213  if (me != to) {
4214  for (k=0; k<myrinfo->ndegrees; k++) {
4215  if (myedegrees[k].pid == to) {
4216  myedegrees[k].ed += adjwgt[j];
4217  break;
4218  }
4219  }
4220  if (k == myrinfo->ndegrees) {
4221  myedegrees[myrinfo->ndegrees].pid = to;
4222  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
4223  }
4224  }
4225 
4226  /* Update the queue */
4227  if (me == to || me == from) {
4228  gain = myrinfo->ed-myrinfo->id;
4229  if (moved[ii] == 2) {
4230  if (myrinfo->ed > 0)
4231  PQueueUpdate(&queue, ii, oldgain, gain);
4232  else {
4233  PQueueDelete(&queue, ii, oldgain);
4234  moved[ii] = -1;
4235  }
4236  }
4237  else if (moved[ii] == -1 && myrinfo->ed > 0) {
4238  PQueueInsert(&queue, ii, gain);
4239  moved[ii] = 2;
4240  }
4241  }
4242 
4243  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
4244  ASSERT(CheckRInfo(myrinfo));
4245  }
4246  nmoves++;
4247  }
4248 
4249  graph->nbnd = nbnd;
4250 
4251  IFSET(ctrl->dbglvl, DBG_REFINE,
4252  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d\n",
4253  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
4254  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut));
4255  }
4256 
4257  PQueueFree(ctrl, &queue);
4258 
4259  idxwspacefree(ctrl, nparts);
4260  idxwspacefree(ctrl, nparts);
4261  idxwspacefree(ctrl, nparts);
4262  idxwspacefree(ctrl, nvtxs);
4263  idxwspacefree(ctrl, nvtxs);
4264 
4265 }
4266 
4267 /*
4268  * Copyright 1997, Regents of the University of Minnesota
4269  *
4270  * kwayrefine.c
4271  *
4272  * This file contains the driving routines for multilevel k-way refinement
4273  *
4274  * Started 7/28/97
4275  * George
4276  *
4277  * $Id$
4278  */
4279 
4280 
4281 
4282 
4283 /*************************************************************************
4284 * This function is the entry point of refinement
4285 **************************************************************************/
4286 void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
4287 {
4288  int i, nlevels, mustfree=0;
4289  GraphType *ptr;
4290 
4291  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
4292 
4293  /* Compute the parameters of the coarsest graph */
4294  ComputeKWayPartitionParams(ctrl, graph, nparts);
4295 
4296  /* Take care any non-contiguity */
4297  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr1));
4298  if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
4299  EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
4300  EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
4301  EliminateComponents(ctrl, graph, nparts, tpwgts, 1.25);
4302  }
4303  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr1));
4304 
4305  /* Determine how many levels are there */
4306  for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);
4307 
4308  for (i=0; ;i++) {
4309  /* PrintSubDomainGraph(graph, nparts, graph->where); */
4310  if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN && (i == nlevels/2 || i == nlevels/2+1))
4311  EliminateSubDomainEdges(ctrl, graph, nparts, tpwgts);
4312 
4313  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
4314 
4315  if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) {
4316  ComputeKWayBalanceBoundary(ctrl, graph, nparts);
4317  if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN)
4318  Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1);
4319  else
4320  Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1);
4321  ComputeKWayBoundary(ctrl, graph, nparts);
4322  }
4323 
4324  switch (ctrl->RType) {
4325  case RTYPE_KWAYRANDOM:
4326  Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
4327  break;
4328  case RTYPE_KWAYGREEDY:
4329  Greedy_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10);
4330  break;
4332  Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 1);
4333  break;
4334  }
4335  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
4336 
4337  if (graph == orggraph)
4338  break;
4339 
4340  GKfree((void **) &graph->gdata, LTERM); /* Deallocate the graph related arrays */
4341 
4342  graph = graph->finer;
4343 
4344  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
4345  if (graph->vwgt == NULL) {
4346  graph->vwgt = idxsmalloc(graph->nvtxs, 1, "RefineKWay: graph->vwgt");
4347  graph->adjwgt = idxsmalloc(graph->nedges, 1, "RefineKWay: graph->adjwgt");
4348  mustfree = 1;
4349  }
4350  ProjectKWayPartition(ctrl, graph, nparts);
4351  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
4352  }
4353 
4354  if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) {
4355  ComputeKWayBalanceBoundary(ctrl, graph, nparts);
4356  if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
4357  Greedy_KWayEdgeBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8);
4358  Random_KWayEdgeRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
4359  }
4360  else {
4361  Greedy_KWayEdgeBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8);
4362  Random_KWayEdgeRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
4363  }
4364  }
4365 
4366  /* Take care any trivial non-contiguity */
4367  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->AuxTmr2));
4368  EliminateComponents(ctrl, graph, nparts, tpwgts, ubfactor);
4369  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->AuxTmr2));
4370 
4371  if (mustfree)
4372  GKfree((void **) &graph->vwgt, (void **) &graph->adjwgt, LTERM);
4373 
4374  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
4375 }
4376 
4377 
4378 /*************************************************************************
4379 * This function allocates memory for k-way edge refinement
4380 **************************************************************************/
4381 void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
4382 {
4383  int nvtxs, pad64;
4384 
4385  nvtxs = graph->nvtxs;
4386 
4387  pad64 = (3*nvtxs+nparts)%2;
4388 
4389  graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata");
4390  graph->pwgts = graph->rdata;
4391  graph->where = graph->rdata + nparts;
4392  graph->bndptr = graph->rdata + nvtxs + nparts;
4393  graph->bndind = graph->rdata + 2*nvtxs + nparts;
4394  graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64);
4395 
4396 /*
4397  if (ctrl->wspace.edegrees != NULL)
4398  free(ctrl->wspace.edegrees);
4399  ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateKWayPartitionMemory: edegrees");
4400 */
4401 }
4402 
4403 
4404 /*************************************************************************
4405 * This function computes the initial id/ed
4406 **************************************************************************/
4407 void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
4408 {
4409  int i, j, k, nvtxs, nbnd, mincut, me, other;
4410  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where, *bndind, *bndptr;
4411  RInfoType *rinfo, *myrinfo;
4412  EDegreeType *myedegrees;
4413 
4414  nvtxs = graph->nvtxs;
4415  xadj = graph->xadj;
4416  vwgt = graph->vwgt;
4417  adjncy = graph->adjncy;
4418  adjwgt = graph->adjwgt;
4419 
4420  where = graph->where;
4421  pwgts = idxset(nparts, 0, graph->pwgts);
4422  bndind = graph->bndind;
4423  bndptr = idxset(nvtxs, -1, graph->bndptr);
4424  rinfo = graph->rinfo;
4425 
4426 
4427  /*------------------------------------------------------------
4428  / Compute now the id/ed degrees
4429  /------------------------------------------------------------*/
4430  ctrl->wspace.cdegree = 0;
4431  nbnd = mincut = 0;
4432  for (i=0; i<nvtxs; i++) {
4433  me = where[i];
4434  pwgts[me] += vwgt[i];
4435 
4436  myrinfo = rinfo+i;
4437  myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
4438  myrinfo->edegrees = NULL;
4439 
4440  for (j=xadj[i]; j<xadj[i+1]; j++) {
4441  if (me != where[adjncy[j]])
4442  myrinfo->ed += adjwgt[j];
4443  }
4444  myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed;
4445 
4446  if (myrinfo->ed > 0)
4447  mincut += myrinfo->ed;
4448 
4449  if (myrinfo->ed-myrinfo->id >= 0)
4450  BNDInsert(nbnd, bndind, bndptr, i);
4451 
4452  /* Time to compute the particular external degrees */
4453  if (myrinfo->ed > 0) {
4454  myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
4455  ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
4456 
4457  for (j=xadj[i]; j<xadj[i+1]; j++) {
4458  other = where[adjncy[j]];
4459  if (me != other) {
4460  for (k=0; k<myrinfo->ndegrees; k++) {
4461  if (myedegrees[k].pid == other) {
4462  myedegrees[k].ed += adjwgt[j];
4463  break;
4464  }
4465  }
4466  if (k == myrinfo->ndegrees) {
4467  myedegrees[myrinfo->ndegrees].pid = other;
4468  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
4469  }
4470  }
4471  }
4472 
4473  ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
4474  }
4475  }
4476 
4477  graph->mincut = mincut/2;
4478  graph->nbnd = nbnd;
4479 
4480 }
4481 
4482 
4483 
4484 /*************************************************************************
4485 * This function projects a partition, and at the same time computes the
4486 * parameters for refinement.
4487 **************************************************************************/
4488 void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
4489 {
4490  int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees;
4491  idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
4492  idxtype *cmap, *where, *bndptr, *bndind;
4493  idxtype *cwhere;
4494  GraphType *cgraph;
4495  RInfoType *crinfo, *rinfo, *myrinfo;
4496  EDegreeType *myedegrees;
4497  idxtype *htable;
4498 
4499  cgraph = graph->coarser;
4500  cwhere = cgraph->where;
4501  crinfo = cgraph->rinfo;
4502 
4503  nvtxs = graph->nvtxs;
4504  cmap = graph->cmap;
4505  xadj = graph->xadj;
4506  adjncy = graph->adjncy;
4507  adjwgt = graph->adjwgt;
4508  adjwgtsum = graph->adjwgtsum;
4509 
4510  AllocateKWayPartitionMemory(ctrl, graph, nparts);
4511  where = graph->where;
4512  rinfo = graph->rinfo;
4513  bndind = graph->bndind;
4514  bndptr = idxset(nvtxs, -1, graph->bndptr);
4515 
4516  /* Go through and project partition and compute id/ed for the nodes */
4517  for (i=0; i<nvtxs; i++) {
4518  k = cmap[i];
4519  where[i] = cwhere[k];
4520  cmap[i] = crinfo[k].ed; /* For optimization */
4521  }
4522 
4523  htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
4524 
4525  ctrl->wspace.cdegree = 0;
4526  for (nbnd=0, i=0; i<nvtxs; i++) {
4527  me = where[i];
4528 
4529  myrinfo = rinfo+i;
4530  myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
4531  myrinfo->edegrees = NULL;
4532 
4533  myrinfo->id = adjwgtsum[i];
4534 
4535  if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */
4536  istart = xadj[i];
4537  iend = xadj[i+1];
4538 
4539  myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
4540  ctrl->wspace.cdegree += iend-istart;
4541 
4542  ndegrees = 0;
4543  for (j=istart; j<iend; j++) {
4544  other = where[adjncy[j]];
4545  if (me != other) {
4546  myrinfo->ed += adjwgt[j];
4547  if ((k = htable[other]) == -1) {
4548  htable[other] = ndegrees;
4549  myedegrees[ndegrees].pid = other;
4550  myedegrees[ndegrees++].ed = adjwgt[j];
4551  }
4552  else {
4553  myedegrees[k].ed += adjwgt[j];
4554  }
4555  }
4556  }
4557  myrinfo->id -= myrinfo->ed;
4558 
4559  /* Remove space for edegrees if it was interior */
4560  if (myrinfo->ed == 0) {
4561  myrinfo->edegrees = NULL;
4562  ctrl->wspace.cdegree -= iend-istart;
4563  }
4564  else {
4565  if (myrinfo->ed-myrinfo->id >= 0)
4566  BNDInsert(nbnd, bndind, bndptr, i);
4567 
4568  myrinfo->ndegrees = ndegrees;
4569 
4570  for (j=0; j<ndegrees; j++)
4571  htable[myedegrees[j].pid] = -1;
4572  }
4573  }
4574  }
4575 
4576  idxcopy(nparts, cgraph->pwgts, graph->pwgts);
4577  graph->mincut = cgraph->mincut;
4578  graph->nbnd = nbnd;
4579 
4580  FreeGraph(graph->coarser);
4581  graph->coarser = NULL;
4582 
4583  idxwspacefree(ctrl, nparts);
4584 
4585  ASSERT(CheckBnd2(graph));
4586 
4587 }
4588 
4589 
4590 
4591 /*************************************************************************
4592 * This function checks if the partition weights are within the balance
4593 * contraints
4594 **************************************************************************/
4595 int IsBalanced(idxtype *pwgts, int nparts, float *tpwgts, float ubfactor)
4596 {
4597  int i, tvwgt;
4598 
4599  tvwgt = idxsum(nparts, pwgts);
4600  for (i=0; i<nparts; i++) {
4601  if (pwgts[i] > tpwgts[i]*tvwgt*(ubfactor+0.005))
4602  return 0;
4603  }
4604 
4605  return 1;
4606 }
4607 
4608 
4609 /*************************************************************************
4610 * This function computes the boundary definition for balancing
4611 **************************************************************************/
4612 void ComputeKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
4613 {
4614  int i, nvtxs, nbnd;
4615  idxtype *bndind, *bndptr;
4616 
4617  nvtxs = graph->nvtxs;
4618  bndind = graph->bndind;
4619  bndptr = idxset(nvtxs, -1, graph->bndptr);
4620 
4621 
4622  /*------------------------------------------------------------
4623  / Compute the new boundary
4624  /------------------------------------------------------------*/
4625  nbnd = 0;
4626  for (i=0; i<nvtxs; i++) {
4627  if (graph->rinfo[i].ed-graph->rinfo[i].id >= 0)
4628  BNDInsert(nbnd, bndind, bndptr, i);
4629  }
4630 
4631  graph->nbnd = nbnd;
4632 }
4633 
4634 /*************************************************************************
4635 * This function computes the boundary definition for balancing
4636 **************************************************************************/
4637 void ComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
4638 {
4639  int i, nvtxs, nbnd;
4640  idxtype *bndind, *bndptr;
4641 
4642  nvtxs = graph->nvtxs;
4643  bndind = graph->bndind;
4644  bndptr = idxset(nvtxs, -1, graph->bndptr);
4645 
4646 
4647  /*------------------------------------------------------------
4648  / Compute the new boundary
4649  /------------------------------------------------------------*/
4650  nbnd = 0;
4651  for (i=0; i<nvtxs; i++) {
4652  if (graph->rinfo[i].ed > 0)
4653  BNDInsert(nbnd, bndind, bndptr, i);
4654  }
4655 
4656  graph->nbnd = nbnd;
4657 }
4658 
4659 /*
4660  * kwayvolfm.c
4661  *
4662  * This file contains code that implements the multilevel k-way refinement
4663  *
4664  * Started 7/8/98
4665  * George
4666  *
4667  * $Id$
4668  *
4669  */
4670 
4671 
4672 
4673 
4674 /*************************************************************************
4675 * This function performs k-way refinement
4676 **************************************************************************/
4677 void Random_KWayVolRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
4678  float ubfactor, int npasses, int ffactor)
4679 {
4680  int i, ii, iii, j, k, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
4681  int from, to, oldcut, oldvol, vwgt;
4682  idxtype *xadj, *adjncy, *adjwgt;
4683  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
4684  VEDegreeType *myedegrees;
4685  VRInfoType *myrinfo;
4686 
4687  nvtxs = graph->nvtxs;
4688  xadj = graph->xadj;
4689  adjncy = graph->adjncy;
4690  adjwgt = graph->adjwgt;
4691 
4692  bndptr = graph->bndptr;
4693  bndind = graph->bndind;
4694 
4695  where = graph->where;
4696  pwgts = graph->pwgts;
4697 
4698  /* Setup the weight intervals of the various subdomains */
4699  minwgt = idxwspacemalloc(ctrl, nparts);
4700  maxwgt = idxwspacemalloc(ctrl, nparts);
4701  itpwgts = idxwspacemalloc(ctrl, nparts);
4702  tvwgt = idxsum(nparts, pwgts);
4703  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
4704 
4705  updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
4706  marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
4707  phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
4708 
4709  for (i=0; i<nparts; i++) {
4710  itpwgts[i] = tpwgts[i]*tvwgt;
4711  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
4712  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
4713  }
4714 
4715  perm = idxwspacemalloc(ctrl, nvtxs);
4716 
4717  IFSET(ctrl->dbglvl, DBG_REFINE,
4718  printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\n",
4719  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
4720  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
4721  graph->mincut, graph->minvol));
4722 
4723  for (pass=0; pass<npasses; pass++) {
4724  ASSERT(ComputeCut(graph, where) == graph->mincut);
4725 
4726  oldcut = graph->mincut;
4727  oldvol = graph->minvol;
4728 
4729  RandomPermute(graph->nbnd, perm, 1);
4730  for (nmoves=iii=0; iii<graph->nbnd; iii++) {
4731  ii = perm[iii];
4732  if (ii >= graph->nbnd)
4733  continue;
4734  i = bndind[ii];
4735  myrinfo = graph->vrinfo+i;
4736 
4737  if (myrinfo->gv >= 0) { /* Total volume gain is too high */
4738  from = where[i];
4739  vwgt = graph->vwgt[i];
4740 
4741  if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
4742  continue; /* This cannot be moved! */
4743 
4744  xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
4745 
4746  myedegrees = myrinfo->edegrees;
4747  myndegrees = myrinfo->ndegrees;
4748 
4749  for (k=0; k<myndegrees; k++) {
4750  to = myedegrees[k].pid;
4751  if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 0)
4752  break;
4753  }
4754  if (k == myndegrees)
4755  continue; /* break out if you did not find a candidate */
4756 
4757  for (j=k+1; j<myndegrees; j++) {
4758  to = myedegrees[j].pid;
4759  if (pwgts[to]+vwgt > maxwgt[to])
4760  continue;
4761  if (myedegrees[j].gv > myedegrees[k].gv ||
4762  (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) ||
4763  (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed == myedegrees[k].ed &&
4764  itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
4765  k = j;
4766  }
4767 
4768  to = myedegrees[k].pid;
4769 
4770  j = 0;
4771  if (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0)
4772  j = 1;
4773  else if (myedegrees[k].ed-myrinfo->id == 0) {
4774  if ((iii&5) == 0 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
4775  j = 1;
4776  }
4777  if (j == 0)
4778  continue;
4779 
4780  /*=====================================================================
4781  * If we got here, we can now move the vertex from 'from' to 'to'
4782  *======================================================================*/
4783  INC_DEC(pwgts[to], pwgts[from], vwgt);
4784  graph->mincut -= myedegrees[k].ed-myrinfo->id;
4785  graph->minvol -= (xgain+myedegrees[k].gv);
4786  where[i] = to;
4787 
4788  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
4789  i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
4790 
4791  KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
4792 
4793  nmoves++;
4794 
4795  /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */
4796  }
4797  }
4798 
4799  IFSET(ctrl->dbglvl, DBG_REFINE,
4800  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n",
4801  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
4802  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,
4803  graph->minvol));
4804 
4805  if (graph->minvol == oldvol && graph->mincut == oldcut)
4806  break;
4807  }
4808 
4809  GKfree((void **) &marker, (void **) &updind, (void **) &phtable, LTERM);
4810 
4811  idxwspacefree(ctrl, nparts);
4812  idxwspacefree(ctrl, nparts);
4813  idxwspacefree(ctrl, nparts);
4814  idxwspacefree(ctrl, nvtxs);
4815 }
4816 
4817 
4818 /*************************************************************************
4819 * This function performs k-way refinement
4820 **************************************************************************/
4821 void Random_KWayVolRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
4822  float ubfactor, int npasses, int ffactor)
4823 {
4824  int i, ii, iii, j, k, l, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
4825  int from, me, to, oldcut, oldvol, vwgt, nadd, maxndoms;
4826  idxtype *xadj, *adjncy, *adjwgt;
4827  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
4828  idxtype *pmat, *pmatptr, *ndoms;
4829  VEDegreeType *myedegrees;
4830  VRInfoType *myrinfo;
4831 
4832  nvtxs = graph->nvtxs;
4833  xadj = graph->xadj;
4834  adjncy = graph->adjncy;
4835  adjwgt = graph->adjwgt;
4836 
4837  bndptr = graph->bndptr;
4838  bndind = graph->bndind;
4839 
4840  where = graph->where;
4841  pwgts = graph->pwgts;
4842 
4843  /* Setup the weight intervals of the various subdomains */
4844  minwgt = idxwspacemalloc(ctrl, nparts);
4845  maxwgt = idxwspacemalloc(ctrl, nparts);
4846  itpwgts = idxwspacemalloc(ctrl, nparts);
4847  tvwgt = idxsum(nparts, pwgts);
4848  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
4849 
4850  updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
4851  marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
4852  phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
4853 
4854  pmat = ctrl->wspace.pmat;
4855  ndoms = idxwspacemalloc(ctrl, nparts);
4856 
4857  ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms);
4858 
4859  for (i=0; i<nparts; i++) {
4860  itpwgts[i] = tpwgts[i]*tvwgt;
4861  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
4862  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
4863  }
4864 
4865  perm = idxwspacemalloc(ctrl, nvtxs);
4866 
4867  IFSET(ctrl->dbglvl, DBG_REFINE,
4868  printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d\n",
4869  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
4870  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
4871  graph->mincut, graph->minvol));
4872 
4873  for (pass=0; pass<npasses; pass++) {
4874  ASSERT(ComputeCut(graph, where) == graph->mincut);
4875 
4876  maxndoms = ndoms[idxamax(nparts, ndoms)];
4877 
4878  oldcut = graph->mincut;
4879  oldvol = graph->minvol;
4880 
4881  RandomPermute(graph->nbnd, perm, 1);
4882  for (nmoves=iii=0; iii<graph->nbnd; iii++) {
4883  ii = perm[iii];
4884  if (ii >= graph->nbnd)
4885  continue;
4886  i = bndind[ii];
4887  myrinfo = graph->vrinfo+i;
4888 
4889  if (myrinfo->gv >= 0) { /* Total volume gain is too high */
4890  from = where[i];
4891  vwgt = graph->vwgt[i];
4892 
4893  if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
4894  continue; /* This cannot be moved! */
4895 
4896  xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
4897 
4898  myedegrees = myrinfo->edegrees;
4899  myndegrees = myrinfo->ndegrees;
4900 
4901  /* Determine the valid domains */
4902  for (j=0; j<myndegrees; j++) {
4903  to = myedegrees[j].pid;
4904  phtable[to] = 1;
4905  pmatptr = pmat + to*nparts;
4906  for (nadd=0, k=0; k<myndegrees; k++) {
4907  if (k == j)
4908  continue;
4909 
4910  l = myedegrees[k].pid;
4911  if (pmatptr[l] == 0) {
4912  if (ndoms[l] > maxndoms-1) {
4913  phtable[to] = 0;
4914  nadd = maxndoms;
4915  break;
4916  }
4917  nadd++;
4918  }
4919  }
4920  if (ndoms[to]+nadd > maxndoms)
4921  phtable[to] = 0;
4922  if (nadd == 0)
4923  phtable[to] = 2;
4924  }
4925 
4926  for (k=0; k<myndegrees; k++) {
4927  to = myedegrees[k].pid;
4928  if (!phtable[to])
4929  continue;
4930  if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*myedegrees[k].gv && xgain+myedegrees[k].gv >= 0)
4931  break;
4932  }
4933  if (k == myndegrees)
4934  continue; /* break out if you did not find a candidate */
4935 
4936  for (j=k+1; j<myndegrees; j++) {
4937  to = myedegrees[j].pid;
4938  if (!phtable[to] || pwgts[to]+vwgt > maxwgt[to])
4939  continue;
4940  if (myedegrees[j].gv > myedegrees[k].gv ||
4941  (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed > myedegrees[k].ed) ||
4942  (myedegrees[j].gv == myedegrees[k].gv && myedegrees[j].ed == myedegrees[k].ed &&
4943  itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
4944  k = j;
4945  }
4946 
4947  to = myedegrees[k].pid;
4948 
4949  j = 0;
4950  if (xgain+myedegrees[k].gv > 0 || myedegrees[k].ed-myrinfo->id > 0)
4951  j = 1;
4952  else if (myedegrees[k].ed-myrinfo->id == 0) {
4953  if ((iii&5) == 0 || phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
4954  j = 1;
4955  }
4956 
4957  if (j == 0)
4958  continue;
4959 
4960  for (j=0; j<myndegrees; j++)
4961  phtable[myedegrees[j].pid] = -1;
4962 
4963 
4964  /*=====================================================================
4965  * If we got here, we can now move the vertex from 'from' to 'to'
4966  *======================================================================*/
4967  INC_DEC(pwgts[to], pwgts[from], vwgt);
4968  graph->mincut -= myedegrees[k].ed-myrinfo->id;
4969  graph->minvol -= (xgain+myedegrees[k].gv);
4970  where[i] = to;
4971 
4972  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
4973  i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
4974 
4975  /* Update pmat to reflect the move of 'i' */
4976  pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
4977  pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
4978  if (pmat[from*nparts+to] == 0) {
4979  ndoms[from]--;
4980  if (ndoms[from]+1 == maxndoms)
4981  maxndoms = ndoms[idxamax(nparts, ndoms)];
4982  }
4983  if (pmat[to*nparts+from] == 0) {
4984  ndoms[to]--;
4985  if (ndoms[to]+1 == maxndoms)
4986  maxndoms = ndoms[idxamax(nparts, ndoms)];
4987  }
4988 
4989  for (j=xadj[i]; j<xadj[i+1]; j++) {
4990  ii = adjncy[j];
4991  me = where[ii];
4992 
4993  /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
4994  if (me != from && me != to) {
4995  pmat[me*nparts+from] -= adjwgt[j];
4996  pmat[from*nparts+me] -= adjwgt[j];
4997  if (pmat[me*nparts+from] == 0) {
4998  ndoms[me]--;
4999  if (ndoms[me]+1 == maxndoms)
5000  maxndoms = ndoms[idxamax(nparts, ndoms)];
5001  }
5002  if (pmat[from*nparts+me] == 0) {
5003  ndoms[from]--;
5004  if (ndoms[from]+1 == maxndoms)
5005  maxndoms = ndoms[idxamax(nparts, ndoms)];
5006  }
5007 
5008  if (pmat[me*nparts+to] == 0) {
5009  ndoms[me]++;
5010  if (ndoms[me] > maxndoms) {
5011  printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms);
5012  maxndoms = ndoms[me];
5013  }
5014  }
5015  if (pmat[to*nparts+me] == 0) {
5016  ndoms[to]++;
5017  if (ndoms[to] > maxndoms) {
5018  printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms);
5019  maxndoms = ndoms[to];
5020  }
5021  }
5022  pmat[me*nparts+to] += adjwgt[j];
5023  pmat[to*nparts+me] += adjwgt[j];
5024  }
5025  }
5026 
5027  KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
5028 
5029  nmoves++;
5030 
5031  /* CheckVolKWayPartitionParams(ctrl, graph, nparts); */
5032  }
5033  }
5034 
5035  IFSET(ctrl->dbglvl, DBG_REFINE,
5036  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n",
5037  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
5038  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,
5039  graph->minvol));
5040 
5041  if (graph->minvol == oldvol && graph->mincut == oldcut)
5042  break;
5043  }
5044 
5045  GKfree((void **) &marker, (void **) &updind, (void **) &phtable, LTERM);
5046 
5047  idxwspacefree(ctrl, nparts);
5048  idxwspacefree(ctrl, nparts);
5049  idxwspacefree(ctrl, nparts);
5050  idxwspacefree(ctrl, nparts);
5051  idxwspacefree(ctrl, nvtxs);
5052 }
5053 
5054 
5055 
5056 
5057 /*************************************************************************
5058 * This function performs k-way refinement
5059 **************************************************************************/
5060 void Greedy_KWayVolBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
5061  float ubfactor, int npasses)
5062 {
5063  int i, ii, j, k, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
5064  int from, to, vwgt;
5065  idxtype *xadj, *adjncy, *adjwgt;
5066  idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
5067  VEDegreeType *myedegrees;
5068  VRInfoType *myrinfo;
5069  PQueueType queue;
5070 
5071  nvtxs = graph->nvtxs;
5072  xadj = graph->xadj;
5073  adjncy = graph->adjncy;
5074  adjwgt = graph->adjwgt;
5075 
5076  bndptr = graph->bndptr;
5077  bndind = graph->bndind;
5078 
5079  where = graph->where;
5080  pwgts = graph->pwgts;
5081 
5082  /* Setup the weight intervals of the various subdomains */
5083  minwgt = idxwspacemalloc(ctrl, nparts);
5084  maxwgt = idxwspacemalloc(ctrl, nparts);
5085  itpwgts = idxwspacemalloc(ctrl, nparts);
5086  tvwgt = idxsum(nparts, pwgts);
5087  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
5088 
5089  updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
5090  marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
5091  phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
5092 
5093  for (i=0; i<nparts; i++) {
5094  itpwgts[i] = tpwgts[i]*tvwgt;
5095  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
5096  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
5097  }
5098 
5099  perm = idxwspacemalloc(ctrl, nvtxs);
5100  moved = idxwspacemalloc(ctrl, nvtxs);
5101 
5102  PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
5103 
5104  IFSET(ctrl->dbglvl, DBG_REFINE,
5105  printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [B]\n",
5106  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
5107  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
5108  graph->mincut, graph->minvol));
5109 
5110 
5111  for (pass=0; pass<npasses; pass++) {
5112  ASSERT(ComputeCut(graph, where) == graph->mincut);
5113  /* Check to see if things are out of balance, given the tolerance */
5114  for (i=0; i<nparts; i++) {
5115  if (pwgts[i] > maxwgt[i])
5116  break;
5117  }
5118  if (i == nparts) /* Things are balanced. Return right away */
5119  break;
5120 
5121  PQueueReset(&queue);
5122  idxset(nvtxs, -1, moved);
5123 
5124  RandomPermute(graph->nbnd, perm, 1);
5125  for (ii=0; ii<graph->nbnd; ii++) {
5126  i = bndind[perm[ii]];
5127  PQueueInsert(&queue, i, graph->vrinfo[i].gv);
5128  moved[i] = 2;
5129  }
5130 
5131  for (nmoves=0;;) {
5132  if ((i = PQueueGetMax(&queue)) == -1)
5133  break;
5134  moved[i] = 1;
5135 
5136  myrinfo = graph->vrinfo+i;
5137  from = where[i];
5138  vwgt = graph->vwgt[i];
5139 
5140  if (pwgts[from]-vwgt < minwgt[from])
5141  continue; /* This cannot be moved! */
5142 
5143  xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
5144 
5145  myedegrees = myrinfo->edegrees;
5146  myndegrees = myrinfo->ndegrees;
5147 
5148  for (k=0; k<myndegrees; k++) {
5149  to = myedegrees[k].pid;
5150  if (pwgts[to]+vwgt <= maxwgt[to] ||
5151  itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
5152  break;
5153  }
5154  if (k == myndegrees)
5155  continue; /* break out if you did not find a candidate */
5156 
5157  for (j=k+1; j<myndegrees; j++) {
5158  to = myedegrees[j].pid;
5159  if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])
5160  k = j;
5161  }
5162 
5163  to = myedegrees[k].pid;
5164 
5165  if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&
5166  (xgain+myedegrees[k].gv < 0 ||
5167  (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0))
5168  )
5169  continue;
5170 
5171 
5172  /*=====================================================================
5173  * If we got here, we can now move the vertex from 'from' to 'to'
5174  *======================================================================*/
5175  INC_DEC(pwgts[to], pwgts[from], vwgt);
5176  graph->mincut -= myedegrees[k].ed-myrinfo->id;
5177  graph->minvol -= (xgain+myedegrees[k].gv);
5178  where[i] = to;
5179 
5180  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
5181  i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
5182 
5183  KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
5184 
5185  nmoves++;
5186 
5187  /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */
5188  }
5189 
5190  IFSET(ctrl->dbglvl, DBG_REFINE,
5191  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n",
5192  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
5193  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,
5194  graph->minvol));
5195 
5196  }
5197 
5198  GKfree((void **) &marker, (void **) &updind, (void **) &phtable, LTERM);
5199 
5200  PQueueFree(ctrl, &queue);
5201 
5202  idxwspacefree(ctrl, nparts);
5203  idxwspacefree(ctrl, nparts);
5204  idxwspacefree(ctrl, nparts);
5205  idxwspacefree(ctrl, nvtxs);
5206  idxwspacefree(ctrl, nvtxs);
5207 }
5208 
5209 
5210 
5211 /*************************************************************************
5212 * This function performs k-way refinement
5213 **************************************************************************/
5214 void Greedy_KWayVolBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts,
5215  float ubfactor, int npasses)
5216 {
5217  int i, ii, j, k, l, pass, nvtxs, nmoves, tvwgt, myndegrees, xgain;
5218  int from, me, to, vwgt, maxndoms, nadd;
5219  idxtype *xadj, *adjncy, *adjwgt;
5220  idxtype *where, *pwgts, *perm, *moved, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts, *updind, *marker, *phtable;
5221  idxtype *pmat, *pmatptr, *ndoms;
5222  VEDegreeType *myedegrees;
5223  VRInfoType *myrinfo;
5224  PQueueType queue;
5225 
5226  nvtxs = graph->nvtxs;
5227  xadj = graph->xadj;
5228  adjncy = graph->adjncy;
5229  adjwgt = graph->adjwgt;
5230 
5231  bndptr = graph->bndptr;
5232  bndind = graph->bndind;
5233 
5234  where = graph->where;
5235  pwgts = graph->pwgts;
5236 
5237  /* Setup the weight intervals of the various subdomains */
5238  minwgt = idxwspacemalloc(ctrl, nparts);
5239  maxwgt = idxwspacemalloc(ctrl, nparts);
5240  itpwgts = idxwspacemalloc(ctrl, nparts);
5241  tvwgt = idxsum(nparts, pwgts);
5242  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
5243 
5244  updind = idxmalloc(nvtxs, "Random_KWayVolRefine: updind");
5245  marker = idxsmalloc(nvtxs, 0, "Random_KWayVolRefine: marker");
5246  phtable = idxsmalloc(nparts, -1, "Random_KWayVolRefine: phtable");
5247 
5248  pmat = ctrl->wspace.pmat;
5249  ndoms = idxwspacemalloc(ctrl, nparts);
5250 
5251  ComputeVolSubDomainGraph(graph, nparts, pmat, ndoms);
5252 
5253  for (i=0; i<nparts; i++) {
5254  itpwgts[i] = tpwgts[i]*tvwgt;
5255  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
5256  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
5257  }
5258 
5259  perm = idxwspacemalloc(ctrl, nvtxs);
5260  moved = idxwspacemalloc(ctrl, nvtxs);
5261 
5262  PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
5263 
5264  IFSET(ctrl->dbglvl, DBG_REFINE,
5265  printf("VolPart: [%5d %5d]-[%5d %5d], Balance: %3.2f, Nv-Nb[%5d %5d]. Cut: %5d, Vol: %5d [B]\n",
5266  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
5267  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
5268  graph->mincut, graph->minvol));
5269 
5270 
5271  for (pass=0; pass<npasses; pass++) {
5272  ASSERT(ComputeCut(graph, where) == graph->mincut);
5273  /* Check to see if things are out of balance, given the tolerance */
5274  for (i=0; i<nparts; i++) {
5275  if (pwgts[i] > maxwgt[i])
5276  break;
5277  }
5278  if (i == nparts) /* Things are balanced. Return right away */
5279  break;
5280 
5281  PQueueReset(&queue);
5282  idxset(nvtxs, -1, moved);
5283 
5284  RandomPermute(graph->nbnd, perm, 1);
5285  for (ii=0; ii<graph->nbnd; ii++) {
5286  i = bndind[perm[ii]];
5287  PQueueInsert(&queue, i, graph->vrinfo[i].gv);
5288  moved[i] = 2;
5289  }
5290 
5291  maxndoms = ndoms[idxamax(nparts, ndoms)];
5292 
5293  for (nmoves=0;;) {
5294  if ((i = PQueueGetMax(&queue)) == -1)
5295  break;
5296  moved[i] = 1;
5297 
5298  myrinfo = graph->vrinfo+i;
5299  from = where[i];
5300  vwgt = graph->vwgt[i];
5301 
5302  if (pwgts[from]-vwgt < minwgt[from])
5303  continue; /* This cannot be moved! */
5304 
5305  xgain = (myrinfo->id == 0 && myrinfo->ed > 0 ? graph->vsize[i] : 0);
5306 
5307  myedegrees = myrinfo->edegrees;
5308  myndegrees = myrinfo->ndegrees;
5309 
5310  /* Determine the valid domains */
5311  for (j=0; j<myndegrees; j++) {
5312  to = myedegrees[j].pid;
5313  phtable[to] = 1;
5314  pmatptr = pmat + to*nparts;
5315  for (nadd=0, k=0; k<myndegrees; k++) {
5316  if (k == j)
5317  continue;
5318 
5319  l = myedegrees[k].pid;
5320  if (pmatptr[l] == 0) {
5321  if (ndoms[l] > maxndoms-1) {
5322  phtable[to] = 0;
5323  nadd = maxndoms;
5324  break;
5325  }
5326  nadd++;
5327  }
5328  }
5329  if (ndoms[to]+nadd > maxndoms)
5330  phtable[to] = 0;
5331  }
5332 
5333  for (k=0; k<myndegrees; k++) {
5334  to = myedegrees[k].pid;
5335  if (!phtable[to])
5336  continue;
5337  if (pwgts[to]+vwgt <= maxwgt[to] ||
5338  itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
5339  break;
5340  }
5341  if (k == myndegrees)
5342  continue; /* break out if you did not find a candidate */
5343 
5344  for (j=k+1; j<myndegrees; j++) {
5345  to = myedegrees[j].pid;
5346  if (!phtable[to])
5347  continue;
5348  if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])
5349  k = j;
5350  }
5351 
5352  to = myedegrees[k].pid;
5353 
5354  for (j=0; j<myndegrees; j++)
5355  phtable[myedegrees[j].pid] = -1;
5356 
5357  if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] &&
5358  (xgain+myedegrees[k].gv < 0 ||
5359  (xgain+myedegrees[k].gv == 0 && myedegrees[k].ed-myrinfo->id < 0))
5360  )
5361  continue;
5362 
5363 
5364  /*=====================================================================
5365  * If we got here, we can now move the vertex from 'from' to 'to'
5366  *======================================================================*/
5367  INC_DEC(pwgts[to], pwgts[from], vwgt);
5368  graph->mincut -= myedegrees[k].ed-myrinfo->id;
5369  graph->minvol -= (xgain+myedegrees[k].gv);
5370  where[i] = to;
5371 
5372  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d from %3d to %3d. Gain: [%4d %4d]. Cut: %6d, Vol: %6d\n",
5373  i, from, to, xgain+myedegrees[k].gv, myedegrees[k].ed-myrinfo->id, graph->mincut, graph->minvol));
5374 
5375  /* Update pmat to reflect the move of 'i' */
5376  pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
5377  pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
5378  if (pmat[from*nparts+to] == 0) {
5379  ndoms[from]--;
5380  if (ndoms[from]+1 == maxndoms)
5381  maxndoms = ndoms[idxamax(nparts, ndoms)];
5382  }
5383  if (pmat[to*nparts+from] == 0) {
5384  ndoms[to]--;
5385  if (ndoms[to]+1 == maxndoms)
5386  maxndoms = ndoms[idxamax(nparts, ndoms)];
5387  }
5388 
5389  for (j=xadj[i]; j<xadj[i+1]; j++) {
5390  ii = adjncy[j];
5391  me = where[ii];
5392 
5393  /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
5394  if (me != from && me != to) {
5395  pmat[me*nparts+from] -= adjwgt[j];
5396  pmat[from*nparts+me] -= adjwgt[j];
5397  if (pmat[me*nparts+from] == 0) {
5398  ndoms[me]--;
5399  if (ndoms[me]+1 == maxndoms)
5400  maxndoms = ndoms[idxamax(nparts, ndoms)];
5401  }
5402  if (pmat[from*nparts+me] == 0) {
5403  ndoms[from]--;
5404  if (ndoms[from]+1 == maxndoms)
5405  maxndoms = ndoms[idxamax(nparts, ndoms)];
5406  }
5407 
5408  if (pmat[me*nparts+to] == 0) {
5409  ndoms[me]++;
5410  if (ndoms[me] > maxndoms) {
5411  printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms);
5412  maxndoms = ndoms[me];
5413  }
5414  }
5415  if (pmat[to*nparts+me] == 0) {
5416  ndoms[to]++;
5417  if (ndoms[to] > maxndoms) {
5418  printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms);
5419  maxndoms = ndoms[to];
5420  }
5421  }
5422  pmat[me*nparts+to] += adjwgt[j];
5423  pmat[to*nparts+me] += adjwgt[j];
5424  }
5425  }
5426 
5427  KWayVolUpdate(ctrl, graph, i, from, to, marker, phtable, updind);
5428 
5429  nmoves++;
5430 
5431  /*CheckVolKWayPartitionParams(ctrl, graph, nparts); */
5432  }
5433 
5434  IFSET(ctrl->dbglvl, DBG_REFINE,
5435  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, Vol: %6d\n",
5436  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
5437  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,
5438  graph->minvol));
5439 
5440  }
5441 
5442  GKfree((void **) &marker, (void **) &updind, (void **) &phtable, LTERM);
5443 
5444  PQueueFree(ctrl, &queue);
5445 
5446  idxwspacefree(ctrl, nparts);
5447  idxwspacefree(ctrl, nparts);
5448  idxwspacefree(ctrl, nparts);
5449  idxwspacefree(ctrl, nparts);
5450  idxwspacefree(ctrl, nvtxs);
5451  idxwspacefree(ctrl, nvtxs);
5452 }
5453 
5454 
5455 
5456 
5457 /*************************************************************************
5458 * This function updates the edge and volume gains as a result of moving
5459 * v from 'from' to 'to'.
5460 * The working arrays marker and phtable are assumed to be initialized to
5461 * -1, and they left to -1 upon return
5462 **************************************************************************/
5463 void KWayVolUpdate(CtrlType *ctrl, GraphType *graph, int v, int from, int to,
5464  idxtype *marker, idxtype *phtable, idxtype *updind)
5465 {
5466  int ii, j, jj, k, kk, u, nupd, other, me, myidx;
5467  idxtype *xadj, *vsize, *adjncy, *adjwgt, *where;
5468  VEDegreeType *myedegrees, *oedegrees;
5469  VRInfoType *myrinfo, *orinfo;
5470 
5471  xadj = graph->xadj;
5472  adjncy = graph->adjncy;
5473  adjwgt = graph->adjwgt;
5474  vsize = graph->vsize;
5475  where = graph->where;
5476 
5477  myrinfo = graph->vrinfo+v;
5478  myedegrees = myrinfo->edegrees;
5479 
5480 
5481  /*======================================================================
5482  * Remove the contributions on the gain made by 'v'.
5483  *=====================================================================*/
5484  for (k=0; k<myrinfo->ndegrees; k++)
5485  phtable[myedegrees[k].pid] = k;
5486  phtable[from] = k;
5487 
5488  myidx = phtable[to]; /* Keep track of the index in myedegrees of the 'to' domain */
5489 
5490  for (j=xadj[v]; j<xadj[v+1]; j++) {
5491  ii = adjncy[j];
5492  other = where[ii];
5493  orinfo = graph->vrinfo+ii;
5494  oedegrees = orinfo->edegrees;
5495 
5496  if (other == from) {
5497  for (k=0; k<orinfo->ndegrees; k++) {
5498  if (phtable[oedegrees[k].pid] == -1)
5499  oedegrees[k].gv += vsize[v];
5500  }
5501  }
5502  else {
5503  ASSERT(phtable[other] != -1);
5504 
5505  if (myedegrees[phtable[other]].ned > 1) {
5506  for (k=0; k<orinfo->ndegrees; k++) {
5507  if (phtable[oedegrees[k].pid] == -1)
5508  oedegrees[k].gv += vsize[v];
5509  }
5510  }
5511  else { /* There is only one connection */
5512  for (k=0; k<orinfo->ndegrees; k++) {
5513  if (phtable[oedegrees[k].pid] != -1)
5514  oedegrees[k].gv -= vsize[v];
5515  }
5516  }
5517  }
5518  }
5519 
5520  for (k=0; k<myrinfo->ndegrees; k++)
5521  phtable[myedegrees[k].pid] = -1;
5522  phtable[from] = -1;
5523 
5524 
5525  /*======================================================================
5526  * Update the id/ed of vertex 'v'
5527  *=====================================================================*/
5528  myrinfo->ed += myrinfo->id-myedegrees[myidx].ed;
5529  SWAP(myrinfo->id, myedegrees[myidx].ed, j);
5530  SWAP(myrinfo->nid, myedegrees[myidx].ned, j);
5531  if (myedegrees[myidx].ed == 0)
5532  myedegrees[myidx] = myedegrees[--myrinfo->ndegrees];
5533  else
5534  myedegrees[myidx].pid = from;
5535 
5536  /*======================================================================
5537  * Update the degrees of adjacent vertices and their volume gains
5538  *=====================================================================*/
5539  marker[v] = 1;
5540  updind[0] = v;
5541  nupd = 1;
5542  for (j=xadj[v]; j<xadj[v+1]; j++) {
5543  ii = adjncy[j];
5544  me = where[ii];
5545 
5546  if (!marker[ii]) { /* The marking is done for boundary and max gv calculations */
5547  marker[ii] = 2;
5548  updind[nupd++] = ii;
5549  }
5550 
5551  myrinfo = graph->vrinfo+ii;
5552  if (myrinfo->edegrees == NULL) {
5553  myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree;
5554  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
5555  }
5556  myedegrees = myrinfo->edegrees;
5557 
5558  if (me == from) {
5559  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
5560  myrinfo->nid--;
5561  }
5562  else if (me == to) {
5563  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
5564  myrinfo->nid++;
5565  }
5566 
5567  /* Remove the edgeweight from the 'pid == from' entry of the vertex */
5568  if (me != from) {
5569  for (k=0; k<myrinfo->ndegrees; k++) {
5570  if (myedegrees[k].pid == from) {
5571  if (myedegrees[k].ned == 1) {
5572  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
5573  marker[ii] = 1; /* You do a complete .gv calculation */
5574 
5575  /* All vertices adjacent to 'ii' need to be updated */
5576  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
5577  u = adjncy[jj];
5578  other = where[u];
5579  orinfo = graph->vrinfo+u;
5580  oedegrees = orinfo->edegrees;
5581 
5582  for (kk=0; kk<orinfo->ndegrees; kk++) {
5583  if (oedegrees[kk].pid == from) {
5584  oedegrees[kk].gv -= vsize[ii];
5585  break;
5586  }
5587  }
5588  }
5589  }
5590  else {
5591  myedegrees[k].ed -= adjwgt[j];
5592  myedegrees[k].ned--;
5593 
5594  /* Update the gv due to single 'ii' connection to 'from' */
5595  if (myedegrees[k].ned == 1) {
5596  /* find the vertex 'u' that 'ii' was connected into 'from' */
5597  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
5598  u = adjncy[jj];
5599  other = where[u];
5600  orinfo = graph->vrinfo+u;
5601  oedegrees = orinfo->edegrees;
5602 
5603  if (other == from) {
5604  for (kk=0; kk<orinfo->ndegrees; kk++)
5605  oedegrees[kk].gv += vsize[ii];
5606  break;
5607  }
5608  }
5609  }
5610  }
5611 
5612  break;
5613  }
5614  }
5615  }
5616 
5617  /* Add the edgeweight to the 'pid == to' entry of the vertex */
5618  if (me != to) {
5619  for (k=0; k<myrinfo->ndegrees; k++) {
5620  if (myedegrees[k].pid == to) {
5621  myedegrees[k].ed += adjwgt[j];
5622  myedegrees[k].ned++;
5623 
5624  /* Update the gv due to non-single 'ii' connection to 'to' */
5625  if (myedegrees[k].ned == 2) {
5626  /* find the vertex 'u' that 'ii' was connected into 'to' */
5627  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
5628  u = adjncy[jj];
5629  other = where[u];
5630  orinfo = graph->vrinfo+u;
5631  oedegrees = orinfo->edegrees;
5632 
5633  if (u != v && other == to) {
5634  for (kk=0; kk<orinfo->ndegrees; kk++)
5635  oedegrees[kk].gv -= vsize[ii];
5636  break;
5637  }
5638  }
5639  }
5640  break;
5641  }
5642  }
5643 
5644  if (k == myrinfo->ndegrees) {
5645  myedegrees[myrinfo->ndegrees].pid = to;
5646  myedegrees[myrinfo->ndegrees].ed = adjwgt[j];
5647  myedegrees[myrinfo->ndegrees++].ned = 1;
5648  marker[ii] = 1; /* You do a complete .gv calculation */
5649 
5650  /* All vertices adjacent to 'ii' need to be updated */
5651  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
5652  u = adjncy[jj];
5653  other = where[u];
5654  orinfo = graph->vrinfo+u;
5655  oedegrees = orinfo->edegrees;
5656 
5657  for (kk=0; kk<orinfo->ndegrees; kk++) {
5658  if (oedegrees[kk].pid == to) {
5659  oedegrees[kk].gv += vsize[ii];
5660  if (!marker[u]) { /* Need to update boundary etc */
5661  marker[u] = 2;
5662  updind[nupd++] = u;
5663  }
5664  break;
5665  }
5666  }
5667  }
5668  }
5669  }
5670 
5671  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
5672  }
5673 
5674  /*======================================================================
5675  * Add the contributions on the volume gain due to 'v'
5676  *=====================================================================*/
5677  myrinfo = graph->vrinfo+v;
5678  myedegrees = myrinfo->edegrees;
5679  for (k=0; k<myrinfo->ndegrees; k++)
5680  phtable[myedegrees[k].pid] = k;
5681  phtable[to] = k;
5682 
5683  for (j=xadj[v]; j<xadj[v+1]; j++) {
5684  ii = adjncy[j];
5685  other = where[ii];
5686  orinfo = graph->vrinfo+ii;
5687  oedegrees = orinfo->edegrees;
5688 
5689  if (other == to) {
5690  for (k=0; k<orinfo->ndegrees; k++) {
5691  if (phtable[oedegrees[k].pid] == -1)
5692  oedegrees[k].gv -= vsize[v];
5693  }
5694  }
5695  else {
5696  ASSERT(phtable[other] != -1);
5697 
5698  if (myedegrees[phtable[other]].ned > 1) {
5699  for (k=0; k<orinfo->ndegrees; k++) {
5700  if (phtable[oedegrees[k].pid] == -1)
5701  oedegrees[k].gv -= vsize[v];
5702  }
5703  }
5704  else { /* There is only one connection */
5705  for (k=0; k<orinfo->ndegrees; k++) {
5706  if (phtable[oedegrees[k].pid] != -1)
5707  oedegrees[k].gv += vsize[v];
5708  }
5709  }
5710  }
5711  }
5712  for (k=0; k<myrinfo->ndegrees; k++)
5713  phtable[myedegrees[k].pid] = -1;
5714  phtable[to] = -1;
5715 
5716 
5717  /*======================================================================
5718  * Recompute the volume information of the 'hard' nodes, and update the
5719  * max volume gain for all the update vertices
5720  *=====================================================================*/
5721  ComputeKWayVolume(graph, nupd, updind, marker, phtable);
5722 
5723 
5724  /*======================================================================
5725  * Maintain a consistent boundary
5726  *=====================================================================*/
5727  for (j=0; j<nupd; j++) {
5728  k = updind[j];
5729  marker[k] = 0;
5730  myrinfo = graph->vrinfo+k;
5731 
5732  if ((myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0) && graph->bndptr[k] == -1)
5733  BNDInsert(graph->nbnd, graph->bndind, graph->bndptr, k);
5734 
5735  if (myrinfo->gv < 0 && myrinfo->ed-myrinfo->id < 0 && graph->bndptr[k] != -1)
5736  BNDDelete(graph->nbnd, graph->bndind, graph->bndptr, k);
5737  }
5738 
5739 }
5740 
5741 
5742 
5743 
5744 /*************************************************************************
5745 * This function computes the initial id/ed
5746 **************************************************************************/
5747 void ComputeKWayVolume(GraphType *graph, int nupd, idxtype *updind, idxtype *marker, idxtype *phtable)
5748 {
5749  int ii, iii, i, j, k, kk, nvtxs, me, other;
5750  idxtype *xadj, *vsize, *adjncy, *adjwgt, *where;
5751  VRInfoType *rinfo, *myrinfo, *orinfo;
5752  VEDegreeType *myedegrees, *oedegrees;
5753 
5754  nvtxs = graph->nvtxs;
5755  xadj = graph->xadj;
5756  vsize = graph->vsize;
5757  adjncy = graph->adjncy;
5758  adjwgt = graph->adjwgt;
5759  where = graph->where;
5760  rinfo = graph->vrinfo;
5761 
5762 
5763  /*------------------------------------------------------------
5764  / Compute now the iv/ev degrees
5765  /------------------------------------------------------------*/
5766  for (iii=0; iii<nupd; iii++) {
5767  i = updind[iii];
5768  me = where[i];
5769 
5770  myrinfo = rinfo+i;
5771  myedegrees = myrinfo->edegrees;
5772 
5773  if (marker[i] == 1) { /* Only complete gain updates go through */
5774  for (k=0; k<myrinfo->ndegrees; k++)
5775  myedegrees[k].gv = 0;
5776 
5777  for (j=xadj[i]; j<xadj[i+1]; j++) {
5778  ii = adjncy[j];
5779  other = where[ii];
5780  orinfo = rinfo+ii;
5781  oedegrees = orinfo->edegrees;
5782 
5783  for (kk=0; kk<orinfo->ndegrees; kk++)
5784  phtable[oedegrees[kk].pid] = kk;
5785  phtable[other] = 1;
5786 
5787  if (me == other) {
5788  /* Find which domains 'i' is connected and 'ii' is not and update their gain */
5789  for (k=0; k<myrinfo->ndegrees; k++) {
5790  if (phtable[myedegrees[k].pid] == -1)
5791  myedegrees[k].gv -= vsize[ii];
5792  }
5793  }
5794  else {
5795  ASSERT(phtable[me] != -1);
5796 
5797  /* I'm the only connection of 'ii' in 'me' */
5798  if (oedegrees[phtable[me]].ned == 1) {
5799  /* Increase the gains for all the common domains between 'i' and 'ii' */
5800  for (k=0; k<myrinfo->ndegrees; k++) {
5801  if (phtable[myedegrees[k].pid] != -1)
5802  myedegrees[k].gv += vsize[ii];
5803  }
5804  }
5805  else {
5806  /* Find which domains 'i' is connected and 'ii' is not and update their gain */
5807  for (k=0; k<myrinfo->ndegrees; k++) {
5808  if (phtable[myedegrees[k].pid] == -1)
5809  myedegrees[k].gv -= vsize[ii];
5810  }
5811  }
5812  }
5813 
5814  for (kk=0; kk<orinfo->ndegrees; kk++)
5815  phtable[oedegrees[kk].pid] = -1;
5816  phtable[other] = -1;
5817 
5818  }
5819  }
5820 
5821  myrinfo->gv = -MAXIDX;
5822  for (k=0; k<myrinfo->ndegrees; k++) {
5823  if (myedegrees[k].gv > myrinfo->gv)
5824  myrinfo->gv = myedegrees[k].gv;
5825  }
5826  if (myrinfo->ed > 0 && myrinfo->id == 0)
5827  myrinfo->gv += vsize[i];
5828 
5829  }
5830 
5831 }
5832 
5833 
5834 
5835 /*************************************************************************
5836 * This function computes the total volume
5837 **************************************************************************/
5838 int ComputeVolume(GraphType *graph, idxtype *where)
5839 {
5840  int i, j, k, nvtxs, nparts, totalv;
5841  idxtype *xadj, *adjncy, *vsize, *marker;
5842 
5843 
5844  nvtxs = graph->nvtxs;
5845  xadj = graph->xadj;
5846  adjncy = graph->adjncy;
5847  vsize = (graph->vsize == NULL ? graph->vwgt : graph->vsize);
5848 
5849  nparts = where[idxamax(nvtxs, where)]+1;
5850  marker = idxsmalloc(nparts, -1, "ComputeVolume: marker");
5851 
5852  totalv = 0;
5853 
5854  for (i=0; i<nvtxs; i++) {
5855  marker[where[i]] = i;
5856  for (j=xadj[i]; j<xadj[i+1]; j++) {
5857  k = where[adjncy[j]];
5858  if (marker[k] != i) {
5859  marker[k] = i;
5860  totalv += vsize[i];
5861  }
5862  }
5863  }
5864 
5865  free(marker);
5866 
5867  return totalv;
5868 }
5869 
5870 
5871 
5872 
5873 
5874 /*************************************************************************
5875 * This function computes the initial id/ed
5876 **************************************************************************/
5877 void CheckVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
5878 {
5879  int i, ii, j, k, kk, nvtxs, me, other, pid;
5880  idxtype *xadj, *vsize, *adjncy, *adjwgt, *where;
5881  VRInfoType *rinfo, *myrinfo, *orinfo, tmprinfo;
5882  VEDegreeType *myedegrees, *oedegrees, *tmpdegrees;
5883 
5884  nvtxs = graph->nvtxs;
5885  xadj = graph->xadj;
5886  vsize = graph->vsize;
5887  adjncy = graph->adjncy;
5888  adjwgt = graph->adjwgt;
5889  where = graph->where;
5890  rinfo = graph->vrinfo;
5891 
5892  tmpdegrees = (VEDegreeType *)GKmalloc(nparts*sizeof(VEDegreeType), "CheckVolKWayPartitionParams: tmpdegrees");
5893 
5894  /*------------------------------------------------------------
5895  / Compute now the iv/ev degrees
5896  /------------------------------------------------------------*/
5897  for (i=0; i<nvtxs; i++) {
5898  me = where[i];
5899 
5900  myrinfo = rinfo+i;
5901  myedegrees = myrinfo->edegrees;
5902 
5903  for (k=0; k<myrinfo->ndegrees; k++)
5904  tmpdegrees[k] = myedegrees[k];
5905 
5906  tmprinfo.ndegrees = myrinfo->ndegrees;
5907  tmprinfo.id = myrinfo->id;
5908  tmprinfo.ed = myrinfo->ed;
5909 
5910  myrinfo = &tmprinfo;
5911  myedegrees = tmpdegrees;
5912 
5913 
5914  for (k=0; k<myrinfo->ndegrees; k++)
5915  myedegrees[k].gv = 0;
5916 
5917  for (j=xadj[i]; j<xadj[i+1]; j++) {
5918  ii = adjncy[j];
5919  other = where[ii];
5920  orinfo = rinfo+ii;
5921  oedegrees = orinfo->edegrees;
5922 
5923  if (me == other) {
5924  /* Find which domains 'i' is connected and 'ii' is not and update their gain */
5925  for (k=0; k<myrinfo->ndegrees; k++) {
5926  pid = myedegrees[k].pid;
5927  for (kk=0; kk<orinfo->ndegrees; kk++) {
5928  if (oedegrees[kk].pid == pid)
5929  break;
5930  }
5931  if (kk == orinfo->ndegrees)
5932  myedegrees[k].gv -= vsize[ii];
5933  }
5934  }
5935  else {
5936  /* Find the orinfo[me].ed and see if I'm the only connection */
5937  for (k=0; k<orinfo->ndegrees; k++) {
5938  if (oedegrees[k].pid == me)
5939  break;
5940  }
5941 
5942  if (oedegrees[k].ned == 1) { /* I'm the only connection of 'ii' in 'me' */
5943  for (k=0; k<myrinfo->ndegrees; k++) {
5944  if (myedegrees[k].pid == other) {
5945  myedegrees[k].gv += vsize[ii];
5946  break;
5947  }
5948  }
5949 
5950  /* Increase the gains for all the common domains between 'i' and 'ii' */
5951  for (k=0; k<myrinfo->ndegrees; k++) {
5952  if ((pid = myedegrees[k].pid) == other)
5953  continue;
5954  for (kk=0; kk<orinfo->ndegrees; kk++) {
5955  if (oedegrees[kk].pid == pid) {
5956  myedegrees[k].gv += vsize[ii];
5957  break;
5958  }
5959  }
5960  }
5961 
5962  }
5963  else {
5964  /* Find which domains 'i' is connected and 'ii' is not and update their gain */
5965  for (k=0; k<myrinfo->ndegrees; k++) {
5966  if ((pid = myedegrees[k].pid) == other)
5967  continue;
5968  for (kk=0; kk<orinfo->ndegrees; kk++) {
5969  if (oedegrees[kk].pid == pid)
5970  break;
5971  }
5972  if (kk == orinfo->ndegrees)
5973  myedegrees[k].gv -= vsize[ii];
5974  }
5975  }
5976  }
5977  }
5978 
5979  myrinfo = rinfo+i;
5980  myedegrees = myrinfo->edegrees;
5981 
5982  for (k=0; k<myrinfo->ndegrees; k++) {
5983  pid = myedegrees[k].pid;
5984  for (kk=0; kk<tmprinfo.ndegrees; kk++) {
5985  if (tmpdegrees[kk].pid == pid) {
5986  if (tmpdegrees[kk].gv != myedegrees[k].gv)
5987  printf("[%d %d %d %d]\n", i, pid, myedegrees[k].gv, tmpdegrees[kk].gv);
5988  break;
5989  }
5990  }
5991  }
5992 
5993  }
5994 
5995  free(tmpdegrees);
5996 
5997 }
5998 
5999 
6000 /*************************************************************************
6001 * This function computes the subdomain graph
6002 **************************************************************************/
6003 void ComputeVolSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms)
6004 {
6005  int i, j, k, me, nvtxs, ndegrees;
6006  idxtype *xadj, *adjncy, *adjwgt, *where;
6007  VRInfoType *rinfo;
6008  VEDegreeType *edegrees;
6009 
6010  nvtxs = graph->nvtxs;
6011  xadj = graph->xadj;
6012  adjncy = graph->adjncy;
6013  adjwgt = graph->adjwgt;
6014  where = graph->where;
6015  rinfo = graph->vrinfo;
6016 
6017  idxset(nparts*nparts, 0, pmat);
6018 
6019  for (i=0; i<nvtxs; i++) {
6020  if (rinfo[i].ed > 0) {
6021  me = where[i];
6022  ndegrees = rinfo[i].ndegrees;
6023  edegrees = rinfo[i].edegrees;
6024 
6025  k = me*nparts;
6026  for (j=0; j<ndegrees; j++)
6027  pmat[k+edegrees[j].pid] += edegrees[j].ed;
6028  }
6029  }
6030 
6031  for (i=0; i<nparts; i++) {
6032  ndoms[i] = 0;
6033  for (j=0; j<nparts; j++) {
6034  if (pmat[i*nparts+j] > 0)
6035  ndoms[i]++;
6036  }
6037  }
6038 }
6039 
6040 
6041 
6042 /*************************************************************************
6043 * This function computes the subdomain graph
6044 **************************************************************************/
6045 void EliminateVolSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts)
6046 {
6047  int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd;
6048  int min, move, cpwgt, tvwgt;
6049  idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind;
6050  KeyValueType *cand, *cand2;
6051 
6052  nvtxs = graph->nvtxs;
6053  xadj = graph->xadj;
6054  adjncy = graph->adjncy;
6055  vwgt = graph->vwgt;
6056  adjwgt = graph->adjwgt;
6057 
6058  where = graph->where;
6059  pwgts = idxset(nparts, 0, graph->pwgts);
6060 
6061  maxpwgt = idxwspacemalloc(ctrl, nparts);
6062  ndoms = idxwspacemalloc(ctrl, nparts);
6063  otherpmat = idxwspacemalloc(ctrl, nparts);
6064  ind = idxwspacemalloc(ctrl, nvtxs);
6065  pmat = idxset(nparts*nparts, 0, ctrl->wspace.pmat);
6066 
6067  cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
6068  cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
6069 
6070  /* Compute the pmat matrix */
6071  for (i=0; i<nvtxs; i++) {
6072  me = where[i];
6073  pwgts[me] += vwgt[i];
6074  for (j=xadj[i]; j<xadj[i+1]; j++) {
6075  k = adjncy[j];
6076  if (where[k] != me)
6077  pmat[me*nparts+where[k]] += adjwgt[j];
6078  }
6079  }
6080 
6081  /* Compute the maximum allowed weight for each domain */
6082  tvwgt = idxsum(nparts, pwgts);
6083  for (i=0; i<nparts; i++)
6084  maxpwgt[i] = 1.25*tpwgts[i]*tvwgt;
6085 
6086  /* Determine the domain connectivity */
6087  for (i=0; i<nparts; i++) {
6088  for (k=0, j=0; j<nparts; j++) {
6089  if (pmat[i*nparts+j] > 0)
6090  k++;
6091  }
6092  ndoms[i] = k;
6093  }
6094 
6095  /* Get into the loop eliminating subdomain connections */
6096  for (;;) {
6097  total = idxsum(nparts, ndoms);
6098  avg = total/nparts;
6099  max = ndoms[idxamax(nparts, ndoms)];
6100 
6101  /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d\n", total, max, avg); */
6102 
6103  if (max < 1.5*avg)
6104  break;
6105 
6106  me = idxamax(nparts, ndoms);
6107  mypmat = pmat + me*nparts;
6108  totalout = idxsum(nparts, mypmat);
6109 
6110  /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/
6111 
6112  /* Sort the connections according to their cut */
6113  for (ncand2=0, i=0; i<nparts; i++) {
6114  if (mypmat[i] > 0) {
6115  cand2[ncand2].key = mypmat[i];
6116  cand2[ncand2++].val = i;
6117  }
6118  }
6119  ikeysort(ncand2, cand2);
6120 
6121  move = 0;
6122  for (min=0; min<ncand2; min++) {
6123  if (cand2[min].key > totalout/(2*ndoms[me]))
6124  break;
6125 
6126  other = cand2[min].val;
6127 
6128  /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/
6129 
6130  idxset(nparts, 0, otherpmat);
6131 
6132  /* Go and find the vertices in 'other' that are connected in 'me' */
6133  for (nind=0, i=0; i<nvtxs; i++) {
6134  if (where[i] == other) {
6135  for (j=xadj[i]; j<xadj[i+1]; j++) {
6136  if (where[adjncy[j]] == me) {
6137  ind[nind++] = i;
6138  break;
6139  }
6140  }
6141  }
6142  }
6143 
6144  /* Go and construct the otherpmat to see where these nind vertices are connected to */
6145  for (cpwgt=0, ii=0; ii<nind; ii++) {
6146  i = ind[ii];
6147  cpwgt += vwgt[i];
6148 
6149  for (j=xadj[i]; j<xadj[i+1]; j++) {
6150  k = adjncy[j];
6151  if (where[k] != other)
6152  otherpmat[where[k]] += adjwgt[j];
6153  }
6154  }
6155 
6156  for (ncand=0, i=0; i<nparts; i++) {
6157  if (otherpmat[i] > 0) {
6158  cand[ncand].key = -otherpmat[i];
6159  cand[ncand++].val = i;
6160  }
6161  }
6162  ikeysort(ncand, cand);
6163 
6164  /*
6165  * Go through and the select the first domain that is common with 'me', and
6166  * does not increase the ndoms[target] higher than my ndoms, subject to the
6167  * maxpwgt constraint. Traversal is done from the mostly connected to the least.
6168  */
6169  target = target2 = -1;
6170  for (i=0; i<ncand; i++) {
6171  k = cand[i].val;
6172 
6173  if (mypmat[k] > 0) {
6174  if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */
6175  continue;
6176 
6177  for (j=0; j<nparts; j++) {
6178  if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0)
6179  break;
6180  }
6181  if (j == nparts) { /* No bad second level effects */
6182  for (nadd=0, j=0; j<nparts; j++) {
6183  if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0)
6184  nadd++;
6185  }
6186 
6187  /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/
6188  if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) {
6189  target2 = k;
6190  }
6191  if (nadd == 0) {
6192  target = k;
6193  break;
6194  }
6195  }
6196  }
6197  }
6198  if (target == -1 && target2 != -1)
6199  target = target2;
6200 
6201  if (target == -1) {
6202  /* printf("\t\tCould not make the move\n");*/
6203  continue;
6204  }
6205 
6206  /*printf("\t\tMoving to %d\n", target);*/
6207 
6208  /* Update the partition weights */
6209  INC_DEC(pwgts[target], pwgts[other], cpwgt);
6210 
6211  /* Set all nind vertices to belong to 'target' */
6212  for (ii=0; ii<nind; ii++) {
6213  i = ind[ii];
6214  where[i] = target;
6215 
6216  /* First remove any contribution that this vertex may have made */
6217  for (j=xadj[i]; j<xadj[i+1]; j++) {
6218  k = adjncy[j];
6219  if (where[k] != other) {
6220  if (pmat[nparts*other + where[k]] == 0)
6221  printf("Something wrong\n");
6222  pmat[nparts*other + where[k]] -= adjwgt[j];
6223  if (pmat[nparts*other + where[k]] == 0)
6224  ndoms[other]--;
6225 
6226  if (pmat[nparts*where[k] + other] == 0)
6227  printf("Something wrong\n");
6228  pmat[nparts*where[k] + other] -= adjwgt[j];
6229  if (pmat[nparts*where[k] + other] == 0)
6230  ndoms[where[k]]--;
6231  }
6232  }
6233 
6234  /* Next add the new contributions as a result of the move */
6235  for (j=xadj[i]; j<xadj[i+1]; j++) {
6236  k = adjncy[j];
6237  if (where[k] != target) {
6238  if (pmat[nparts*target + where[k]] == 0)
6239  ndoms[target]++;
6240  pmat[nparts*target + where[k]] += adjwgt[j];
6241 
6242  if (pmat[nparts*where[k] + target] == 0)
6243  ndoms[where[k]]++;
6244  pmat[nparts*where[k] + target] += adjwgt[j];
6245  }
6246  }
6247  }
6248 
6249  move = 1;
6250  break;
6251  }
6252 
6253  if (move == 0)
6254  break;
6255  }
6256 
6257  idxwspacefree(ctrl, nparts);
6258  idxwspacefree(ctrl, nparts);
6259  idxwspacefree(ctrl, nparts);
6260  idxwspacefree(ctrl, nvtxs);
6261 
6262  GKfree((void **) &cand, (void **) &cand2, LTERM);
6263 }
6264 
6265 
6266 
6267 /*************************************************************************
6268 * This function finds all the connected components induced by the
6269 * partitioning vector in wgraph->where and tries to push them around to
6270 * remove some of them
6271 **************************************************************************/
6272 void EliminateVolComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
6273 {
6274  int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, ncand, other, target, deltawgt;
6275  idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt;
6276  idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps;
6277  KeyValueType *cand;
6278  int recompute=0;
6279 
6280  nvtxs = graph->nvtxs;
6281  xadj = graph->xadj;
6282  adjncy = graph->adjncy;
6283  vwgt = graph->vwgt;
6284  adjwgt = graph->adjwgt;
6285 
6286  where = graph->where;
6287  pwgts = idxset(nparts, 0, graph->pwgts);
6288 
6289  touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs));
6290  cptr = idxwspacemalloc(ctrl, nvtxs);
6291  cind = idxwspacemalloc(ctrl, nvtxs);
6292  perm = idxwspacemalloc(ctrl, nvtxs);
6293  todo = idxwspacemalloc(ctrl, nvtxs);
6294  maxpwgt = idxwspacemalloc(ctrl, nparts);
6295  cpvec = idxwspacemalloc(ctrl, nparts);
6296  npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts));
6297 
6298  for (i=0; i<nvtxs; i++)
6299  perm[i] = todo[i] = i;
6300 
6301  /* Find the connected componends induced by the partition */
6302  ncmps = -1;
6303  first = last = 0;
6304  nleft = nvtxs;
6305  while (nleft > 0) {
6306  if (first == last) { /* Find another starting vertex */
6307  cptr[++ncmps] = first;
6308  ASSERT(touched[todo[0]] == 0);
6309  i = todo[0];
6310  cind[last++] = i;
6311  touched[i] = 1;
6312  me = where[i];
6313  npcmps[me]++;
6314  }
6315 
6316  i = cind[first++];
6317  k = perm[i];
6318  j = todo[k] = todo[--nleft];
6319  perm[j] = k;
6320 
6321  for (j=xadj[i]; j<xadj[i+1]; j++) {
6322  k = adjncy[j];
6323  if (where[k] == me && !touched[k]) {
6324  cind[last++] = k;
6325  touched[k] = 1;
6326  }
6327  }
6328  }
6329  cptr[++ncmps] = first;
6330 
6331  /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */
6332 
6333  if (ncmps > nparts) { /* There are more components than processors */
6334  cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
6335 
6336  /* First determine the partition sizes and max allowed load imbalance */
6337  for (i=0; i<nvtxs; i++)
6338  pwgts[where[i]] += vwgt[i];
6339  tvwgt = idxsum(nparts, pwgts);
6340  for (i=0; i<nparts; i++)
6341  maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt;
6342 
6343  deltawgt = tvwgt/(100*nparts);
6344  deltawgt = 5;
6345 
6346  for (i=0; i<ncmps; i++) {
6347  me = where[cind[cptr[i]]]; /* Get the domain of this component */
6348  if (npcmps[me] == 1)
6349  continue; /* Skip it because it is contigous */
6350 
6351  /*printf("Trying to move %d from %d\n", i, me); */
6352 
6353  /* Determine the connectivity */
6354  idxset(nparts, 0, cpvec);
6355  for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++) {
6356  ii = cind[j];
6357  cwgt += vwgt[ii];
6358  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) {
6359  other = where[adjncy[jj]];
6360  if (me != other)
6361  cpvec[other] += adjwgt[jj];
6362  }
6363  }
6364 
6365  /*printf("\tCmp weight: %d\n", cwgt);*/
6366 
6367  if (cwgt > .30*pwgts[me])
6368  continue; /* Skip the component if it is over 30% of the weight */
6369 
6370  for (ncand=0, j=0; j<nparts; j++) {
6371  if (cpvec[j] > 0) {
6372  cand[ncand].key = -cpvec[j];
6373  cand[ncand++].val = j;
6374  }
6375  }
6376  if (ncand == 0)
6377  continue;
6378 
6379  ikeysort(ncand, cand);
6380 
6381  target = -1;
6382  for (j=0; j<ncand; j++) {
6383  k = cand[j].val;
6384  if (cwgt < deltawgt || pwgts[k] + cwgt < maxpwgt[k]) {
6385  target = k;
6386  break;
6387  }
6388  }
6389 
6390  /*printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/
6391 
6392  if (target != -1) {
6393  /* Assign all the vertices of 'me' to 'target' and update data structures */
6394  pwgts[me] -= cwgt;
6395  pwgts[target] += cwgt;
6396  npcmps[me]--;
6397 
6398  for (j=cptr[i]; j<cptr[i+1]; j++)
6399  where[cind[j]] = target;
6400 
6401  graph->mincut -= cpvec[target];
6402  recompute = 1;
6403  }
6404  }
6405 
6406  free(cand);
6407  }
6408 
6409  if (recompute) {
6410  int ttlv;
6411  idxtype *marker;
6412 
6413  marker = idxset(nparts, -1, cpvec);
6414  for (ttlv=0, i=0; i<nvtxs; i++) {
6415  marker[where[i]] = i;
6416  for (j=xadj[i]; j<xadj[i+1]; j++) {
6417  if (marker[where[adjncy[j]]] != i) {
6418  ttlv += graph->vsize[i];
6419  marker[where[adjncy[j]]] = i;
6420  }
6421  }
6422  }
6423  graph->minvol = ttlv;
6424  }
6425 
6426  idxwspacefree(ctrl, nparts);
6427  idxwspacefree(ctrl, nparts);
6428  idxwspacefree(ctrl, nparts);
6429  idxwspacefree(ctrl, nvtxs);
6430  idxwspacefree(ctrl, nvtxs);
6431  idxwspacefree(ctrl, nvtxs);
6432  idxwspacefree(ctrl, nvtxs);
6433  idxwspacefree(ctrl, nvtxs);
6434 
6435 }
6436 
6437 /*
6438  * Copyright 1997, Regents of the University of Minnesota
6439  *
6440  * kwayvolrefine.c
6441  *
6442  * This file contains the driving routines for multilevel k-way refinement
6443  *
6444  * Started 7/28/97
6445  * George
6446  *
6447  * $Id$
6448  */
6449 
6450 
6451 
6452 
6453 /*************************************************************************
6454 * This function is the entry point of refinement
6455 **************************************************************************/
6456 void RefineVolKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts,
6457  float *tpwgts, float ubfactor)
6458 {
6459  int i, nlevels;
6460  GraphType *ptr;
6461 
6462  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
6463 
6464  /* Take care any non-contiguity */
6465  if (ctrl->RType == RTYPE_KWAYRANDOM_MCONN) {
6466  ComputeVolKWayPartitionParams(ctrl, graph, nparts);
6467  EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25);
6468  EliminateVolSubDomainEdges(ctrl, graph, nparts, tpwgts);
6469  EliminateVolComponents(ctrl, graph, nparts, tpwgts, 1.25);
6470  }
6471 
6472 
6473  /* Determine how many levels are there */
6474  for (ptr=graph, nlevels=0; ptr!=orggraph; ptr=ptr->finer, nlevels++);
6475 
6476  /* Compute the parameters of the coarsest graph */
6477  ComputeVolKWayPartitionParams(ctrl, graph, nparts);
6478 
6479  for (i=0; ;i++) {
6480  /*PrintSubDomainGraph(graph, nparts, graph->where);*/
6481  MALLOC_CHECK(NULL);
6482  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
6483 
6484  if (2*i >= nlevels && !IsBalanced(graph->pwgts, nparts, tpwgts, 1.04*ubfactor)) {
6485  ComputeVolKWayBalanceBoundary(ctrl, graph, nparts);
6486  switch (ctrl->RType) {
6487  case RTYPE_KWAYRANDOM:
6488  Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 1);
6489  break;
6491  Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 1);
6492  break;
6493  }
6494  ComputeVolKWayBoundary(ctrl, graph, nparts);
6495  }
6496 
6497  switch (ctrl->RType) {
6498  case RTYPE_KWAYRANDOM:
6499  Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
6500  break;
6502  Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
6503  break;
6504  }
6505  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
6506 
6507  if (graph == orggraph)
6508  break;
6509 
6510  GKfree((void **) &graph->gdata, LTERM); /* Deallocate the graph related arrays */
6511 
6512  graph = graph->finer;
6513 
6514  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
6515  ProjectVolKWayPartition(ctrl, graph, nparts);
6516  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
6517  }
6518 
6519  if (!IsBalanced(graph->pwgts, nparts, tpwgts, ubfactor)) {
6520  ComputeVolKWayBalanceBoundary(ctrl, graph, nparts);
6521  switch (ctrl->RType) {
6522  case RTYPE_KWAYRANDOM:
6523  Greedy_KWayVolBalance(ctrl, graph, nparts, tpwgts, ubfactor, 8);
6524  Random_KWayVolRefine(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
6525  break;
6527  Greedy_KWayVolBalanceMConn(ctrl, graph, nparts, tpwgts, ubfactor, 8);
6528  Random_KWayVolRefineMConn(ctrl, graph, nparts, tpwgts, ubfactor, 10, 0);
6529  break;
6530  }
6531  }
6532 
6533  EliminateVolComponents(ctrl, graph, nparts, tpwgts, ubfactor);
6534 
6535  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
6536 }
6537 
6538 
6539 
6540 /*************************************************************************
6541 * This function allocates memory for k-way edge refinement
6542 **************************************************************************/
6543 void AllocateVolKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
6544 {
6545  int nvtxs, pad64;
6546 
6547  nvtxs = graph->nvtxs;
6548 
6549  pad64 = (3*nvtxs+nparts)%2;
6550 
6551  graph->rdata = idxmalloc(3*nvtxs+nparts+(sizeof(VRInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateVolKWayPartitionMemory: rdata");
6552  graph->pwgts = graph->rdata;
6553  graph->where = graph->rdata + nparts;
6554  graph->bndptr = graph->rdata + nvtxs + nparts;
6555  graph->bndind = graph->rdata + 2*nvtxs + nparts;
6556  graph->vrinfo = (VRInfoType *)(graph->rdata + 3*nvtxs+nparts + pad64);
6557 
6558 }
6559 
6560 
6561 
6562 /*************************************************************************
6563 * This function computes the initial id/ed
6564 **************************************************************************/
6565 void ComputeVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
6566 {
6567  int i, j, k, nvtxs, mincut, me, other;
6568  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts, *where;
6569  VRInfoType *rinfo, *myrinfo;
6570  VEDegreeType *myedegrees;
6571 
6572  nvtxs = graph->nvtxs;
6573  xadj = graph->xadj;
6574  vwgt = graph->vwgt;
6575  adjncy = graph->adjncy;
6576  adjwgt = graph->adjwgt;
6577 
6578  where = graph->where;
6579  pwgts = idxset(nparts, 0, graph->pwgts);
6580  rinfo = graph->vrinfo;
6581 
6582 
6583  /*------------------------------------------------------------
6584  / Compute now the id/ed degrees
6585  /------------------------------------------------------------*/
6586  ctrl->wspace.cdegree = 0;
6587  mincut = 0;
6588  for (i=0; i<nvtxs; i++) {
6589  me = where[i];
6590  pwgts[me] += vwgt[i];
6591 
6592  myrinfo = rinfo+i;
6593  myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0;
6594  myrinfo->edegrees = NULL;
6595 
6596  for (j=xadj[i]; j<xadj[i+1]; j++) {
6597  if (me == where[adjncy[j]]) {
6598  myrinfo->id += adjwgt[j];
6599  myrinfo->nid++;
6600  }
6601  }
6602  myrinfo->ed = graph->adjwgtsum[i] - myrinfo->id;
6603 
6604  mincut += myrinfo->ed;
6605 
6606  /* Time to compute the particular external degrees */
6607  if (myrinfo->ed > 0) {
6608  myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree;
6609  ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
6610 
6611  for (j=xadj[i]; j<xadj[i+1]; j++) {
6612  other = where[adjncy[j]];
6613  if (me != other) {
6614  for (k=0; k<myrinfo->ndegrees; k++) {
6615  if (myedegrees[k].pid == other) {
6616  myedegrees[k].ed += adjwgt[j];
6617  myedegrees[k].ned++;
6618  break;
6619  }
6620  }
6621  if (k == myrinfo->ndegrees) {
6622  myedegrees[myrinfo->ndegrees].gv = 0;
6623  myedegrees[myrinfo->ndegrees].pid = other;
6624  myedegrees[myrinfo->ndegrees].ed = adjwgt[j];
6625  myedegrees[myrinfo->ndegrees++].ned = 1;
6626  }
6627  }
6628  }
6629 
6630  ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
6631  }
6632  }
6633  graph->mincut = mincut/2;
6634 
6635 
6636  ComputeKWayVolGains(ctrl, graph, nparts);
6637 
6638 }
6639 
6640 
6641 
6642 /*************************************************************************
6643 * This function computes the initial id/ed
6644 **************************************************************************/
6645 void ComputeKWayVolGains(CtrlType *ctrl, GraphType *graph, int nparts)
6646 {
6647  int i, ii, j, k, kk, nvtxs, me, other, myndegrees;
6648  idxtype *xadj, *vsize, *adjncy, *adjwgt, *where, *bndind, *bndptr, *ophtable;
6649  VRInfoType *rinfo, *myrinfo, *orinfo;
6650  VEDegreeType *myedegrees, *oedegrees;
6651 
6652  nvtxs = graph->nvtxs;
6653  xadj = graph->xadj;
6654  vsize = graph->vsize;
6655  adjncy = graph->adjncy;
6656  adjwgt = graph->adjwgt;
6657 
6658  where = graph->where;
6659  bndind = graph->bndind;
6660  bndptr = idxset(nvtxs, -1, graph->bndptr);
6661  rinfo = graph->vrinfo;
6662 
6663  ophtable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
6664 
6665  /*------------------------------------------------------------
6666  / Compute now the iv/ev degrees
6667  /------------------------------------------------------------*/
6668  graph->minvol = graph->nbnd = 0;
6669  for (i=0; i<nvtxs; i++) {
6670  myrinfo = rinfo+i;
6671  myrinfo->gv = -MAXIDX;
6672 
6673  if (myrinfo->ndegrees > 0) {
6674  me = where[i];
6675  myedegrees = myrinfo->edegrees;
6676  myndegrees = myrinfo->ndegrees;
6677 
6678  graph->minvol += myndegrees*vsize[i];
6679 
6680  for (j=xadj[i]; j<xadj[i+1]; j++) {
6681  ii = adjncy[j];
6682  other = where[ii];
6683  orinfo = rinfo+ii;
6684  oedegrees = orinfo->edegrees;
6685 
6686  for (k=0; k<orinfo->ndegrees; k++)
6687  ophtable[oedegrees[k].pid] = k;
6688  ophtable[other] = 1; /* this is to simplify coding */
6689 
6690  if (me == other) {
6691  /* Find which domains 'i' is connected and 'ii' is not and update their gain */
6692  for (k=0; k<myndegrees; k++) {
6693  if (ophtable[myedegrees[k].pid] == -1)
6694  myedegrees[k].gv -= vsize[ii];
6695  }
6696  }
6697  else {
6698  ASSERT(ophtable[me] != -1);
6699 
6700  if (oedegrees[ophtable[me]].ned == 1) { /* I'm the only connection of 'ii' in 'me' */
6701  /* Increase the gains for all the common domains between 'i' and 'ii' */
6702  for (k=0; k<myndegrees; k++) {
6703  if (ophtable[myedegrees[k].pid] != -1)
6704  myedegrees[k].gv += vsize[ii];
6705  }
6706  }
6707  else {
6708  /* Find which domains 'i' is connected and 'ii' is not and update their gain */
6709  for (k=0; k<myndegrees; k++) {
6710  if (ophtable[myedegrees[k].pid] == -1)
6711  myedegrees[k].gv -= vsize[ii];
6712  }
6713  }
6714  }
6715 
6716  for (kk=0; kk<orinfo->ndegrees; kk++)
6717  ophtable[oedegrees[kk].pid] = -1;
6718  ophtable[other] = -1;
6719  }
6720 
6721  /* Compute the max vgain */
6722  for (k=0; k<myndegrees; k++) {
6723  if (myedegrees[k].gv > myrinfo->gv)
6724  myrinfo->gv = myedegrees[k].gv;
6725  }
6726  }
6727 
6728  if (myrinfo->ed > 0 && myrinfo->id == 0)
6729  myrinfo->gv += vsize[i];
6730 
6731  if (myrinfo->gv >= 0 || myrinfo->ed-myrinfo->id >= 0)
6732  BNDInsert(graph->nbnd, bndind, bndptr, i);
6733  }
6734 
6735  idxwspacefree(ctrl, nparts);
6736 
6737 }
6738 
6739 
6740 
6741 /*************************************************************************
6742 * This function projects a partition, and at the same time computes the
6743 * parameters for refinement.
6744 **************************************************************************/
6745 void ProjectVolKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
6746 {
6747  int i, j, k, nvtxs, me, other, istart, iend, ndegrees;
6748  idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
6749  idxtype *cmap, *where;
6750  idxtype *cwhere;
6751  GraphType *cgraph;
6752  VRInfoType *crinfo, *rinfo, *myrinfo;
6753  VEDegreeType *myedegrees;
6754  idxtype *htable;
6755 
6756  cgraph = graph->coarser;
6757  cwhere = cgraph->where;
6758  crinfo = cgraph->vrinfo;
6759 
6760  nvtxs = graph->nvtxs;
6761  cmap = graph->cmap;
6762  xadj = graph->xadj;
6763  adjncy = graph->adjncy;
6764  adjwgt = graph->adjwgt;
6765  adjwgtsum = graph->adjwgtsum;
6766 
6767  AllocateVolKWayPartitionMemory(ctrl, graph, nparts);
6768  where = graph->where;
6769  rinfo = graph->vrinfo;
6770 
6771  /* Go through and project partition and compute id/ed for the nodes */
6772  for (i=0; i<nvtxs; i++) {
6773  k = cmap[i];
6774  where[i] = cwhere[k];
6775  cmap[i] = crinfo[k].ed; /* For optimization */
6776  }
6777 
6778  htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
6779 
6780  ctrl->wspace.cdegree = 0;
6781  for (i=0; i<nvtxs; i++) {
6782  me = where[i];
6783 
6784  myrinfo = rinfo+i;
6785  myrinfo->id = myrinfo->ed = myrinfo->nid = myrinfo->ndegrees = 0;
6786  myrinfo->edegrees = NULL;
6787 
6788  myrinfo->id = adjwgtsum[i];
6789  myrinfo->nid = xadj[i+1]-xadj[i];
6790 
6791  if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */
6792  istart = xadj[i];
6793  iend = xadj[i+1];
6794 
6795  myedegrees = myrinfo->edegrees = ctrl->wspace.vedegrees+ctrl->wspace.cdegree;
6796  ctrl->wspace.cdegree += iend-istart;
6797 
6798  ndegrees = 0;
6799  for (j=istart; j<iend; j++) {
6800  other = where[adjncy[j]];
6801  if (me != other) {
6802  myrinfo->ed += adjwgt[j];
6803  myrinfo->nid--;
6804  if ((k = htable[other]) == -1) {
6805  htable[other] = ndegrees;
6806  myedegrees[ndegrees].gv = 0;
6807  myedegrees[ndegrees].pid = other;
6808  myedegrees[ndegrees].ed = adjwgt[j];
6809  myedegrees[ndegrees++].ned = 1;
6810  }
6811  else {
6812  myedegrees[k].ed += adjwgt[j];
6813  myedegrees[k].ned++;
6814  }
6815  }
6816  }
6817  myrinfo->id -= myrinfo->ed;
6818 
6819  /* Remove space for edegrees if it was interior */
6820  if (myrinfo->ed == 0) {
6821  myrinfo->edegrees = NULL;
6822  ctrl->wspace.cdegree -= iend-istart;
6823  }
6824  else {
6825  myrinfo->ndegrees = ndegrees;
6826 
6827  for (j=0; j<ndegrees; j++)
6828  htable[myedegrees[j].pid] = -1;
6829  }
6830  }
6831  }
6832 
6833  ComputeKWayVolGains(ctrl, graph, nparts);
6834 
6835  idxcopy(nparts, cgraph->pwgts, graph->pwgts);
6836  graph->mincut = cgraph->mincut;
6837 
6838  FreeGraph(graph->coarser);
6839  graph->coarser = NULL;
6840 
6841  idxwspacefree(ctrl, nparts);
6842 
6843 }
6844 
6845 
6846 
6847 /*************************************************************************
6848 * This function computes the boundary definition for balancing
6849 **************************************************************************/
6850 void ComputeVolKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
6851 {
6852  int i, nvtxs, nbnd;
6853  idxtype *bndind, *bndptr;
6854 
6855  nvtxs = graph->nvtxs;
6856  bndind = graph->bndind;
6857  bndptr = idxset(nvtxs, -1, graph->bndptr);
6858 
6859 
6860  /*------------------------------------------------------------
6861  / Compute the new boundary
6862  /------------------------------------------------------------*/
6863  nbnd = 0;
6864  for (i=0; i<nvtxs; i++) {
6865  if (graph->vrinfo[i].gv >=0 || graph->vrinfo[i].ed-graph->vrinfo[i].id >= 0)
6866  BNDInsert(nbnd, bndind, bndptr, i);
6867  }
6868 
6869  graph->nbnd = nbnd;
6870 }
6871 
6872 /*************************************************************************
6873 * This function computes the boundary definition for balancing
6874 **************************************************************************/
6875 void ComputeVolKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
6876 {
6877  int i, nvtxs, nbnd;
6878  idxtype *bndind, *bndptr;
6879 
6880  nvtxs = graph->nvtxs;
6881  bndind = graph->bndind;
6882  bndptr = idxset(nvtxs, -1, graph->bndptr);
6883 
6884 
6885  /*------------------------------------------------------------
6886  / Compute the new boundary
6887  /------------------------------------------------------------*/
6888  nbnd = 0;
6889  for (i=0; i<nvtxs; i++) {
6890  if (graph->vrinfo[i].ed > 0)
6891  BNDInsert(nbnd, bndind, bndptr, i);
6892  }
6893 
6894  graph->nbnd = nbnd;
6895 }
6896 
6897 /*
6898  * Copyright 1997, Regents of the University of Minnesota
6899  *
6900  * match.c
6901  *
6902  * This file contains the code that computes matchings and creates the next
6903  * level coarse graph.
6904  *
6905  * Started 7/23/97
6906  * George
6907  *
6908  * $Id$
6909  *
6910  */
6911 
6912 
6913 
6914 
6915 /*************************************************************************
6916 * This function finds a matching using the HEM heuristic
6917 **************************************************************************/
6918 void Match_RM(CtrlType *ctrl, GraphType *graph)
6919 {
6920  int i, ii, j, nvtxs, cnvtxs, maxidx;
6921  idxtype *xadj, *vwgt, *adjncy, *adjwgt;
6922  idxtype *match, *cmap, *perm;
6923 
6924  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
6925 
6926  nvtxs = graph->nvtxs;
6927  xadj = graph->xadj;
6928  vwgt = graph->vwgt;
6929  adjncy = graph->adjncy;
6930  adjwgt = graph->adjwgt;
6931 
6932  cmap = graph->cmap;
6933  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
6934 
6935  perm = idxwspacemalloc(ctrl, nvtxs);
6936  RandomPermute(nvtxs, perm, 1);
6937 
6938  cnvtxs = 0;
6939  for (ii=0; ii<nvtxs; ii++) {
6940  i = perm[ii];
6941 
6942  if (match[i] == UNMATCHED) { /* Unmatched */
6943  maxidx = i;
6944 
6945  /* Find a random matching, subject to maxvwgt constraints */
6946  for (j=xadj[i]; j<xadj[i+1]; j++) {
6947  if (match[adjncy[j]] == UNMATCHED && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) {
6948  maxidx = adjncy[j];
6949  break;
6950  }
6951  }
6952 
6953  cmap[i] = cmap[maxidx] = cnvtxs++;
6954  match[i] = maxidx;
6955  match[maxidx] = i;
6956  }
6957  }
6958 
6959  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
6960 
6961  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
6962 
6963  idxwspacefree(ctrl, nvtxs);
6964  idxwspacefree(ctrl, nvtxs);
6965 }
6966 
6967 
6968 /*************************************************************************
6969 * This function finds a matching using the HEM heuristic
6970 **************************************************************************/
6971 void Match_RM_NVW(CtrlType *ctrl, GraphType *graph)
6972 {
6973  int i, ii, j, nvtxs, cnvtxs, maxidx;
6974  idxtype *xadj, *adjncy;
6975  idxtype *match, *cmap, *perm;
6976 
6977  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
6978 
6979  nvtxs = graph->nvtxs;
6980  xadj = graph->xadj;
6981  adjncy = graph->adjncy;
6982 
6983  cmap = graph->cmap;
6984  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
6985 
6986  perm = idxwspacemalloc(ctrl, nvtxs);
6987  RandomPermute(nvtxs, perm, 1);
6988 
6989  cnvtxs = 0;
6990  for (ii=0; ii<nvtxs; ii++) {
6991  i = perm[ii];
6992 
6993  if (match[i] == UNMATCHED) { /* Unmatched */
6994  maxidx = i;
6995 
6996  /* Find a random matching, subject to maxvwgt constraints */
6997  for (j=xadj[i]; j<xadj[i+1]; j++) {
6998  if (match[adjncy[j]] == UNMATCHED) {
6999  maxidx = adjncy[j];
7000  break;
7001  }
7002  }
7003 
7004  cmap[i] = cmap[maxidx] = cnvtxs++;
7005  match[i] = maxidx;
7006  match[maxidx] = i;
7007  }
7008  }
7009 
7010  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
7011 
7012  CreateCoarseGraph_NVW(ctrl, graph, cnvtxs, match, perm);
7013 
7014  idxwspacefree(ctrl, nvtxs);
7015  idxwspacefree(ctrl, nvtxs);
7016 }
7017 
7018 
7019 
7020 /*************************************************************************
7021 * This function finds a matching using the HEM heuristic
7022 **************************************************************************/
7023 void Match_HEM(CtrlType *ctrl, GraphType *graph)
7024 {
7025  int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt;
7026  idxtype *xadj, *vwgt, *adjncy, *adjwgt;
7027  idxtype *match, *cmap, *perm;
7028 
7029  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
7030 
7031  nvtxs = graph->nvtxs;
7032  xadj = graph->xadj;
7033  vwgt = graph->vwgt;
7034  adjncy = graph->adjncy;
7035  adjwgt = graph->adjwgt;
7036 
7037  cmap = graph->cmap;
7038  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
7039 
7040  perm = idxwspacemalloc(ctrl, nvtxs);
7041  RandomPermute(nvtxs, perm, 1);
7042 
7043  cnvtxs = 0;
7044  for (ii=0; ii<nvtxs; ii++) {
7045  i = perm[ii];
7046 
7047  if (match[i] == UNMATCHED) { /* Unmatched */
7048  maxidx = i;
7049  maxwgt = 0;
7050 
7051  /* Find a heavy-edge matching, subject to maxvwgt constraints */
7052  for (j=xadj[i]; j<xadj[i+1]; j++) {
7053  k = adjncy[j];
7054  if (match[k] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[k] <= ctrl->maxvwgt) {
7055  maxwgt = adjwgt[j];
7056  maxidx = adjncy[j];
7057  }
7058  }
7059 
7060  cmap[i] = cmap[maxidx] = cnvtxs++;
7061  match[i] = maxidx;
7062  match[maxidx] = i;
7063  }
7064  }
7065 
7066  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
7067 
7068  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
7069 
7070  idxwspacefree(ctrl, nvtxs);
7071  idxwspacefree(ctrl, nvtxs);
7072 }
7073 
7074 
7075 
7076 /*************************************************************************
7077 * This function finds a matching using the HEM heuristic
7078 **************************************************************************/
7079 void Match_SHEM(CtrlType *ctrl, GraphType *graph)
7080 {
7081  int i, ii, j, k, nvtxs, cnvtxs, maxidx, maxwgt, avgdegree;
7082  idxtype *xadj, *vwgt, *adjncy, *adjwgt;
7083  idxtype *match, *cmap, *degrees, *perm, *tperm;
7084 
7085  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
7086 
7087  nvtxs = graph->nvtxs;
7088  xadj = graph->xadj;
7089  vwgt = graph->vwgt;
7090  adjncy = graph->adjncy;
7091  adjwgt = graph->adjwgt;
7092 
7093  cmap = graph->cmap;
7094  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
7095 
7096  perm = idxwspacemalloc(ctrl, nvtxs);
7097  tperm = idxwspacemalloc(ctrl, nvtxs);
7098  degrees = idxwspacemalloc(ctrl, nvtxs);
7099 
7100  RandomPermute(nvtxs, tperm, 1);
7101  avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
7102  for (i=0; i<nvtxs; i++)
7103  degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
7104  BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
7105 
7106  cnvtxs = 0;
7107 
7108  /* Take care any islands. Islands are matched with non-islands due to coarsening */
7109  for (ii=0; ii<nvtxs; ii++) {
7110  i = perm[ii];
7111 
7112  if (match[i] == UNMATCHED) { /* Unmatched */
7113  if (xadj[i] < xadj[i+1])
7114  break;
7115 
7116  maxidx = i;
7117  for (j=nvtxs-1; j>ii; j--) {
7118  k = perm[j];
7119  if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
7120  maxidx = k;
7121  break;
7122  }
7123  }
7124 
7125  cmap[i] = cmap[maxidx] = cnvtxs++;
7126  match[i] = maxidx;
7127  match[maxidx] = i;
7128  }
7129  }
7130 
7131  /* Continue with normal matching */
7132  for (; ii<nvtxs; ii++) {
7133  i = perm[ii];
7134 
7135  if (match[i] == UNMATCHED) { /* Unmatched */
7136  maxidx = i;
7137  maxwgt = 0;
7138 
7139  /* Find a heavy-edge matching, subject to maxvwgt constraints */
7140  for (j=xadj[i]; j<xadj[i+1]; j++) {
7141  if (match[adjncy[j]] == UNMATCHED && maxwgt < adjwgt[j] && vwgt[i]+vwgt[adjncy[j]] <= ctrl->maxvwgt) {
7142  maxwgt = adjwgt[j];
7143  maxidx = adjncy[j];
7144  }
7145  }
7146 
7147  cmap[i] = cmap[maxidx] = cnvtxs++;
7148  match[i] = maxidx;
7149  match[maxidx] = i;
7150  }
7151  }
7152 
7153  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
7154 
7155  idxwspacefree(ctrl, nvtxs); /* degrees */
7156  idxwspacefree(ctrl, nvtxs); /* tperm */
7157 
7158  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
7159 
7160  idxwspacefree(ctrl, nvtxs);
7161  idxwspacefree(ctrl, nvtxs);
7162 }
7163 
7164 /*
7165  * Copyright 1997, Regents of the University of Minnesota
7166  *
7167  * mbalance2.c
7168  *
7169  * This file contains code that is used to forcefully balance either
7170  * bisections or k-sections
7171  *
7172  * Started 7/29/97
7173  * George
7174  *
7175  * $Id$
7176  *
7177  */
7178 
7179 
7180 
7181 
7182 /*************************************************************************
7183 * This function is the entry point of the bisection balancing algorithms.
7184 **************************************************************************/
7185 void MocBalance2Way2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
7186 {
7187  float tvec[MAXNCON];
7188 
7189  Compute2WayHLoadImbalanceVec(graph->ncon, graph->npwgts, tpwgts, tvec);
7190  if (!AreAllBelow(graph->ncon, tvec, ubvec))
7191  MocGeneral2WayBalance2(ctrl, graph, tpwgts, ubvec);
7192 }
7193 
7194 
7195 
7196 /*************************************************************************
7197 * This function performs an edge-based FM refinement
7198 **************************************************************************/
7199 void MocGeneral2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
7200 {
7201  int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, limit, tmp, cnum;
7202  idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
7203  idxtype *moved, *swaps, *perm, *qnum;
7204  float *nvwgt, *npwgts, origbal[MAXNCON], minbal[MAXNCON], newbal[MAXNCON];
7205  PQueueType parts[MAXNCON][2];
7206  int higain, oldgain, mincut, newcut, mincutorder;
7207  float *maxwgt, *minwgt, tvec[MAXNCON];
7208 
7209 
7210  nvtxs = graph->nvtxs;
7211  ncon = graph->ncon;
7212  xadj = graph->xadj;
7213  nvwgt = graph->nvwgt;
7214  adjncy = graph->adjncy;
7215  adjwgt = graph->adjwgt;
7216  where = graph->where;
7217  id = graph->id;
7218  ed = graph->ed;
7219  npwgts = graph->npwgts;
7220  bndptr = graph->bndptr;
7221  bndind = graph->bndind;
7222 
7223  moved = idxwspacemalloc(ctrl, nvtxs);
7224  swaps = idxwspacemalloc(ctrl, nvtxs);
7225  perm = idxwspacemalloc(ctrl, nvtxs);
7226  qnum = idxwspacemalloc(ctrl, nvtxs);
7227 
7228  limit = amin(amax(0.01*nvtxs, 15), 100);
7229 
7230  /* Setup the weight intervals of the two subdomains */
7231  minwgt = fwspacemalloc(ctrl, 2*ncon);
7232  maxwgt = fwspacemalloc(ctrl, 2*ncon);
7233 
7234  for (i=0; i<2; i++) {
7235  for (j=0; j<ncon; j++) {
7236  maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j];
7237  minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]);
7238  }
7239  }
7240 
7241 
7242  /* Initialize the queues */
7243  for (i=0; i<ncon; i++) {
7244  PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
7245  PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
7246  }
7247  for (i=0; i<nvtxs; i++)
7248  qnum[i] = samax(ncon, nvwgt+i*ncon);
7249 
7250  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal);
7251  for (i=0; i<ncon; i++)
7252  minbal[i] = origbal[i];
7253 
7254  newcut = mincut = graph->mincut;
7255  mincutorder = -1;
7256 
7257  if (ctrl->dbglvl&DBG_REFINE) {
7258  printf("Parts: [");
7259  for (l=0; l<ncon; l++)
7260  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
7261  printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1],
7262  graph->nvtxs, graph->nbnd, graph->mincut);
7263  for (i=0; i<ncon; i++)
7264  printf("%.3f ", origbal[i]);
7265  printf("[B]\n");
7266  }
7267 
7268  idxset(nvtxs, -1, moved);
7269 
7270  ASSERT(ComputeCut(graph, where) == graph->mincut);
7271  ASSERT(CheckBnd(graph));
7272 
7273  /* Insert all nodes in the priority queues */
7274  nbnd = graph->nbnd;
7275  RandomPermute(nvtxs, perm, 1);
7276  for (ii=0; ii<nvtxs; ii++) {
7277  i = perm[ii];
7278  PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
7279  }
7280 
7281 
7282  for (nswaps=0; nswaps<nvtxs; nswaps++) {
7283  if (AreAllBelow(ncon, minbal, ubvec))
7284  break;
7285 
7286  SelectQueue3(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt);
7287  to = (from+1)%2;
7288 
7289  if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
7290  break;
7291 
7292  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
7293  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
7294  newcut -= (ed[higain]-id[higain]);
7295  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, newbal);
7296 
7297  if (IsBetter2wayBalance(ncon, newbal, minbal, ubvec) ||
7298  (IsBetter2wayBalance(ncon, newbal, origbal, ubvec) && newcut < mincut)) {
7299  mincut = newcut;
7300  for (i=0; i<ncon; i++)
7301  minbal[i] = newbal[i];
7302  mincutorder = nswaps;
7303  }
7304  else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
7305  newcut += (ed[higain]-id[higain]);
7306  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
7307  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
7308  break;
7309  }
7310 
7311  where[higain] = to;
7312  moved[higain] = nswaps;
7313  swaps[nswaps] = higain;
7314 
7315  if (ctrl->dbglvl&DBG_MOVEINFO) {
7316  printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
7317  for (i=0; i<ncon; i++)
7318  printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]);
7319 
7320  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
7321  printf(", LB: ");
7322  for (i=0; i<ncon; i++)
7323  printf("%.3f ", tvec[i]);
7324  if (mincutorder == nswaps)
7325  printf(" *\n");
7326  else
7327  printf("\n");
7328  }
7329 
7330 
7331  /**************************************************************
7332  * Update the id[i]/ed[i] values of the affected nodes
7333  ***************************************************************/
7334  SWAP(id[higain], ed[higain], tmp);
7335  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
7336  BNDDelete(nbnd, bndind, bndptr, higain);
7337  if (ed[higain] > 0 && bndptr[higain] == -1)
7338  BNDInsert(nbnd, bndind, bndptr, higain);
7339 
7340  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
7341  k = adjncy[j];
7342  oldgain = ed[k]-id[k];
7343 
7344  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
7345  INC_DEC(id[k], ed[k], kwgt);
7346 
7347  /* Update the queue position */
7348  if (moved[k] == -1)
7349  PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
7350 
7351  /* Update its boundary information */
7352  if (ed[k] == 0 && bndptr[k] != -1)
7353  BNDDelete(nbnd, bndind, bndptr, k);
7354  else if (ed[k] > 0 && bndptr[k] == -1)
7355  BNDInsert(nbnd, bndind, bndptr, k);
7356  }
7357 
7358  }
7359 
7360 
7361 
7362  /****************************************************************
7363  * Roll back computations
7364  *****************************************************************/
7365  for (i=0; i<nswaps; i++)
7366  moved[swaps[i]] = -1; /* reset moved array */
7367  for (nswaps--; nswaps>mincutorder; nswaps--) {
7368  higain = swaps[nswaps];
7369 
7370  to = where[higain] = (where[higain]+1)%2;
7371  SWAP(id[higain], ed[higain], tmp);
7372  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
7373  BNDDelete(nbnd, bndind, bndptr, higain);
7374  else if (ed[higain] > 0 && bndptr[higain] == -1)
7375  BNDInsert(nbnd, bndind, bndptr, higain);
7376 
7377  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
7378  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1);
7379  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
7380  k = adjncy[j];
7381 
7382  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
7383  INC_DEC(id[k], ed[k], kwgt);
7384 
7385  if (bndptr[k] != -1 && ed[k] == 0)
7386  BNDDelete(nbnd, bndind, bndptr, k);
7387  if (bndptr[k] == -1 && ed[k] > 0)
7388  BNDInsert(nbnd, bndind, bndptr, k);
7389  }
7390  }
7391 
7392  if (ctrl->dbglvl&DBG_REFINE) {
7393  printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
7394  for (i=0; i<ncon; i++)
7395  printf("(%.3f, %.3f) ", npwgts[i], npwgts[ncon+i]);
7396  printf("], LB: ");
7397  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
7398  for (i=0; i<ncon; i++)
7399  printf("%.3f ", tvec[i]);
7400  printf("\n");
7401  }
7402 
7403  graph->mincut = mincut;
7404  graph->nbnd = nbnd;
7405 
7406 
7407  for (i=0; i<ncon; i++) {
7408  PQueueFree(ctrl, &parts[i][0]);
7409  PQueueFree(ctrl, &parts[i][1]);
7410  }
7411 
7412  idxwspacefree(ctrl, nvtxs);
7413  idxwspacefree(ctrl, nvtxs);
7414  idxwspacefree(ctrl, nvtxs);
7415  idxwspacefree(ctrl, nvtxs);
7416  fwspacefree(ctrl, 2*ncon);
7417  fwspacefree(ctrl, 2*ncon);
7418 
7419 }
7420 
7421 
7422 
7423 
7424 /*************************************************************************
7425 * This function selects the partition number and the queue from which
7426 * we will move vertices out
7427 **************************************************************************/
7428 void SelectQueue3(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum,
7429  PQueueType queues[MAXNCON][2], float *maxwgt)
7430 {
7431  int i, j, maxgain=0;
7432  float maxdiff=0.0, diff;
7433 
7434  *from = -1;
7435  *cnum = -1;
7436 
7437  /* First determine the side and the queue, irrespective of the presence of nodes */
7438  for (j=0; j<2; j++) {
7439  for (i=0; i<ncon; i++) {
7440  diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i];
7441  if (diff >= maxdiff) {
7442  maxdiff = diff;
7443  *from = j;
7444  *cnum = i;
7445  }
7446  }
7447  }
7448 
7449 /* DELETE
7450 j = *from;
7451 for (i=0; i<ncon; i++)
7452  printf("[%5d %5d %.4f %.4f] ", i, PQueueGetSize(&queues[i][j]), npwgts[j*ncon+i], maxwgt[j*ncon+i]);
7453 printf("***[%5d %5d]\n", *cnum, *from);
7454 */
7455 
7456  /* If the desired queue is empty, select a node from that side anyway */
7457  if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
7458  for (i=0; i<ncon; i++) {
7459  if (PQueueGetSize(&queues[i][*from]) > 0) {
7460  maxdiff = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]);
7461  *cnum = i;
7462  break;
7463  }
7464  }
7465 
7466  for (i++; i<ncon; i++) {
7467  diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i];
7468  if (diff > maxdiff && PQueueGetSize(&queues[i][*from]) > 0) {
7469  maxdiff = diff;
7470  *cnum = i;
7471  }
7472  }
7473  }
7474 
7475  /* If the constraints ar OK, select a high gain vertex */
7476  if (*from == -1) {
7477  maxgain = -100000;
7478  for (j=0; j<2; j++) {
7479  for (i=0; i<ncon; i++) {
7480  if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) {
7481  maxgain = PQueueGetKey(&queues[i][0]);
7482  *from = j;
7483  *cnum = i;
7484  }
7485  }
7486  }
7487 
7488  /* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */
7489  }
7490 }
7491 /*
7492  * Copyright 1997, Regents of the University of Minnesota
7493  *
7494  * mbalance.c
7495  *
7496  * This file contains code that is used to forcefully balance either
7497  * bisections or k-sections
7498  *
7499  * Started 7/29/97
7500  * George
7501  *
7502  * $Id$
7503  *
7504  */
7505 
7506 
7507 
7508 
7509 /*************************************************************************
7510 * This function is the entry point of the bisection balancing algorithms.
7511 **************************************************************************/
7512 void MocBalance2Way(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor)
7513 {
7514 
7515  if (Compute2WayHLoadImbalance(graph->ncon, graph->npwgts, tpwgts) < lbfactor)
7516  return;
7517 
7518  MocGeneral2WayBalance(ctrl, graph, tpwgts, lbfactor);
7519 
7520 }
7521 
7522 
7523 /*************************************************************************
7524 * This function performs an edge-based FM refinement
7525 **************************************************************************/
7526 void MocGeneral2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor)
7527 {
7528  int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, limit, tmp, cnum;
7529  idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
7530  idxtype *moved, *swaps, *perm, *qnum;
7531  float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
7532  PQueueType parts[MAXNCON][2];
7533  int higain, oldgain, mincut, newcut, mincutorder;
7534  int qsizes[MAXNCON][2];
7535 
7536  nvtxs = graph->nvtxs;
7537  ncon = graph->ncon;
7538  xadj = graph->xadj;
7539  nvwgt = graph->nvwgt;
7540  adjncy = graph->adjncy;
7541  adjwgt = graph->adjwgt;
7542  where = graph->where;
7543  id = graph->id;
7544  ed = graph->ed;
7545  npwgts = graph->npwgts;
7546  bndptr = graph->bndptr;
7547  bndind = graph->bndind;
7548 
7549  moved = idxwspacemalloc(ctrl, nvtxs);
7550  swaps = idxwspacemalloc(ctrl, nvtxs);
7551  perm = idxwspacemalloc(ctrl, nvtxs);
7552  qnum = idxwspacemalloc(ctrl, nvtxs);
7553 
7554  limit = amin(amax(0.01*nvtxs, 15), 100);
7555 
7556  /* Initialize the queues */
7557  for (i=0; i<ncon; i++) {
7558  PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
7559  PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
7560  qsizes[i][0] = qsizes[i][1] = 0;
7561  }
7562 
7563  for (i=0; i<nvtxs; i++) {
7564  qnum[i] = samax(ncon, nvwgt+i*ncon);
7565  qsizes[qnum[i]][where[i]]++;
7566  }
7567 
7568 /*
7569  printf("Weight Distribution: \t");
7570  for (i=0; i<ncon; i++)
7571  printf(" [%d %d]", qsizes[i][0], qsizes[i][1]);
7572  printf("\n");
7573 */
7574 
7575  for (from=0; from<2; from++) {
7576  for (j=0; j<ncon; j++) {
7577  if (qsizes[j][from] == 0) {
7578  for (i=0; i<nvtxs; i++) {
7579  if (where[i] != from)
7580  continue;
7581 
7582  k = samax2(ncon, nvwgt+i*ncon);
7583  if (k == j && qsizes[qnum[i]][from] > qsizes[j][from] && nvwgt[i*ncon+qnum[i]] < 1.3*nvwgt[i*ncon+j]) {
7584  qsizes[qnum[i]][from]--;
7585  qsizes[j][from]++;
7586  qnum[i] = j;
7587  }
7588  }
7589  }
7590  }
7591  }
7592 
7593 /*
7594  printf("Weight Distribution (after):\t ");
7595  for (i=0; i<ncon; i++)
7596  printf(" [%d %d]", qsizes[i][0], qsizes[i][1]);
7597  printf("\n");
7598 */
7599 
7600 
7601 
7602  for (i=0; i<ncon; i++)
7603  mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
7604  minbal = origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
7605  newcut = mincut = graph->mincut;
7606  mincutorder = -1;
7607 
7608  if (ctrl->dbglvl&DBG_REFINE) {
7609  printf("Parts: [");
7610  for (l=0; l<ncon; l++)
7611  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
7612  printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal);
7613  }
7614 
7615  idxset(nvtxs, -1, moved);
7616 
7617  ASSERT(ComputeCut(graph, where) == graph->mincut);
7618  ASSERT(CheckBnd(graph));
7619 
7620  /* Insert all nodes in the priority queues */
7621  nbnd = graph->nbnd;
7622  RandomPermute(nvtxs, perm, 1);
7623  for (ii=0; ii<nvtxs; ii++) {
7624  i = perm[ii];
7625  PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
7626  }
7627 
7628  for (nswaps=0; nswaps<nvtxs; nswaps++) {
7629  if (minbal < lbfactor)
7630  break;
7631 
7632  SelectQueue(ncon, npwgts, tpwgts, &from, &cnum, parts);
7633  to = (from+1)%2;
7634 
7635  if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
7636  break;
7637 
7638  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
7639  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
7640  newcut -= (ed[higain]-id[higain]);
7641  newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
7642 
7643  if (newbal < minbal || (newbal == minbal &&
7644  (newcut < mincut || (newcut == mincut && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
7645  mincut = newcut;
7646  minbal = newbal;
7647  mincutorder = nswaps;
7648  for (i=0; i<ncon; i++)
7649  mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
7650  }
7651  else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
7652  newcut += (ed[higain]-id[higain]);
7653  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
7654  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
7655  break;
7656  }
7657 
7658  where[higain] = to;
7659  moved[higain] = nswaps;
7660  swaps[nswaps] = higain;
7661 
7662  if (ctrl->dbglvl&DBG_MOVEINFO) {
7663  printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
7664  for (l=0; l<ncon; l++)
7665  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
7666  printf(", %.3f LB: %.3f\n", minbal, newbal);
7667  }
7668 
7669 
7670  /**************************************************************
7671  * Update the id[i]/ed[i] values of the affected nodes
7672  ***************************************************************/
7673  SWAP(id[higain], ed[higain], tmp);
7674  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
7675  BNDDelete(nbnd, bndind, bndptr, higain);
7676  if (ed[higain] > 0 && bndptr[higain] == -1)
7677  BNDInsert(nbnd, bndind, bndptr, higain);
7678 
7679  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
7680  k = adjncy[j];
7681  oldgain = ed[k]-id[k];
7682 
7683  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
7684  INC_DEC(id[k], ed[k], kwgt);
7685 
7686  /* Update the queue position */
7687  if (moved[k] == -1)
7688  PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
7689 
7690  /* Update its boundary information */
7691  if (ed[k] == 0 && bndptr[k] != -1)
7692  BNDDelete(nbnd, bndind, bndptr, k);
7693  else if (ed[k] > 0 && bndptr[k] == -1)
7694  BNDInsert(nbnd, bndind, bndptr, k);
7695  }
7696  }
7697 
7698 
7699 
7700  /****************************************************************
7701  * Roll back computations
7702  *****************************************************************/
7703  for (nswaps--; nswaps>mincutorder; nswaps--) {
7704  higain = swaps[nswaps];
7705 
7706  to = where[higain] = (where[higain]+1)%2;
7707  SWAP(id[higain], ed[higain], tmp);
7708  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
7709  BNDDelete(nbnd, bndind, bndptr, higain);
7710  else if (ed[higain] > 0 && bndptr[higain] == -1)
7711  BNDInsert(nbnd, bndind, bndptr, higain);
7712 
7713  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
7714  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1);
7715  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
7716  k = adjncy[j];
7717 
7718  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
7719  INC_DEC(id[k], ed[k], kwgt);
7720 
7721  if (bndptr[k] != -1 && ed[k] == 0)
7722  BNDDelete(nbnd, bndind, bndptr, k);
7723  if (bndptr[k] == -1 && ed[k] > 0)
7724  BNDInsert(nbnd, bndind, bndptr, k);
7725  }
7726  }
7727 
7728  if (ctrl->dbglvl&DBG_REFINE) {
7729  printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
7730  for (l=0; l<ncon; l++)
7731  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
7732  printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
7733  }
7734 
7735  graph->mincut = mincut;
7736  graph->nbnd = nbnd;
7737 
7738 
7739  for (i=0; i<ncon; i++) {
7740  PQueueFree(ctrl, &parts[i][0]);
7741  PQueueFree(ctrl, &parts[i][1]);
7742  }
7743 
7744  idxwspacefree(ctrl, nvtxs);
7745  idxwspacefree(ctrl, nvtxs);
7746  idxwspacefree(ctrl, nvtxs);
7747  idxwspacefree(ctrl, nvtxs);
7748 
7749 }
7750 
7751 /*
7752  * mcoarsen.c
7753  *
7754  * This file contains the driving routines for the coarsening process
7755  *
7756  * Started 7/23/97
7757  * George
7758  *
7759  * $Id$
7760  *
7761  */
7762 
7763 
7764 
7765 
7766 /*************************************************************************
7767 * This function takes a graph and creates a sequence of coarser graphs
7768 **************************************************************************/
7770 {
7771  int i, clevel;
7772  GraphType *cgraph;
7773 
7774  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->CoarsenTmr));
7775 
7776  cgraph = graph;
7777 
7778  clevel = 0;
7779  do {
7780  if (ctrl->dbglvl&DBG_COARSEN) {
7781  printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges,
7782  idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt);
7783  for (i=0; i<graph->ncon; i++)
7784  printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon));
7785  printf("]\n");
7786  }
7787 
7788  switch (ctrl->CType) {
7789  case MATCH_RM:
7790  MCMatch_RM(ctrl, cgraph);
7791  break;
7792  case MATCH_HEM:
7793  if (clevel < 1)
7794  MCMatch_RM(ctrl, cgraph);
7795  else
7796  MCMatch_HEM(ctrl, cgraph);
7797  break;
7798  case MATCH_SHEM:
7799  if (clevel < 1)
7800  MCMatch_RM(ctrl, cgraph);
7801  else
7802  MCMatch_SHEM(ctrl, cgraph);
7803  break;
7804  case MATCH_SHEMKWAY:
7805  MCMatch_SHEM(ctrl, cgraph);
7806  break;
7807  case MATCH_SHEBM_ONENORM:
7808  MCMatch_SHEBM(ctrl, cgraph, 1);
7809  break;
7810  case MATCH_SHEBM_INFNORM:
7811  MCMatch_SHEBM(ctrl, cgraph, -1);
7812  break;
7813  case MATCH_SBHEM_ONENORM:
7814  MCMatch_SBHEM(ctrl, cgraph, 1);
7815  break;
7816  case MATCH_SBHEM_INFNORM:
7817  MCMatch_SBHEM(ctrl, cgraph, -1);
7818  break;
7819  default:
7820  errexit("Unknown CType: %d\n", ctrl->CType);
7821  }
7822 
7823  cgraph = cgraph->coarser;
7824  clevel++;
7825 
7826  } while (cgraph->nvtxs > ctrl->CoarsenTo && cgraph->nvtxs < COARSEN_FRACTION2*cgraph->finer->nvtxs && cgraph->nedges > cgraph->nvtxs/2);
7827 
7828  if (ctrl->dbglvl&DBG_COARSEN) {
7829  printf("%6d %7d %10d [%d] [%6.4f", cgraph->nvtxs, cgraph->nedges,
7830  idxsum(cgraph->nvtxs, cgraph->adjwgtsum), ctrl->CoarsenTo, ctrl->nmaxvwgt);
7831  for (i=0; i<graph->ncon; i++)
7832  printf(" %5.3f", ssum_strd(cgraph->nvtxs, cgraph->nvwgt+i, cgraph->ncon));
7833  printf("]\n");
7834  }
7835 
7836 
7837  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->CoarsenTmr));
7838 
7839  return cgraph;
7840 }
7841 
7842 /*
7843  * Copyright 1997, Regents of the University of Minnesota
7844  *
7845  * memory.c
7846  *
7847  * This file contains routines that deal with memory allocation
7848  *
7849  * Started 2/24/96
7850  * George
7851  *
7852  * $Id$
7853  *
7854  */
7855 
7856 
7857 
7858 
7859 /*************************************************************************
7860 * This function allocates memory for the workspace
7861 **************************************************************************/
7862 void AllocateWorkSpace(CtrlType *ctrl, GraphType *graph, int nparts)
7863 {
7864  ctrl->wspace.pmat = NULL;
7865 
7866  if (ctrl->optype == OP_KMETIS) {
7867  ctrl->wspace.edegrees = (EDegreeType *)GKmalloc(graph->nedges*sizeof(EDegreeType), "AllocateWorkSpace: edegrees");
7868  ctrl->wspace.vedegrees = NULL;
7869  ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees;
7870 
7871  ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat");
7872 
7873  /* Memory requirements for different phases
7874  Coarsening
7875  Matching: 4*nvtxs vectors
7876  Contraction: 2*nvtxs vectors (from the above 4), 1*nparts, 1*Nedges
7877  Total = MAX(4*nvtxs, 2*nvtxs+nparts+nedges)
7878 
7879  Refinement
7880  Random Refinement/Balance: 5*nparts + 1*nvtxs + 2*nedges
7881  Greedy Refinement/Balance: 5*nparts + 2*nvtxs + 2*nedges + 1*PQueue(==Nvtxs)
7882  Total = 5*nparts + 3*nvtxs + 2*nedges
7883 
7884  Total = 5*nparts + 3*nvtxs + 2*nedges
7885  */
7886  ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */
7887  5*(nparts+1) + /* Partition weights etc */
7888  graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */
7889  20 /* padding for 64 bit machines */
7890  ;
7891  }
7892  else if (ctrl->optype == OP_KVMETIS) {
7893  ctrl->wspace.edegrees = NULL;
7894  ctrl->wspace.vedegrees = (VEDegreeType *)GKmalloc(graph->nedges*sizeof(VEDegreeType), "AllocateWorkSpace: vedegrees");
7895  ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.vedegrees;
7896 
7897  ctrl->wspace.pmat = idxmalloc(nparts*nparts, "AllocateWorkSpace: pmat");
7898 
7899  /* Memory requirements for different phases are identical to KMETIS */
7900  ctrl->wspace.maxcore = 3*(graph->nvtxs+1) + /* Match/Refinement vectors */
7901  3*(nparts+1) + /* Partition weights etc */
7902  graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* Greedy k-way balance/refine */
7903  20 /* padding for 64 bit machines */
7904  ;
7905  }
7906  else {
7907  ctrl->wspace.edegrees = (EDegreeType *)idxmalloc(graph->nedges, "AllocateWorkSpace: edegrees");
7908  ctrl->wspace.vedegrees = NULL;
7909  ctrl->wspace.auxcore = (idxtype *)ctrl->wspace.edegrees;
7910 
7911  ctrl->wspace.maxcore = 5*(graph->nvtxs+1) + /* Refinement vectors */
7912  4*(nparts+1) + /* Partition weights etc */
7913  2*graph->ncon*graph->nvtxs*(sizeof(ListNodeType)/sizeof(idxtype)) + /* 2-way refinement */
7914  2*graph->ncon*(NEG_GAINSPAN+PLUS_GAINSPAN+1)*(sizeof(ListNodeType *)/sizeof(idxtype)) + /* 2-way refinement */
7915  20 /* padding for 64 bit machines */
7916  ;
7917  }
7918 
7919  ctrl->wspace.maxcore += HTLENGTH;
7920  ctrl->wspace.core = idxmalloc(ctrl->wspace.maxcore, "AllocateWorkSpace: maxcore");
7921  ctrl->wspace.ccore = 0;
7922 }
7923 
7924 
7925 /*************************************************************************
7926 * This function allocates memory for the workspace
7927 **************************************************************************/
7928 void FreeWorkSpace(CtrlType *ctrl, GraphType *graph)
7929 {
7930  GKfree((void **) &ctrl->wspace.edegrees, (void **) &ctrl->wspace.vedegrees,
7931  (void **) &ctrl->wspace.core, (void **) &ctrl->wspace.pmat, LTERM);
7932 }
7933 
7934 /*************************************************************************
7935 * This function returns how may words are left in the workspace
7936 **************************************************************************/
7938 {
7939  return ctrl->wspace.maxcore - ctrl->wspace.ccore;
7940 }
7941 
7942 
7943 /*************************************************************************
7944 * This function allocate space from the core
7945 **************************************************************************/
7947 {
7948  n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
7949 
7950  ctrl->wspace.ccore += n;
7951  ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore);
7952  return ctrl->wspace.core + ctrl->wspace.ccore - n;
7953 }
7954 
7955 /*************************************************************************
7956 * This function frees space from the core
7957 **************************************************************************/
7958 void idxwspacefree(CtrlType *ctrl, int n)
7959 {
7960  n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
7961 
7962  ctrl->wspace.ccore -= n;
7963  ASSERT(ctrl->wspace.ccore >= 0);
7964 }
7965 
7966 
7967 /*************************************************************************
7968 * This function allocate space from the core
7969 **************************************************************************/
7970 float *fwspacemalloc(CtrlType *ctrl, int n)
7971 {
7972  n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
7973 
7974  ctrl->wspace.ccore += n;
7975  ASSERT(ctrl->wspace.ccore <= ctrl->wspace.maxcore);
7976  return (float *) (ctrl->wspace.core + ctrl->wspace.ccore - n);
7977 }
7978 
7979 /*************************************************************************
7980 * This function frees space from the core
7981 **************************************************************************/
7982 void fwspacefree(CtrlType *ctrl, int n)
7983 {
7984  n += n%2; /* This is a fix for 64 bit machines that require 8-byte pointer allignment */
7985 
7986  ctrl->wspace.ccore -= n;
7987  ASSERT(ctrl->wspace.ccore >= 0);
7988 }
7989 
7990 
7991 
7992 /*************************************************************************
7993 * This function creates a CoarseGraphType data structure and initializes
7994 * the various fields
7995 **************************************************************************/
7997 {
7998  GraphType *graph;
7999 
8000  graph = (GraphType *)GKmalloc(sizeof(GraphType), "CreateCoarseGraph: graph");
8001 
8002  InitGraph(graph);
8003 
8004  return graph;
8005 }
8006 
8007 
8008 /*************************************************************************
8009 * This function creates a CoarseGraphType data structure and initializes
8010 * the various fields
8011 **************************************************************************/
8012 void InitGraph(GraphType *graph)
8013 {
8014  graph->gdata = graph->rdata = NULL;
8015 
8016  graph->nvtxs = graph->nedges = -1;
8017  graph->mincut = graph->minvol = -1;
8018 
8019  graph->xadj = graph->vwgt = graph->adjncy = graph->adjwgt = NULL;
8020  graph->adjwgtsum = NULL;
8021  graph->label = NULL;
8022  graph->cmap = NULL;
8023 
8024  graph->where = graph->pwgts = NULL;
8025  graph->id = graph->ed = NULL;
8026  graph->bndptr = graph->bndind = NULL;
8027  graph->rinfo = NULL;
8028  graph->vrinfo = NULL;
8029  graph->nrinfo = NULL;
8030 
8031  graph->ncon = -1;
8032  graph->nvwgt = NULL;
8033  graph->npwgts = NULL;
8034 
8035  graph->vsize = NULL;
8036 
8037  graph->coarser = graph->finer = NULL;
8038 
8039 }
8040 
8041 /*************************************************************************
8042 * This function deallocates any memory stored in a graph
8043 **************************************************************************/
8044 void FreeGraph(GraphType *graph)
8045 {
8046 
8047  GKfree((void **) &graph->gdata, (void **) &graph->nvwgt,
8048  (void **) &graph->rdata, (void **) &graph->npwgts, LTERM);
8049  free(graph);
8050 }
8051 
8052 /*
8053  * Copyright 1997, Regents of the University of Minnesota
8054  *
8055  * mesh.c
8056  *
8057  * This file contains routines for converting 3D and 4D finite element
8058  * meshes into dual or nodal graphs
8059  *
8060  * Started 8/18/97
8061  * George
8062  *
8063  * $Id$
8064  *
8065  */
8066 
8067 
8068 
8069 /*****************************************************************************
8070 * This function creates a graph corresponding to the dual of a finite element
8071 * mesh. At this point the supported elements are triangles, tetrahedrons, and
8072 * bricks.
8073 ******************************************************************************/
8074 void METIS_MeshToDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
8075  idxtype *dxadj, idxtype *dadjncy)
8076 {
8077  int esizes[] = {-1, 3, 4, 8, 4};
8078 
8079  if (*numflag == 1)
8080  ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts);
8081 
8082  GENDUALMETIS(*ne, *nn, *etype, elmnts, dxadj, dadjncy);
8083 
8084  if (*numflag == 1)
8085  ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *ne, dxadj, dadjncy);
8086 }
8087 
8088 
8089 /*****************************************************************************
8090 * This function creates a graph corresponding to the finite element mesh.
8091 * At this point the supported elements are triangles, tetrahedrons.
8092 ******************************************************************************/
8093 void METIS_MeshToNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
8094  idxtype *dxadj, idxtype *dadjncy)
8095 {
8096  int esizes[] = {-1, 3, 4, 8, 4};
8097 
8098  if (*numflag == 1)
8099  ChangeMesh2CNumbering((*ne)*esizes[*etype], elmnts);
8100 
8101  switch (*etype) {
8102  case 1:
8103  TRINODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
8104  break;
8105  case 2:
8106  TETNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
8107  break;
8108  case 3:
8109  HEXNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
8110  break;
8111  case 4:
8112  QUADNODALMETIS(*ne, *nn, elmnts, dxadj, dadjncy);
8113  break;
8114  }
8115 
8116  if (*numflag == 1)
8117  ChangeMesh2FNumbering((*ne)*esizes[*etype], elmnts, *nn, dxadj, dadjncy);
8118 }
8119 
8120 
8121 
8122 /*****************************************************************************
8123 * This function creates the dual of a finite element mesh
8124 ******************************************************************************/
8125 void GENDUALMETIS(int nelmnts, int nvtxs, int etype, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
8126 {
8127  int i, j, jj, k, kk, kkk, l, m, n, mask;
8128  idxtype *nptr, *nind;
8129  idxtype *mark, ind[200], wgt[200];
8130  int esize, esizes[] = {-1, 3, 4, 8, 4},
8131  mgcnum, mgcnums[] = {-1, 2, 3, 4, 2};
8132 
8133  mask = (1<<11)-1;
8134  mark = idxsmalloc(mask+1, -1, "GENDUALMETIS: mark");
8135 
8136  /* Get the element size and magic number for the particular element */
8137  esize = esizes[etype];
8138  mgcnum = mgcnums[etype];
8139 
8140  /* Construct the node-element list first */
8141  nptr = idxsmalloc(nvtxs+1, 0, "GENDUALMETIS: nptr");
8142  for (j=esize*nelmnts, i=0; i<j; i++)
8143  nptr[elmnts[i]]++;
8144  MAKECSR(i, nvtxs, nptr);
8145 
8146  nind = idxmalloc(nptr[nvtxs], "GENDUALMETIS: nind");
8147  for (k=i=0; i<nelmnts; i++) {
8148  for (j=0; j<esize; j++, k++)
8149  nind[nptr[elmnts[k]]++] = i;
8150  }
8151  for (i=nvtxs; i>0; i--)
8152  nptr[i] = nptr[i-1];
8153  nptr[0] = 0;
8154 
8155  for (i=0; i<nelmnts; i++)
8156  dxadj[i] = esize*i;
8157 
8158  for (i=0; i<nelmnts; i++) {
8159  for (m=j=0; j<esize; j++) {
8160  n = elmnts[esize*i+j];
8161  for (k=nptr[n+1]-1; k>=nptr[n]; k--) {
8162  if ((kk = nind[k]) <= i)
8163  break;
8164 
8165  kkk = kk&mask;
8166  if ((l = mark[kkk]) == -1) {
8167  ind[m] = kk;
8168  wgt[m] = 1;
8169  mark[kkk] = m++;
8170  }
8171  else if (ind[l] == kk) {
8172  wgt[l]++;
8173  }
8174  else {
8175  for (jj=0; jj<m; jj++) {
8176  if (ind[jj] == kk) {
8177  wgt[jj]++;
8178  break;
8179  }
8180  }
8181  if (jj == m) {
8182  ind[m] = kk;
8183  wgt[m++] = 1;
8184  }
8185  }
8186  }
8187  }
8188  for (j=0; j<m; j++) {
8189  if (wgt[j] == mgcnum) {
8190  k = ind[j];
8191  dadjncy[dxadj[i]++] = k;
8192  dadjncy[dxadj[k]++] = i;
8193  }
8194  mark[ind[j]&mask] = -1;
8195  }
8196  }
8197 
8198  /* Go and consolidate the dxadj and dadjncy */
8199  for (j=i=0; i<nelmnts; i++) {
8200  for (k=esize*i; k<dxadj[i]; k++, j++)
8201  dadjncy[j] = dadjncy[k];
8202  dxadj[i] = j;
8203  }
8204  for (i=nelmnts; i>0; i--)
8205  dxadj[i] = dxadj[i-1];
8206  dxadj[0] = 0;
8207 
8208  free(mark);
8209  free(nptr);
8210  free(nind);
8211 
8212 }
8213 
8214 
8215 
8216 
8217 /*****************************************************************************
8218 * This function creates the nodal graph of a finite element mesh
8219 ******************************************************************************/
8220 void TRINODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
8221 {
8222  int i, j, jj, k, kk, nedges;
8223  idxtype *nptr, *nind;
8224  idxtype *mark;
8225 
8226  /* Construct the node-element list first */
8227  nptr = idxsmalloc(nvtxs+1, 0, "TRINODALMETIS: nptr");
8228  for (j=3*nelmnts, i=0; i<j; i++)
8229  nptr[elmnts[i]]++;
8230  MAKECSR(i, nvtxs, nptr);
8231 
8232  nind = idxmalloc(nptr[nvtxs], "TRINODALMETIS: nind");
8233  for (k=i=0; i<nelmnts; i++) {
8234  for (j=0; j<3; j++, k++)
8235  nind[nptr[elmnts[k]]++] = i;
8236  }
8237  for (i=nvtxs; i>0; i--)
8238  nptr[i] = nptr[i-1];
8239  nptr[0] = 0;
8240 
8241 
8242  mark = idxsmalloc(nvtxs, -1, "TRINODALMETIS: mark");
8243 
8244  nedges = dxadj[0] = 0;
8245  for (i=0; i<nvtxs; i++) {
8246  mark[i] = i;
8247  for (j=nptr[i]; j<nptr[i+1]; j++) {
8248  for (jj=3*nind[j], k=0; k<3; k++, jj++) {
8249  kk = elmnts[jj];
8250  if (mark[kk] != i) {
8251  mark[kk] = i;
8252  dadjncy[nedges++] = kk;
8253  }
8254  }
8255  }
8256  dxadj[i+1] = nedges;
8257  }
8258 
8259  free(mark);
8260  free(nptr);
8261  free(nind);
8262 
8263 }
8264 
8265 
8266 /*****************************************************************************
8267 * This function creates the nodal graph of a finite element mesh
8268 ******************************************************************************/
8269 void TETNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
8270 {
8271  int i, j, jj, k, kk, nedges;
8272  idxtype *nptr, *nind;
8273  idxtype *mark;
8274 
8275  /* Construct the node-element list first */
8276  nptr = idxsmalloc(nvtxs+1, 0, "TETNODALMETIS: nptr");
8277  for (j=4*nelmnts, i=0; i<j; i++)
8278  nptr[elmnts[i]]++;
8279  MAKECSR(i, nvtxs, nptr);
8280 
8281  nind = idxmalloc(nptr[nvtxs], "TETNODALMETIS: nind");
8282  for (k=i=0; i<nelmnts; i++) {
8283  for (j=0; j<4; j++, k++)
8284  nind[nptr[elmnts[k]]++] = i;
8285  }
8286  for (i=nvtxs; i>0; i--)
8287  nptr[i] = nptr[i-1];
8288  nptr[0] = 0;
8289 
8290 
8291  mark = idxsmalloc(nvtxs, -1, "TETNODALMETIS: mark");
8292 
8293  nedges = dxadj[0] = 0;
8294  for (i=0; i<nvtxs; i++) {
8295  mark[i] = i;
8296  for (j=nptr[i]; j<nptr[i+1]; j++) {
8297  for (jj=4*nind[j], k=0; k<4; k++, jj++) {
8298  kk = elmnts[jj];
8299  if (mark[kk] != i) {
8300  mark[kk] = i;
8301  dadjncy[nedges++] = kk;
8302  }
8303  }
8304  }
8305  dxadj[i+1] = nedges;
8306  }
8307 
8308  free(mark);
8309  free(nptr);
8310  free(nind);
8311 
8312 }
8313 
8314 
8315 /*****************************************************************************
8316 * This function creates the nodal graph of a finite element mesh
8317 ******************************************************************************/
8318 void HEXNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
8319 {
8320  int i, j, jj, k, kk, nedges;
8321  idxtype *nptr, *nind;
8322  idxtype *mark;
8323  int table[8][3] = {{1, 3, 4},
8324  {0, 2, 5},
8325  {1, 3, 6},
8326  {0, 2, 7},
8327  {0, 5, 7},
8328  {1, 4, 6},
8329  {2, 5, 7},
8330  {3, 4, 6}};
8331 
8332  /* Construct the node-element list first */
8333  nptr = idxsmalloc(nvtxs+1, 0, "HEXNODALMETIS: nptr");
8334  for (j=8*nelmnts, i=0; i<j; i++)
8335  nptr[elmnts[i]]++;
8336  MAKECSR(i, nvtxs, nptr);
8337 
8338  nind = idxmalloc(nptr[nvtxs], "HEXNODALMETIS: nind");
8339  for (k=i=0; i<nelmnts; i++) {
8340  for (j=0; j<8; j++, k++)
8341  nind[nptr[elmnts[k]]++] = i;
8342  }
8343  for (i=nvtxs; i>0; i--)
8344  nptr[i] = nptr[i-1];
8345  nptr[0] = 0;
8346 
8347 
8348  mark = idxsmalloc(nvtxs, -1, "HEXNODALMETIS: mark");
8349 
8350  nedges = dxadj[0] = 0;
8351  for (i=0; i<nvtxs; i++) {
8352  mark[i] = i;
8353  for (j=nptr[i]; j<nptr[i+1]; j++) {
8354  jj=8*nind[j];
8355  for (k=0; k<8; k++) {
8356  if (elmnts[jj+k] == i)
8357  break;
8358  }
8359  ASSERT(k != 8);
8360 
8361  /* You found the index, now go and put the 3 neighbors */
8362  kk = elmnts[jj+table[k][0]];
8363  if (mark[kk] != i) {
8364  mark[kk] = i;
8365  dadjncy[nedges++] = kk;
8366  }
8367  kk = elmnts[jj+table[k][1]];
8368  if (mark[kk] != i) {
8369  mark[kk] = i;
8370  dadjncy[nedges++] = kk;
8371  }
8372  kk = elmnts[jj+table[k][2]];
8373  if (mark[kk] != i) {
8374  mark[kk] = i;
8375  dadjncy[nedges++] = kk;
8376  }
8377  }
8378  dxadj[i+1] = nedges;
8379  }
8380 
8381  free(mark);
8382  free(nptr);
8383  free(nind);
8384 
8385 }
8386 
8387 
8388 /*****************************************************************************
8389 * This function creates the nodal graph of a finite element mesh
8390 ******************************************************************************/
8391 void QUADNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
8392 {
8393  int i, j, jj, k, kk, nedges;
8394  idxtype *nptr, *nind;
8395  idxtype *mark;
8396  int table[4][2] = {{1, 3},
8397  {0, 2},
8398  {1, 3},
8399  {0, 2}};
8400 
8401  /* Construct the node-element list first */
8402  nptr = idxsmalloc(nvtxs+1, 0, "QUADNODALMETIS: nptr");
8403  for (j=4*nelmnts, i=0; i<j; i++)
8404  nptr[elmnts[i]]++;
8405  MAKECSR(i, nvtxs, nptr);
8406 
8407  nind = idxmalloc(nptr[nvtxs], "QUADNODALMETIS: nind");
8408  for (k=i=0; i<nelmnts; i++) {
8409  for (j=0; j<4; j++, k++)
8410  nind[nptr[elmnts[k]]++] = i;
8411  }
8412  for (i=nvtxs; i>0; i--)
8413  nptr[i] = nptr[i-1];
8414  nptr[0] = 0;
8415 
8416 
8417  mark = idxsmalloc(nvtxs, -1, "QUADNODALMETIS: mark");
8418 
8419  nedges = dxadj[0] = 0;
8420  for (i=0; i<nvtxs; i++) {
8421  mark[i] = i;
8422  for (j=nptr[i]; j<nptr[i+1]; j++) {
8423  jj=4*nind[j];
8424  for (k=0; k<4; k++) {
8425  if (elmnts[jj+k] == i)
8426  break;
8427  }
8428  ASSERT(k != 4);
8429 
8430  /* You found the index, now go and put the 2 neighbors */
8431  kk = elmnts[jj+table[k][0]];
8432  if (mark[kk] != i) {
8433  mark[kk] = i;
8434  dadjncy[nedges++] = kk;
8435  }
8436  kk = elmnts[jj+table[k][1]];
8437  if (mark[kk] != i) {
8438  mark[kk] = i;
8439  dadjncy[nedges++] = kk;
8440  }
8441  }
8442  dxadj[i+1] = nedges;
8443  }
8444 
8445  free(mark);
8446  free(nptr);
8447  free(nind);
8448 
8449 }
8450 /*
8451  * Copyright 1997, Regents of the University of Minnesota
8452  *
8453  * meshpart.c
8454  *
8455  * This file contains routines for partitioning finite element meshes.
8456  *
8457  * Started 9/29/97
8458  * George
8459  *
8460  * $Id$
8461  *
8462  */
8463 
8464 
8465 
8466 
8467 /*************************************************************************
8468 * This function partitions a finite element mesh by partitioning its nodal
8469 * graph using KMETIS and then assigning elements in a load balanced fashion.
8470 **************************************************************************/
8471 void METIS_PartMeshNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
8472  int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
8473 {
8474  int i, j, k, me;
8475  idxtype *xadj, *adjncy, *pwgts;
8476  int options[10], pnumflag=0, wgtflag=0;
8477  int nnbrs, nbrind[200], nbrwgt[200], maxpwgt;
8478  int esize, esizes[] = {-1, 3, 4, 8, 4};
8479 
8480  esize = esizes[*etype];
8481 
8482  if (*numflag == 1)
8483  ChangeMesh2CNumbering((*ne)*esize, elmnts);
8484 
8485  xadj = idxmalloc(*nn+1, "METIS_MESHPARTNODAL: xadj");
8486  adjncy = idxmalloc(20*(*nn), "METIS_MESHPARTNODAL: adjncy");
8487 
8488  METIS_MeshToNodal(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy);
8489 
8490  adjncy = realloc(adjncy, xadj[*nn]*sizeof(idxtype));
8491 
8492  options[0] = 0;
8493  METIS_PartGraphKway(nn, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, npart);
8494 
8495  /* OK, now compute an element partition based on the nodal partition npart */
8496  idxset(*ne, -1, epart);
8497  pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTNODAL: pwgts");
8498  for (i=0; i<*ne; i++) {
8499  me = npart[elmnts[i*esize]];
8500  for (j=1; j<esize; j++) {
8501  if (npart[elmnts[i*esize+j]] != me)
8502  break;
8503  }
8504  if (j == esize) {
8505  epart[i] = me;
8506  pwgts[me]++;
8507  }
8508  }
8509 
8510  maxpwgt = 1.03*(*ne)/(*nparts);
8511  for (i=0; i<*ne; i++) {
8512  if (epart[i] == -1) { /* Assign the boundary element */
8513  nnbrs = 0;
8514  for (j=0; j<esize; j++) {
8515  me = npart[elmnts[i*esize+j]];
8516  for (k=0; k<nnbrs; k++) {
8517  if (nbrind[k] == me) {
8518  nbrwgt[k]++;
8519  break;
8520  }
8521  }
8522  if (k == nnbrs) {
8523  nbrind[nnbrs] = me;
8524  nbrwgt[nnbrs++] = 1;
8525  }
8526  }
8527  /* Try to assign it first to the domain with most things in common */
8528  j = iamax(nnbrs, nbrwgt);
8529  if (pwgts[nbrind[j]] < maxpwgt) {
8530  epart[i] = nbrind[j];
8531  }
8532  else {
8533  /* If that fails, assign it to a light domain */
8534  for (j=0; j<nnbrs; j++) {
8535  if (pwgts[nbrind[j]] < maxpwgt) {
8536  epart[i] = nbrind[j];
8537  break;
8538  }
8539  }
8540  if (j == nnbrs)
8541  epart[i] = nbrind[iamax(nnbrs, nbrwgt)];
8542  }
8543  pwgts[epart[i]]++;
8544  }
8545  }
8546 
8547  if (*numflag == 1)
8548  ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart);
8549 
8550  GKfree((void **) &xadj, (void **) &adjncy, (void **) &pwgts, LTERM);
8551 
8552 }
8553 
8554 
8555 /*************************************************************************
8556 * This function partitions a finite element mesh by partitioning its dual
8557 * graph using KMETIS and then assigning nodes in a load balanced fashion.
8558 **************************************************************************/
8559 void METIS_PartMeshDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag,
8560  int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
8561 {
8562  int i, j, k, me;
8563  idxtype *xadj, *adjncy, *pwgts, *nptr, *nind;
8564  int options[10], pnumflag=0, wgtflag=0;
8565  int nnbrs, nbrind[200], nbrwgt[200], maxpwgt;
8566  int esize, esizes[] = {-1, 3, 4, 8, 4};
8567 
8568  esize = esizes[*etype];
8569 
8570  if (*numflag == 1)
8571  ChangeMesh2CNumbering((*ne)*esize, elmnts);
8572 
8573  xadj = idxmalloc(*ne+1, "METIS_MESHPARTNODAL: xadj");
8574  adjncy = idxmalloc(esize*(*ne), "METIS_MESHPARTNODAL: adjncy");
8575 
8576  METIS_MeshToDual(ne, nn, elmnts, etype, &pnumflag, xadj, adjncy);
8577 
8578  options[0] = 0;
8579  METIS_PartGraphKway(ne, xadj, adjncy, NULL, NULL, &wgtflag, &pnumflag, nparts, options, edgecut, epart);
8580 
8581  /* Construct the node-element list */
8582  nptr = idxsmalloc(*nn+1, 0, "METIS_MESHPARTDUAL: nptr");
8583  for (j=esize*(*ne), i=0; i<j; i++)
8584  nptr[elmnts[i]]++;
8585  MAKECSR(i, *nn, nptr);
8586 
8587  nind = idxmalloc(nptr[*nn], "METIS_MESHPARTDUAL: nind");
8588  for (k=i=0; i<(*ne); i++) {
8589  for (j=0; j<esize; j++, k++)
8590  nind[nptr[elmnts[k]]++] = i;
8591  }
8592  for (i=(*nn); i>0; i--)
8593  nptr[i] = nptr[i-1];
8594  nptr[0] = 0;
8595 
8596 
8597  /* OK, now compute a nodal partition based on the element partition npart */
8598  idxset(*nn, -1, npart);
8599  pwgts = idxsmalloc(*nparts, 0, "METIS_MESHPARTDUAL: pwgts");
8600  for (i=0; i<*nn; i++) {
8601  me = epart[nind[nptr[i]]];
8602  for (j=nptr[i]+1; j<nptr[i+1]; j++) {
8603  if (epart[nind[j]] != me)
8604  break;
8605  }
8606  if (j == nptr[i+1]) {
8607  npart[i] = me;
8608  pwgts[me]++;
8609  }
8610  }
8611 
8612  maxpwgt = 1.03*(*nn)/(*nparts);
8613  for (i=0; i<*nn; i++) {
8614  if (npart[i] == -1) { /* Assign the boundary element */
8615  nnbrs = 0;
8616  for (j=nptr[i]; j<nptr[i+1]; j++) {
8617  me = epart[nind[j]];
8618  for (k=0; k<nnbrs; k++) {
8619  if (nbrind[k] == me) {
8620  nbrwgt[k]++;
8621  break;
8622  }
8623  }
8624  if (k == nnbrs) {
8625  nbrind[nnbrs] = me;
8626  nbrwgt[nnbrs++] = 1;
8627  }
8628  }
8629  /* Try to assign it first to the domain with most things in common */
8630  j = iamax(nnbrs, nbrwgt);
8631  if (pwgts[nbrind[j]] < maxpwgt) {
8632  npart[i] = nbrind[j];
8633  }
8634  else {
8635  /* If that fails, assign it to a light domain */
8636  npart[i] = nbrind[0];
8637  for (j=0; j<nnbrs; j++) {
8638  if (pwgts[nbrind[j]] < maxpwgt) {
8639  npart[i] = nbrind[j];
8640  break;
8641  }
8642  }
8643  }
8644  pwgts[npart[i]]++;
8645  }
8646  }
8647 
8648  if (*numflag == 1)
8649  ChangeMesh2FNumbering2((*ne)*esize, elmnts, *ne, *nn, epart, npart);
8650 
8651  GKfree((void **) &xadj, (void **) &adjncy, (void **) &pwgts,
8652  (void **) &nptr, (void **) &nind, LTERM);
8653 
8654 }
8655 /*
8656  * Copyright 1997, Regents of the University of Minnesota
8657  *
8658  * mfm2.c
8659  *
8660  * This file contains code that implements the edge-based FM refinement
8661  *
8662  * Started 7/23/97
8663  * George
8664  *
8665  * $Id$
8666  */
8667 
8668 
8669 
8670 
8671 /*************************************************************************
8672 * This function performs an edge-based FM refinement
8673 **************************************************************************/
8674 void MocFM_2WayEdgeRefine2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *orgubvec,
8675  int npasses)
8676 {
8677  int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, limit, tmp, cnum;
8678  idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
8679  idxtype *moved, *swaps, *perm, *qnum;
8680  float *nvwgt, *npwgts, origdiff[MAXNCON], origbal[MAXNCON], minbal[MAXNCON];
8681  PQueueType parts[MAXNCON][2];
8682  int higain, oldgain, mincut, initcut, newcut, mincutorder;
8683  float *maxwgt, *minwgt, ubvec[MAXNCON], tvec[MAXNCON];
8684 
8685  nvtxs = graph->nvtxs;
8686  ncon = graph->ncon;
8687  xadj = graph->xadj;
8688  nvwgt = graph->nvwgt;
8689  adjncy = graph->adjncy;
8690  adjwgt = graph->adjwgt;
8691  where = graph->where;
8692  id = graph->id;
8693  ed = graph->ed;
8694  npwgts = graph->npwgts;
8695  bndptr = graph->bndptr;
8696  bndind = graph->bndind;
8697 
8698  moved = idxwspacemalloc(ctrl, nvtxs);
8699  swaps = idxwspacemalloc(ctrl, nvtxs);
8700  perm = idxwspacemalloc(ctrl, nvtxs);
8701  qnum = idxwspacemalloc(ctrl, nvtxs);
8702 
8703  limit = amin(amax(0.01*nvtxs, 15), 100);
8704 
8705  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, origbal);
8706  for (i=0; i<ncon; i++) {
8707  origdiff[i] = fabs(tpwgts[0]-npwgts[i]);
8708  ubvec[i] = amax(origbal[i], orgubvec[i]);
8709  }
8710 
8711  /* Setup the weight intervals of the two subdomains */
8712  minwgt = fwspacemalloc(ctrl, 2*ncon);
8713  maxwgt = fwspacemalloc(ctrl, 2*ncon);
8714 
8715  for (i=0; i<2; i++) {
8716  for (j=0; j<ncon; j++) {
8717  maxwgt[i*ncon+j] = tpwgts[i]*ubvec[j];
8718  minwgt[i*ncon+j] = tpwgts[i]*(1.0/ubvec[j]);
8719  }
8720  }
8721 
8722  /* Initialize the queues */
8723  for (i=0; i<ncon; i++) {
8724  PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
8725  PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
8726  }
8727  for (i=0; i<nvtxs; i++)
8728  qnum[i] = samax(ncon, nvwgt+i*ncon);
8729 
8730 
8731  if (ctrl->dbglvl&DBG_REFINE) {
8732  printf("Parts: [");
8733  for (l=0; l<ncon; l++)
8734  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
8735  printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: ", tpwgts[0], tpwgts[1],
8736  graph->nvtxs, graph->nbnd, graph->mincut);
8737  for (i=0; i<ncon; i++)
8738  printf("%.3f ", origbal[i]);
8739  printf("\n");
8740  }
8741 
8742  idxset(nvtxs, -1, moved);
8743  for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
8744  for (i=0; i<ncon; i++) {
8745  PQueueReset(&parts[i][0]);
8746  PQueueReset(&parts[i][1]);
8747  }
8748 
8749  mincutorder = -1;
8750  newcut = mincut = initcut = graph->mincut;
8751  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, minbal);
8752 
8753  ASSERT(ComputeCut(graph, where) == graph->mincut);
8754  ASSERT(CheckBnd(graph));
8755 
8756  /* Insert boundary nodes in the priority queues */
8757  nbnd = graph->nbnd;
8758  RandomPermute(nbnd, perm, 1);
8759  for (ii=0; ii<nbnd; ii++) {
8760  i = bndind[perm[ii]];
8761  ASSERT(ed[i] > 0 || id[i] == 0);
8762  ASSERT(bndptr[i] != -1);
8763  PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
8764  }
8765 
8766  for (nswaps=0; nswaps<nvtxs; nswaps++) {
8767  SelectQueue2(ncon, npwgts, tpwgts, &from, &cnum, parts, maxwgt);
8768  to = (from+1)%2;
8769 
8770  if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
8771  break;
8772  ASSERT(bndptr[higain] != -1);
8773 
8774  newcut -= (ed[higain]-id[higain]);
8775  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
8776  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
8777 
8778  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
8779  if ((newcut < mincut && AreAllBelow(ncon, tvec, ubvec)) ||
8780  (newcut == mincut && IsBetter2wayBalance(ncon, tvec, minbal, ubvec))) {
8781  mincut = newcut;
8782  for (i=0; i<ncon; i++)
8783  minbal[i] = tvec[i];
8784  mincutorder = nswaps;
8785  }
8786  else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
8787  newcut += (ed[higain]-id[higain]);
8788  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
8789  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
8790  break;
8791  }
8792 
8793  where[higain] = to;
8794  moved[higain] = nswaps;
8795  swaps[nswaps] = higain;
8796 
8797  if (ctrl->dbglvl&DBG_MOVEINFO) {
8798  printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
8799  for (l=0; l<ncon; l++)
8800  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
8801 
8802  printf(", LB: ");
8803  for (i=0; i<ncon; i++)
8804  printf("%.3f ", tvec[i]);
8805  if (mincutorder == nswaps)
8806  printf(" *\n");
8807  else
8808  printf("\n");
8809  }
8810 
8811 
8812  /**************************************************************
8813  * Update the id[i]/ed[i] values of the affected nodes
8814  ***************************************************************/
8815  SWAP(id[higain], ed[higain], tmp);
8816  if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
8817  BNDDelete(nbnd, bndind, bndptr, higain);
8818 
8819  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
8820  k = adjncy[j];
8821  oldgain = ed[k]-id[k];
8822 
8823  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
8824  INC_DEC(id[k], ed[k], kwgt);
8825 
8826  /* Update its boundary information and queue position */
8827  if (bndptr[k] != -1) { /* If k was a boundary vertex */
8828  if (ed[k] == 0) { /* Not a boundary vertex any more */
8829  BNDDelete(nbnd, bndind, bndptr, k);
8830  if (moved[k] == -1) /* Remove it if in the queues */
8831  PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain);
8832  }
8833  else { /* If it has not been moved, update its position in the queue */
8834  if (moved[k] == -1)
8835  PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
8836  }
8837  }
8838  else {
8839  if (ed[k] > 0) { /* It will now become a boundary vertex */
8840  BNDInsert(nbnd, bndind, bndptr, k);
8841  if (moved[k] == -1)
8842  PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]);
8843  }
8844  }
8845  }
8846 
8847  }
8848 
8849 
8850  /****************************************************************
8851  * Roll back computations
8852  *****************************************************************/
8853  for (i=0; i<nswaps; i++)
8854  moved[swaps[i]] = -1; /* reset moved array */
8855  for (nswaps--; nswaps>mincutorder; nswaps--) {
8856  higain = swaps[nswaps];
8857 
8858  to = where[higain] = (where[higain]+1)%2;
8859  SWAP(id[higain], ed[higain], tmp);
8860  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
8861  BNDDelete(nbnd, bndind, bndptr, higain);
8862  else if (ed[higain] > 0 && bndptr[higain] == -1)
8863  BNDInsert(nbnd, bndind, bndptr, higain);
8864 
8865  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
8866  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1);
8867  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
8868  k = adjncy[j];
8869 
8870  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
8871  INC_DEC(id[k], ed[k], kwgt);
8872 
8873  if (bndptr[k] != -1 && ed[k] == 0)
8874  BNDDelete(nbnd, bndind, bndptr, k);
8875  if (bndptr[k] == -1 && ed[k] > 0)
8876  BNDInsert(nbnd, bndind, bndptr, k);
8877  }
8878  }
8879 
8880  if (ctrl->dbglvl&DBG_REFINE) {
8881  printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
8882  for (l=0; l<ncon; l++)
8883  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
8884  printf("], LB: ");
8885  Compute2WayHLoadImbalanceVec(ncon, npwgts, tpwgts, tvec);
8886  for (i=0; i<ncon; i++)
8887  printf("%.3f ", tvec[i]);
8888  printf("\n");
8889  }
8890 
8891  graph->mincut = mincut;
8892  graph->nbnd = nbnd;
8893 
8894  if (mincutorder == -1 || mincut == initcut)
8895  break;
8896  }
8897 
8898  for (i=0; i<ncon; i++) {
8899  PQueueFree(ctrl, &parts[i][0]);
8900  PQueueFree(ctrl, &parts[i][1]);
8901  }
8902 
8903  idxwspacefree(ctrl, nvtxs);
8904  idxwspacefree(ctrl, nvtxs);
8905  idxwspacefree(ctrl, nvtxs);
8906  idxwspacefree(ctrl, nvtxs);
8907  fwspacefree(ctrl, 2*ncon);
8908  fwspacefree(ctrl, 2*ncon);
8909 
8910 }
8911 
8912 
8913 /*************************************************************************
8914 * This function selects the partition number and the queue from which
8915 * we will move vertices out
8916 **************************************************************************/
8917 void SelectQueue2(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum,
8918  PQueueType queues[MAXNCON][2], float *maxwgt)
8919 {
8920  int i, j, maxgain=0;
8921  float diff, max, maxdiff=0.0;
8922 
8923  *from = -1;
8924  *cnum = -1;
8925 
8926  /* First determine the side and the queue, irrespective of the presence of nodes */
8927  for (j=0; j<2; j++) {
8928  for (i=0; i<ncon; i++) {
8929  diff = npwgts[j*ncon+i]-maxwgt[j*ncon+i];
8930  if (diff >= maxdiff) {
8931  maxdiff = diff;
8932  *from = j;
8933  *cnum = i;
8934  }
8935  }
8936  }
8937 
8938  if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
8939  /* The desired queue is empty, select a node from that side anyway */
8940  for (i=0; i<ncon; i++) {
8941  if (PQueueGetSize(&queues[i][*from]) > 0) {
8942  max = (npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i]);
8943  *cnum = i;
8944  break;
8945  }
8946  }
8947 
8948  for (i++; i<ncon; i++) {
8949  diff = npwgts[(*from)*ncon+i] - maxwgt[(*from)*ncon+i];
8950  if (diff > max && PQueueGetSize(&queues[i][*from]) > 0) {
8951  max = diff;
8952  *cnum = i;
8953  }
8954  }
8955  }
8956 
8957  /* Check to see if you can focus on the cut */
8958  if (maxdiff <= 0.0 || *from == -1) {
8959  maxgain = -100000;
8960 
8961  for (j=0; j<2; j++) {
8962  for (i=0; i<ncon; i++) {
8963  if (PQueueGetSize(&queues[i][j]) > 0 && PQueueGetKey(&queues[i][j]) > maxgain) {
8964  maxgain = PQueueGetKey(&queues[i][j]);
8965  *from = j;
8966  *cnum = i;
8967  }
8968  }
8969  }
8970 
8971  /* printf("(%2d %2d) %3d\n", *from, *cnum, maxgain); */
8972  }
8973 }
8974 
8975 
8976 /*************************************************************************
8977 * This function checks if the newbal is better than oldbal given the
8978 * ubvector ubvec
8979 **************************************************************************/
8980 int IsBetter2wayBalance(int ncon, float *newbal, float *oldbal, float *ubvec)
8981 {
8982  int i;
8983  float max1=0.0, max2=0.0, sum1=0.0, sum2=0.0, tmp;
8984 
8985  for (i=0; i<ncon; i++) {
8986  tmp = (newbal[i]-1)/(ubvec[i]-1);
8987  max1 = (max1 < tmp ? tmp : max1);
8988  sum1 += tmp;
8989 
8990  tmp = (oldbal[i]-1)/(ubvec[i]-1);
8991  max2 = (max2 < tmp ? tmp : max2);
8992  sum2 += tmp;
8993  }
8994 
8995  if (max1 < max2)
8996  return 1;
8997  else if (max1 > max2)
8998  return 0;
8999  else
9000  return sum1 <= sum2;
9001 }
9002 
9003 
9004 /*
9005  * Copyright 1997, Regents of the University of Minnesota
9006  *
9007  * mfm.c
9008  *
9009  * This file contains code that implements the edge-based FM refinement
9010  *
9011  * Started 7/23/97
9012  * George
9013  *
9014  * $Id$
9015  */
9016 
9017 
9018 
9019 
9020 /*************************************************************************
9021 * This function performs an edge-based FM refinement
9022 **************************************************************************/
9023 void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses)
9024 {
9025  int i, ii, j, k, l, kwgt, nvtxs, ncon, nbnd, nswaps, from, to, pass, limit, tmp, cnum;
9026  idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
9027  idxtype *moved, *swaps, *perm, *qnum;
9028  float *nvwgt, *npwgts, mindiff[MAXNCON], origbal, minbal, newbal;
9029  PQueueType parts[MAXNCON][2];
9030  int higain, oldgain, mincut, initcut, newcut, mincutorder;
9031  float rtpwgts[2];
9032 
9033  nvtxs = graph->nvtxs;
9034  ncon = graph->ncon;
9035  xadj = graph->xadj;
9036  nvwgt = graph->nvwgt;
9037  adjncy = graph->adjncy;
9038  adjwgt = graph->adjwgt;
9039  where = graph->where;
9040  id = graph->id;
9041  ed = graph->ed;
9042  npwgts = graph->npwgts;
9043  bndptr = graph->bndptr;
9044  bndind = graph->bndind;
9045 
9046  moved = idxwspacemalloc(ctrl, nvtxs);
9047  swaps = idxwspacemalloc(ctrl, nvtxs);
9048  perm = idxwspacemalloc(ctrl, nvtxs);
9049  qnum = idxwspacemalloc(ctrl, nvtxs);
9050 
9051  limit = amin(amax(0.01*nvtxs, 25), 150);
9052 
9053  /* Initialize the queues */
9054  for (i=0; i<ncon; i++) {
9055  PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
9056  PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
9057  }
9058  for (i=0; i<nvtxs; i++)
9059  qnum[i] = samax(ncon, nvwgt+i*ncon);
9060 
9061  origbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
9062 
9063  rtpwgts[0] = origbal*tpwgts[0];
9064  rtpwgts[1] = origbal*tpwgts[1];
9065 
9066 
9067  if (ctrl->dbglvl&DBG_REFINE) {
9068  printf("Parts: [");
9069  for (l=0; l<ncon; l++)
9070  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
9071  printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, origbal);
9072  }
9073 
9074  idxset(nvtxs, -1, moved);
9075  for (pass=0; pass<npasses; pass++) { /* Do a number of passes */
9076  for (i=0; i<ncon; i++) {
9077  PQueueReset(&parts[i][0]);
9078  PQueueReset(&parts[i][1]);
9079  }
9080 
9081  mincutorder = -1;
9082  newcut = mincut = initcut = graph->mincut;
9083  for (i=0; i<ncon; i++)
9084  mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
9085  minbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
9086 
9087  ASSERT(ComputeCut(graph, where) == graph->mincut);
9088  ASSERT(CheckBnd(graph));
9089 
9090  /* Insert boundary nodes in the priority queues */
9091  nbnd = graph->nbnd;
9092  RandomPermute(nbnd, perm, 1);
9093  for (ii=0; ii<nbnd; ii++) {
9094  i = bndind[perm[ii]];
9095  ASSERT(ed[i] > 0 || id[i] == 0);
9096  ASSERT(bndptr[i] != -1);
9097  PQueueInsert(&parts[qnum[i]][where[i]], i, ed[i]-id[i]);
9098  }
9099 
9100  for (nswaps=0; nswaps<nvtxs; nswaps++) {
9101  SelectQueue(ncon, npwgts, rtpwgts, &from, &cnum, parts);
9102  to = (from+1)%2;
9103 
9104  if (from == -1 || (higain = PQueueGetMax(&parts[cnum][from])) == -1)
9105  break;
9106  ASSERT(bndptr[higain] != -1);
9107 
9108  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
9109  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
9110 
9111  newcut -= (ed[higain]-id[higain]);
9112  newbal = Compute2WayHLoadImbalance(ncon, npwgts, tpwgts);
9113 
9114  if ((newcut < mincut && newbal-origbal <= .00001) ||
9115  (newcut == mincut && (newbal < minbal ||
9116  (newbal == minbal && BetterBalance(ncon, npwgts, tpwgts, mindiff))))) {
9117  mincut = newcut;
9118  minbal = newbal;
9119  mincutorder = nswaps;
9120  for (i=0; i<ncon; i++)
9121  mindiff[i] = fabs(tpwgts[0]-npwgts[i]);
9122  }
9123  else if (nswaps-mincutorder > limit) { /* We hit the limit, undo last move */
9124  newcut += (ed[higain]-id[higain]);
9125  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
9126  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
9127  break;
9128  }
9129 
9130  where[higain] = to;
9131  moved[higain] = nswaps;
9132  swaps[nswaps] = higain;
9133 
9134  if (ctrl->dbglvl&DBG_MOVEINFO) {
9135  printf("Moved %6d from %d(%d). Gain: %5d, Cut: %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], newcut);
9136  for (l=0; l<ncon; l++)
9137  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
9138  printf(", %.3f LB: %.3f\n", minbal, newbal);
9139  }
9140 
9141 
9142  /**************************************************************
9143  * Update the id[i]/ed[i] values of the affected nodes
9144  ***************************************************************/
9145  SWAP(id[higain], ed[higain], tmp);
9146  if (ed[higain] == 0 && xadj[higain] < xadj[higain+1])
9147  BNDDelete(nbnd, bndind, bndptr, higain);
9148 
9149  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
9150  k = adjncy[j];
9151  oldgain = ed[k]-id[k];
9152 
9153  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
9154  INC_DEC(id[k], ed[k], kwgt);
9155 
9156  /* Update its boundary information and queue position */
9157  if (bndptr[k] != -1) { /* If k was a boundary vertex */
9158  if (ed[k] == 0) { /* Not a boundary vertex any more */
9159  BNDDelete(nbnd, bndind, bndptr, k);
9160  if (moved[k] == -1) /* Remove it if in the queues */
9161  PQueueDelete(&parts[qnum[k]][where[k]], k, oldgain);
9162  }
9163  else { /* If it has not been moved, update its position in the queue */
9164  if (moved[k] == -1)
9165  PQueueUpdate(&parts[qnum[k]][where[k]], k, oldgain, ed[k]-id[k]);
9166  }
9167  }
9168  else {
9169  if (ed[k] > 0) { /* It will now become a boundary vertex */
9170  BNDInsert(nbnd, bndind, bndptr, k);
9171  if (moved[k] == -1)
9172  PQueueInsert(&parts[qnum[k]][where[k]], k, ed[k]-id[k]);
9173  }
9174  }
9175  }
9176 
9177  }
9178 
9179 
9180  /****************************************************************
9181  * Roll back computations
9182  *****************************************************************/
9183  for (i=0; i<nswaps; i++)
9184  moved[swaps[i]] = -1; /* reset moved array */
9185  for (nswaps--; nswaps>mincutorder; nswaps--) {
9186  higain = swaps[nswaps];
9187 
9188  to = where[higain] = (where[higain]+1)%2;
9189  SWAP(id[higain], ed[higain], tmp);
9190  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
9191  BNDDelete(nbnd, bndind, bndptr, higain);
9192  else if (ed[higain] > 0 && bndptr[higain] == -1)
9193  BNDInsert(nbnd, bndind, bndptr, higain);
9194 
9195  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
9196  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+((to+1)%2)*ncon, 1);
9197  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
9198  k = adjncy[j];
9199 
9200  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
9201  INC_DEC(id[k], ed[k], kwgt);
9202 
9203  if (bndptr[k] != -1 && ed[k] == 0)
9204  BNDDelete(nbnd, bndind, bndptr, k);
9205  if (bndptr[k] == -1 && ed[k] > 0)
9206  BNDInsert(nbnd, bndind, bndptr, k);
9207  }
9208  }
9209 
9210  if (ctrl->dbglvl&DBG_REFINE) {
9211  printf("\tMincut: %6d at %5d, NBND: %6d, NPwgts: [", mincut, mincutorder, nbnd);
9212  for (l=0; l<ncon; l++)
9213  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
9214  printf("], LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
9215  }
9216 
9217  graph->mincut = mincut;
9218  graph->nbnd = nbnd;
9219 
9220  if (mincutorder == -1 || mincut == initcut)
9221  break;
9222  }
9223 
9224  for (i=0; i<ncon; i++) {
9225  PQueueFree(ctrl, &parts[i][0]);
9226  PQueueFree(ctrl, &parts[i][1]);
9227  }
9228 
9229  idxwspacefree(ctrl, nvtxs);
9230  idxwspacefree(ctrl, nvtxs);
9231  idxwspacefree(ctrl, nvtxs);
9232  idxwspacefree(ctrl, nvtxs);
9233 
9234 }
9235 
9236 
9237 /*************************************************************************
9238 * This function selects the partition number and the queue from which
9239 * we will move vertices out
9240 **************************************************************************/
9241 void SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2])
9242 {
9243  int i, part, maxgain=0;
9244  float max, maxdiff=0.0;
9245 
9246  *from = -1;
9247  *cnum = -1;
9248 
9249  /* First determine the side and the queue, irrespective of the presence of nodes */
9250  for (part=0; part<2; part++) {
9251  for (i=0; i<ncon; i++) {
9252  if (npwgts[part*ncon+i]-tpwgts[part] >= maxdiff) {
9253  maxdiff = npwgts[part*ncon+i]-tpwgts[part];
9254  *from = part;
9255  *cnum = i;
9256  }
9257  }
9258  }
9259 
9260  /* printf("Selected1 %d(%d) -> %d [%5f]\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from]), maxdiff); */
9261 
9262  if (*from != -1 && PQueueGetSize(&queues[*cnum][*from]) == 0) {
9263  /* The desired queue is empty, select a node from that side anyway */
9264  for (i=0; i<ncon; i++) {
9265  if (PQueueGetSize(&queues[i][*from]) > 0) {
9266  max = npwgts[(*from)*ncon + i];
9267  *cnum = i;
9268  break;
9269  }
9270  }
9271 
9272  for (i++; i<ncon; i++) {
9273  if (npwgts[(*from)*ncon + i] > max && PQueueGetSize(&queues[i][*from]) > 0) {
9274  max = npwgts[(*from)*ncon + i];
9275  *cnum = i;
9276  }
9277  }
9278  }
9279 
9280  /* Check to see if you can focus on the cut */
9281  if (maxdiff <= 0.0 || *from == -1) {
9282  maxgain = -100000;
9283 
9284  for (part=0; part<2; part++) {
9285  for (i=0; i<ncon; i++) {
9286  if (PQueueGetSize(&queues[i][part]) > 0 && PQueueGetKey(&queues[i][part]) > maxgain) {
9287  maxgain = PQueueGetKey(&queues[i][part]);
9288  *from = part;
9289  *cnum = i;
9290  }
9291  }
9292  }
9293  }
9294 
9295  /* printf("Selected2 %d(%d) -> %d\n", *from, *cnum, PQueueGetSize(&queues[*cnum][*from])); */
9296 }
9297 
9298 
9299 
9300 
9301 
9302 /*************************************************************************
9303 * This function checks if the balance achieved is better than the diff
9304 * For now, it uses a 2-norm measure
9305 **************************************************************************/
9306 int BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff)
9307 {
9308  int i;
9309  float ndiff[MAXNCON];
9310 
9311  for (i=0; i<ncon; i++)
9312  ndiff[i] = fabs(tpwgts[0]-npwgts[i]);
9313 
9314  return snorm2(ncon, ndiff) < snorm2(ncon, diff);
9315 }
9316 
9317 
9318 
9319 /*************************************************************************
9320 * This function computes the load imbalance over all the constrains
9321 **************************************************************************/
9322 float Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts)
9323 {
9324  int i;
9325  float max=0.0, temp;
9326 
9327  for (i=0; i<ncon; i++) {
9328  /* temp = amax(npwgts[i]/tpwgts[0], npwgts[ncon+i]/tpwgts[1]); */
9329  temp = fabs(tpwgts[0]-npwgts[i])/tpwgts[0];
9330  max = (max < temp ? temp : max);
9331  }
9332  return 1.0+max;
9333 }
9334 
9335 
9336 /*************************************************************************
9337 * This function computes the load imbalance over all the constrains
9338 * For now assume that we just want balanced partitionings
9339 **************************************************************************/
9340 void Compute2WayHLoadImbalanceVec(int ncon, float *npwgts, float *tpwgts, float *lbvec)
9341 {
9342  int i;
9343 
9344  for (i=0; i<ncon; i++)
9345  lbvec[i] = 1.0 + fabs(tpwgts[0]-npwgts[i])/tpwgts[0];
9346 }
9347 
9348 /*
9349  * Copyright 1997, Regents of the University of Minnesota
9350  *
9351  * mincover.c
9352  *
9353  * This file implements the minimum cover algorithm
9354  *
9355  * Started 8/1/97
9356  * George
9357  *
9358  * $Id$
9359  */
9360 
9361 
9362 
9363 /*************************************************************************
9364 * Constants used by mincover algorithm
9365 **************************************************************************/
9366 #define INCOL 10
9367 #define INROW 20
9368 #define VC 1
9369 #define SC 2
9370 #define HC 3
9371 #define VR 4
9372 #define SR 5
9373 #define HR 6
9374 
9375 
9376 /*************************************************************************
9377 * This function returns the min-cover of a bipartite graph.
9378 * The algorithm used is due to Hopcroft and Karp as modified by Duff etal
9379 * adj: the adjacency list of the bipartite graph
9380 * asize: the number of vertices in the first part of the bipartite graph
9381 * bsize-asize: the number of vertices in the second part
9382 * 0..(asize-1) > A vertices
9383 * asize..bsize > B vertices
9384 *
9385 * Returns:
9386 * cover : the actual cover (array)
9387 * csize : the size of the cover
9388 **************************************************************************/
9389 void MinCover(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *cover, int *csize)
9390 {
9391  int i, j;
9392  idxtype *mate, *queue, *flag, *level, *lst;
9393  int fptr, rptr, lstptr;
9394  int row, maxlevel, col;
9395 
9396  mate = idxsmalloc(bsize, -1, "MinCover: mate");
9397  flag = idxmalloc(bsize, "MinCover: flag");
9398  level = idxmalloc(bsize, "MinCover: level");
9399  queue = idxmalloc(bsize, "MinCover: queue");
9400  lst = idxmalloc(bsize, "MinCover: lst");
9401 
9402  /* Get a cheap matching */
9403  for (i=0; i<asize; i++) {
9404  for (j=xadj[i]; j<xadj[i+1]; j++) {
9405  if (mate[adjncy[j]] == -1) {
9406  mate[i] = adjncy[j];
9407  mate[adjncy[j]] = i;
9408  break;
9409  }
9410  }
9411  }
9412 
9413  /* Get into the main loop */
9414  while (1) {
9415  /* Initialization */
9416  fptr = rptr = 0; /* Empty Queue */
9417  lstptr = 0; /* Empty List */
9418  for (i=0; i<bsize; i++) {
9419  level[i] = -1;
9420  flag[i] = 0;
9421  }
9422  maxlevel = bsize;
9423 
9424  /* Insert free nodes into the queue */
9425  for (i=0; i<asize; i++)
9426  if (mate[i] == -1) {
9427  queue[rptr++] = i;
9428  level[i] = 0;
9429  }
9430 
9431  /* Perform the BFS */
9432  while (fptr != rptr) {
9433  row = queue[fptr++];
9434  if (level[row] < maxlevel) {
9435  flag[row] = 1;
9436  for (j=xadj[row]; j<xadj[row+1]; j++) {
9437  col = adjncy[j];
9438  if (!flag[col]) { /* If this column has not been accessed yet */
9439  flag[col] = 1;
9440  if (mate[col] == -1) { /* Free column node was found */
9441  maxlevel = level[row];
9442  lst[lstptr++] = col;
9443  }
9444  else { /* This column node is matched */
9445  if (flag[mate[col]])
9446  printf("\nSomething wrong, flag[%d] is 1",mate[col]);
9447  queue[rptr++] = mate[col];
9448  level[mate[col]] = level[row] + 1;
9449  }
9450  }
9451  }
9452  }
9453  }
9454 
9455  if (lstptr == 0)
9456  break; /* No free columns can be reached */
9457 
9458  /* Perform restricted DFS from the free column nodes */
9459  for (i=0; i<lstptr; i++)
9460  MinCover_Augment(xadj, adjncy, lst[i], mate, flag, level, maxlevel);
9461  }
9462 
9463  MinCover_Decompose(xadj, adjncy, asize, bsize, mate, cover, csize);
9464 
9465  GKfree((void **) &mate, (void **) &flag, (void **) &level,
9466  (void **) &queue, (void **) &lst, LTERM);
9467 
9468 }
9469 
9470 
9471 /*************************************************************************
9472 * This function perfoms a restricted DFS and augments matchings
9473 **************************************************************************/
9474 int MinCover_Augment(idxtype *xadj, idxtype *adjncy, int col, idxtype *mate, idxtype *flag, idxtype *level, int maxlevel)
9475 {
9476  int i;
9477  int row = -1;
9478  int status;
9479 
9480  flag[col] = 2;
9481  for (i=xadj[col]; i<xadj[col+1]; i++) {
9482  row = adjncy[i];
9483 
9484  if (flag[row] == 1) { /* First time through this row node */
9485  if (level[row] == maxlevel) { /* (col, row) is an edge of the G^T */
9486  flag[row] = 2; /* Mark this node as being visited */
9487  if (maxlevel != 0)
9488  status = MinCover_Augment(xadj, adjncy, mate[row], mate, flag, level, maxlevel-1);
9489  else
9490  status = 1;
9491 
9492  if (status) {
9493  mate[col] = row;
9494  mate[row] = col;
9495  return 1;
9496  }
9497  }
9498  }
9499  }
9500 
9501  return 0;
9502 }
9503 
9504 
9505 
9506 /*************************************************************************
9507 * This function performs a coarse decomposition and determines the
9508 * min-cover.
9509 * REF: Pothen ACMTrans. on Amth Software
9510 **************************************************************************/
9511 void MinCover_Decompose(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *mate, idxtype *cover, int *csize)
9512 {
9513  int i, k;
9514  idxtype *where;
9515  int card[10];
9516 
9517  where = idxmalloc(bsize, "MinCover_Decompose: where");
9518  for (i=0; i<10; i++)
9519  card[i] = 0;
9520 
9521  for (i=0; i<asize; i++)
9522  where[i] = SC;
9523  for (; i<bsize; i++)
9524  where[i] = SR;
9525 
9526  for (i=0; i<asize; i++)
9527  if (mate[i] == -1)
9528  MinCover_ColDFS(xadj, adjncy, i, mate, where, INCOL);
9529  for (; i<bsize; i++)
9530  if (mate[i] == -1)
9531  MinCover_RowDFS(xadj, adjncy, i, mate, where, INROW);
9532 
9533  for (i=0; i<bsize; i++)
9534  card[where[i]]++;
9535 
9536  k = 0;
9537  if (abs(card[VC]+card[SC]-card[HR]) < abs(card[VC]-card[SR]-card[HR])) { /* S = VC+SC+HR */
9538  /* printf("%d %d ",vc+sc, hr); */
9539  for (i=0; i<bsize; i++)
9540  if (where[i] == VC || where[i] == SC || where[i] == HR)
9541  cover[k++] = i;
9542  }
9543  else { /* S = VC+SR+HR */
9544  /* printf("%d %d ",vc, hr+sr); */
9545  for (i=0; i<bsize; i++)
9546  if (where[i] == VC || where[i] == SR || where[i] == HR)
9547  cover[k++] = i;
9548  }
9549 
9550  *csize = k;
9551  free(where);
9552 
9553 }
9554 
9555 
9556 /*************************************************************************
9557 * This function perfoms a dfs starting from an unmatched col node
9558 * forming alternate paths
9559 **************************************************************************/
9560 void MinCover_ColDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag)
9561 {
9562  int i;
9563 
9564  if (flag == INCOL) {
9565  if (where[root] == HC)
9566  return;
9567  where[root] = HC;
9568  for (i=xadj[root]; i<xadj[root+1]; i++)
9569  MinCover_ColDFS(xadj, adjncy, adjncy[i], mate, where, INROW);
9570  }
9571  else {
9572  if (where[root] == HR)
9573  return;
9574  where[root] = HR;
9575  if (mate[root] != -1)
9576  MinCover_ColDFS(xadj, adjncy, mate[root], mate, where, INCOL);
9577  }
9578 
9579 }
9580 
9581 /*************************************************************************
9582 * This function perfoms a dfs starting from an unmatched col node
9583 * forming alternate paths
9584 **************************************************************************/
9585 void MinCover_RowDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag)
9586 {
9587  int i;
9588 
9589  if (flag == INROW) {
9590  if (where[root] == VR)
9591  return;
9592  where[root] = VR;
9593  for (i=xadj[root]; i<xadj[root+1]; i++)
9594  MinCover_RowDFS(xadj, adjncy, adjncy[i], mate, where, INCOL);
9595  }
9596  else {
9597  if (where[root] == VC)
9598  return;
9599  where[root] = VC;
9600  if (mate[root] != -1)
9601  MinCover_RowDFS(xadj, adjncy, mate[root], mate, where, INROW);
9602  }
9603 
9604 }
9605 
9606 
9607 
9608 /*
9609  * Copyright 1997, Regents of the University of Minnesota
9610  *
9611  * minitpart2.c
9612  *
9613  * This file contains code that performs the initial partition of the
9614  * coarsest graph
9615  *
9616  * Started 7/23/97
9617  * George
9618  *
9619  * $Id$
9620  *
9621  */
9622 
9623 
9624 
9625 /*************************************************************************
9626 * This function computes the initial bisection of the coarsest graph
9627 **************************************************************************/
9628 void MocInit2WayPartition2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
9629 {
9630  int dbglvl;
9631 
9632  dbglvl = ctrl->dbglvl;
9633  IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
9634  IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
9635 
9636  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
9637 
9638  switch (ctrl->IType) {
9639  case IPART_GGPKL:
9640  case IPART_RANDOM:
9641  MocGrowBisection2(ctrl, graph, tpwgts, ubvec);
9642  break;
9643  case 3:
9644  MocGrowBisectionNew2(ctrl, graph, tpwgts, ubvec);
9645  break;
9646  default:
9647  errexit("Unknown initial partition type: %d\n", ctrl->IType);
9648  }
9649 
9650  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d\n", graph->mincut));
9651  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
9652  ctrl->dbglvl = dbglvl;
9653 
9654 }
9655 
9656 
9657 
9658 
9659 /*************************************************************************
9660 * This function takes a graph and produces a bisection by using a region
9661 * growing algorithm. The resulting partition is returned in
9662 * graph->where
9663 **************************************************************************/
9664 void MocGrowBisection2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
9665 {
9666  int nvtxs, bestcut, nbfs;
9667  idxtype *bestwhere, *where;
9668 
9669  nvtxs = graph->nvtxs;
9670 
9671  MocAllocate2WayPartitionMemory(ctrl, graph);
9672  where = graph->where;
9673 
9674  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
9675  nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
9676  bestcut = idxsum(graph->nedges, graph->adjwgt);
9677 
9678  for (; nbfs>0; nbfs--) {
9679  idxset(nvtxs, 1, where);
9680  where[RandomInRange(nvtxs)] = 0;
9681 
9682  MocCompute2WayPartitionParams(ctrl, graph);
9683 
9684  MocBalance2Way2(ctrl, graph, tpwgts, ubvec);
9685 
9686  MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4);
9687 
9688  MocBalance2Way2(ctrl, graph, tpwgts, ubvec);
9689  MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4);
9690 
9691  if (bestcut > graph->mincut) {
9692  bestcut = graph->mincut;
9693  idxcopy(nvtxs, where, bestwhere);
9694  if (bestcut == 0)
9695  break;
9696  }
9697  }
9698 
9699  graph->mincut = bestcut;
9700  idxcopy(nvtxs, bestwhere, where);
9701 
9702  GKfree((void **) &bestwhere, LTERM);
9703 }
9704 
9705 
9706 
9707 
9708 
9709 
9710 /*************************************************************************
9711 * This function takes a graph and produces a bisection by using a region
9712 * growing algorithm. The resulting partition is returned in
9713 * graph->where
9714 **************************************************************************/
9715 void MocGrowBisectionNew2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
9716 {
9717  int nvtxs, bestcut, nbfs;
9718  idxtype *bestwhere, *where;
9719 
9720  nvtxs = graph->nvtxs;
9721 
9722  MocAllocate2WayPartitionMemory(ctrl, graph);
9723  where = graph->where;
9724 
9725  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
9726  nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
9727  bestcut = idxsum(graph->nedges, graph->adjwgt);
9728 
9729  for (; nbfs>0; nbfs--) {
9730  idxset(nvtxs, 1, where);
9731  where[RandomInRange(nvtxs)] = 0;
9732 
9733  MocCompute2WayPartitionParams(ctrl, graph);
9734 
9735  MocInit2WayBalance2(ctrl, graph, tpwgts, ubvec);
9736 
9737  MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 4);
9738 
9739  if (bestcut > graph->mincut) {
9740  bestcut = graph->mincut;
9741  idxcopy(nvtxs, where, bestwhere);
9742  if (bestcut == 0)
9743  break;
9744  }
9745  }
9746 
9747  graph->mincut = bestcut;
9748  idxcopy(nvtxs, bestwhere, where);
9749 
9750  GKfree((void **) &bestwhere, LTERM);
9751 }
9752 
9753 
9754 
9755 /*************************************************************************
9756 * This function balances two partitions by moving the highest gain
9757 * (including negative gain) vertices to the other domain.
9758 * It is used only when tha unbalance is due to non contigous
9759 * subdomains. That is, the are no boundary vertices.
9760 * It moves vertices from the domain that is overweight to the one that
9761 * is underweight.
9762 **************************************************************************/
9763 void MocInit2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
9764 {
9765  int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, cnum, tmp, imin;
9766  idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
9767  idxtype *moved, *perm, *qnum;
9768  float *nvwgt, *npwgts, minwgt;
9769  PQueueType parts[MAXNCON][2];
9770  int higain, oldgain, mincut;
9771 
9772  nvtxs = graph->nvtxs;
9773  ncon = graph->ncon;
9774  xadj = graph->xadj;
9775  adjncy = graph->adjncy;
9776  nvwgt = graph->nvwgt;
9777  adjwgt = graph->adjwgt;
9778  where = graph->where;
9779  id = graph->id;
9780  ed = graph->ed;
9781  npwgts = graph->npwgts;
9782  bndptr = graph->bndptr;
9783  bndind = graph->bndind;
9784 
9785  moved = idxwspacemalloc(ctrl, nvtxs);
9786  perm = idxwspacemalloc(ctrl, nvtxs);
9787  qnum = idxwspacemalloc(ctrl, nvtxs);
9788 
9789  /* This is called for initial partitioning so we know from where to pick nodes */
9790  from = 1;
9791  to = (from+1)%2;
9792 
9793  if (ctrl->dbglvl&DBG_REFINE) {
9794  printf("Parts: [");
9795  for (l=0; l<ncon; l++)
9796  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
9797  printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1], graph->nvtxs, graph->nbnd, graph->mincut, ComputeLoadImbalance(ncon, 2, npwgts, tpwgts));
9798  }
9799 
9800  for (i=0; i<ncon; i++) {
9801  PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
9802  PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
9803  }
9804 
9805  idxset(nvtxs, -1, moved);
9806 
9807  ASSERT(ComputeCut(graph, where) == graph->mincut);
9808  ASSERT(CheckBnd(graph));
9809  ASSERT(CheckGraph(graph));
9810 
9811  /* Compute the queues in which each vertex will be assigned to */
9812  for (i=0; i<nvtxs; i++)
9813  qnum[i] = samax(ncon, nvwgt+i*ncon);
9814 
9815  /* Insert the nodes of the proper partition in the appropriate priority queue */
9816  RandomPermute(nvtxs, perm, 1);
9817  for (ii=0; ii<nvtxs; ii++) {
9818  i = perm[ii];
9819  if (where[i] == from) {
9820  if (ed[i] > 0)
9821  PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]);
9822  else
9823  PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]);
9824  }
9825  }
9826 
9827 /*
9828  for (i=0; i<ncon; i++)
9829  printf("Queue #%d has %d %d\n", i, parts[i][0].nnodes, parts[i][1].nnodes);
9830 */
9831 
9832  /* Determine the termination criterion */
9833  imin = 0;
9834  for (i=1; i<ncon; i++)
9835  imin = (ubvec[i] < ubvec[imin] ? i : imin);
9836  minwgt = .5/ubvec[imin];
9837 
9838  mincut = graph->mincut;
9839  nbnd = graph->nbnd;
9840  for (nswaps=0; nswaps<nvtxs; nswaps++) {
9841  /* Exit as soon as the minimum weight crossed over */
9842  if (npwgts[to*ncon+imin] > minwgt)
9843  break;
9844 
9845  if ((cnum = SelectQueueOneWay2(ncon, npwgts+to*ncon, parts, ubvec)) == -1)
9846  break;
9847 
9848  if ((higain = PQueueGetMax(&parts[cnum][0])) == -1)
9849  higain = PQueueGetMax(&parts[cnum][1]);
9850 
9851  mincut -= (ed[higain]-id[higain]);
9852  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
9853  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
9854 
9855  where[higain] = to;
9856  moved[higain] = nswaps;
9857 
9858  if (ctrl->dbglvl&DBG_MOVEINFO) {
9859  printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut);
9860  for (l=0; l<ncon; l++)
9861  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
9862  printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts));
9863  if (ed[higain] == 0 && id[higain] > 0)
9864  printf("\t Pulled from the interior!\n");
9865  }
9866 
9867 
9868  /**************************************************************
9869  * Update the id[i]/ed[i] values of the affected nodes
9870  ***************************************************************/
9871  SWAP(id[higain], ed[higain], tmp);
9872  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
9873  BNDDelete(nbnd, bndind, bndptr, higain);
9874  if (ed[higain] > 0 && bndptr[higain] == -1)
9875  BNDInsert(nbnd, bndind, bndptr, higain);
9876 
9877  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
9878  k = adjncy[j];
9879  oldgain = ed[k]-id[k];
9880 
9881  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
9882  INC_DEC(id[k], ed[k], kwgt);
9883 
9884  /* Update the queue position */
9885  if (moved[k] == -1 && where[k] == from) {
9886  if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */
9887  PQueueDelete(&parts[qnum[k]][1], k, oldgain);
9888  PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]);
9889  }
9890  else { /* It must be in the boundary already */
9891  if (bndptr[k] == -1)
9892  printf("What you thought was wrong!\n");
9893  PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]);
9894  }
9895  }
9896 
9897  /* Update its boundary information */
9898  if (ed[k] == 0 && bndptr[k] != -1)
9899  BNDDelete(nbnd, bndind, bndptr, k);
9900  else if (ed[k] > 0 && bndptr[k] == -1)
9901  BNDInsert(nbnd, bndind, bndptr, k);
9902  }
9903 
9904  ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut));
9905 
9906  }
9907 
9908  if (ctrl->dbglvl&DBG_REFINE) {
9909  printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd);
9910  for (l=0; l<ncon; l++)
9911  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
9912  printf(", LB: %.3f\n", ComputeLoadImbalance(ncon, 2, npwgts, tpwgts));
9913  }
9914 
9915  graph->mincut = mincut;
9916  graph->nbnd = nbnd;
9917 
9918  for (i=0; i<ncon; i++) {
9919  PQueueFree(ctrl, &parts[i][0]);
9920  PQueueFree(ctrl, &parts[i][1]);
9921  }
9922 
9923  ASSERT(ComputeCut(graph, where) == graph->mincut);
9924  ASSERT(CheckBnd(graph));
9925 
9926  idxwspacefree(ctrl, nvtxs);
9927  idxwspacefree(ctrl, nvtxs);
9928  idxwspacefree(ctrl, nvtxs);
9929 }
9930 
9931 
9932 
9933 /*************************************************************************
9934 * This function selects the partition number and the queue from which
9935 * we will move vertices out
9936 **************************************************************************/
9937 int SelectQueueOneWay2(int ncon, float *pto, PQueueType queues[MAXNCON][2], float *ubvec)
9938 {
9939  int i, cnum=-1, imax, maxgain;
9940  float max=0.0;
9941  float twgt[MAXNCON];
9942 
9943  for (i=0; i<ncon; i++) {
9944  if (max < pto[i]) {
9945  imax = i;
9946  max = pto[i];
9947  }
9948  }
9949  for (i=0; i<ncon; i++)
9950  twgt[i] = (max/(ubvec[imax]*ubvec[i]))/pto[i];
9951  twgt[imax] = 0.0;
9952 
9953  max = 0.0;
9954  for (i=0; i<ncon; i++) {
9955  if (max < twgt[i] && (PQueueGetSize(&queues[i][0]) > 0 || PQueueGetSize(&queues[i][1]) > 0)) {
9956  max = twgt[i];
9957  cnum = i;
9958  }
9959  }
9960  if (max > 1)
9961  return cnum;
9962 
9963  /* optimize of cut */
9964  maxgain = -10000000;
9965  for (i=0; i<ncon; i++) {
9966  if (PQueueGetSize(&queues[i][0]) > 0 && PQueueGetKey(&queues[i][0]) > maxgain) {
9967  maxgain = PQueueGetKey(&queues[i][0]);
9968  cnum = i;
9969  }
9970  }
9971 
9972  return cnum;
9973 
9974 }
9975 
9976 /*
9977  * Copyright 1997, Regents of the University of Minnesota
9978  *
9979  * minitpart.c
9980  *
9981  * This file contains code that performs the initial partition of the
9982  * coarsest graph
9983  *
9984  * Started 7/23/97
9985  * George
9986  *
9987  * $Id$
9988  *
9989  */
9990 
9991 
9992 
9993 /*************************************************************************
9994 * This function computes the initial bisection of the coarsest graph
9995 **************************************************************************/
9996 void MocInit2WayPartition(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
9997 {
9998  int dbglvl;
9999 
10000  dbglvl = ctrl->dbglvl;
10001  IFSET(ctrl->dbglvl, DBG_REFINE, ctrl->dbglvl -= DBG_REFINE);
10002  IFSET(ctrl->dbglvl, DBG_MOVEINFO, ctrl->dbglvl -= DBG_MOVEINFO);
10003 
10004  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
10005 
10006  switch (ctrl->IType) {
10007  case IPART_GGPKL:
10008  MocGrowBisection(ctrl, graph, tpwgts, ubfactor);
10009  break;
10010  case IPART_RANDOM:
10011  MocRandomBisection(ctrl, graph, tpwgts, ubfactor);
10012  break;
10013  default:
10014  errexit("Unknown initial partition type: %d\n", ctrl->IType);
10015  }
10016 
10017  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial Cut: %d [%d]\n", graph->mincut, graph->where[0]));
10018  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
10019  ctrl->dbglvl = dbglvl;
10020 
10021 }
10022 
10023 
10024 
10025 
10026 
10027 /*************************************************************************
10028 * This function takes a graph and produces a bisection by using a region
10029 * growing algorithm. The resulting partition is returned in
10030 * graph->where
10031 **************************************************************************/
10032 void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
10033 {
10034  int nvtxs, bestcut, nbfs;
10035  idxtype *bestwhere, *where;
10036 
10037  nvtxs = graph->nvtxs;
10038 
10039  MocAllocate2WayPartitionMemory(ctrl, graph);
10040  where = graph->where;
10041 
10042  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
10043  nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
10044  bestcut = idxsum(graph->nedges, graph->adjwgt);
10045 
10046  for (; nbfs>0; nbfs--) {
10047  idxset(nvtxs, 1, where);
10048  where[RandomInRange(nvtxs)] = 0;
10049 
10050  MocCompute2WayPartitionParams(ctrl, graph);
10051 
10052  MocInit2WayBalance(ctrl, graph, tpwgts);
10053 
10054  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
10055 
10056  MocBalance2Way(ctrl, graph, tpwgts, 1.02);
10057  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 4);
10058 
10059  if (bestcut >= graph->mincut) {
10060  bestcut = graph->mincut;
10061  idxcopy(nvtxs, where, bestwhere);
10062  if (bestcut == 0)
10063  break;
10064  }
10065  }
10066 
10067  graph->mincut = bestcut;
10068  idxcopy(nvtxs, bestwhere, where);
10069 
10070  GKfree((void **) &bestwhere, LTERM);
10071 }
10072 
10073 
10074 
10075 /*************************************************************************
10076 * This function takes a graph and produces a bisection by using a region
10077 * growing algorithm. The resulting partition is returned in
10078 * graph->where
10079 **************************************************************************/
10080 void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
10081 {
10082  int i, ii, nvtxs, ncon, bestcut, nbfs, qnum;
10083  idxtype *bestwhere, *where, *perm;
10084  int counts[MAXNCON];
10085  float *nvwgt;
10086 
10087  nvtxs = graph->nvtxs;
10088  ncon = graph->ncon;
10089  nvwgt = graph->nvwgt;
10090 
10091  MocAllocate2WayPartitionMemory(ctrl, graph);
10092  where = graph->where;
10093 
10094  bestwhere = idxmalloc(nvtxs, "BisectGraph: bestwhere");
10095  nbfs = 2*(nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);
10096  bestcut = idxsum(graph->nedges, graph->adjwgt);
10097  perm = idxmalloc(nvtxs, "BisectGraph: perm");
10098 
10099  for (; nbfs>0; nbfs--) {
10100  for (i=0; i<ncon; i++)
10101  counts[i] = 0;
10102 
10103  RandomPermute(nvtxs, perm, 1);
10104 
10105  /* Partition by spliting the queues randomly */
10106  for (ii=0; ii<nvtxs; ii++) {
10107  i = perm[ii];
10108  qnum = samax(ncon, nvwgt+i*ncon);
10109  where[i] = counts[qnum];
10110  counts[qnum] = (counts[qnum]+1)%2;
10111  }
10112 
10113  MocCompute2WayPartitionParams(ctrl, graph);
10114 
10115  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
10116  MocBalance2Way(ctrl, graph, tpwgts, 1.02);
10117  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
10118  MocBalance2Way(ctrl, graph, tpwgts, 1.02);
10119  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 6);
10120 
10121  /*
10122  printf("Edgecut: %6d, NPwgts: [", graph->mincut);
10123  for (i=0; i<graph->ncon; i++)
10124  printf("(%.3f %.3f) ", graph->npwgts[i], graph->npwgts[graph->ncon+i]);
10125  printf("]\n");
10126  */
10127 
10128  if (bestcut >= graph->mincut) {
10129  bestcut = graph->mincut;
10130  idxcopy(nvtxs, where, bestwhere);
10131  if (bestcut == 0)
10132  break;
10133  }
10134  }
10135 
10136  graph->mincut = bestcut;
10137  idxcopy(nvtxs, bestwhere, where);
10138 
10139  GKfree((void **) &bestwhere, &perm, LTERM);
10140 }
10141 
10142 
10143 
10144 
10145 /*************************************************************************
10146 * This function balances two partitions by moving the highest gain
10147 * (including negative gain) vertices to the other domain.
10148 * It is used only when tha unbalance is due to non contigous
10149 * subdomains. That is, the are no boundary vertices.
10150 * It moves vertices from the domain that is overweight to the one that
10151 * is underweight.
10152 **************************************************************************/
10153 void MocInit2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts)
10154 {
10155  int i, ii, j, k, l, kwgt, nvtxs, nbnd, ncon, nswaps, from, to, cnum, tmp;
10156  idxtype *xadj, *adjncy, *adjwgt, *where, *id, *ed, *bndptr, *bndind;
10157  idxtype *perm, *qnum;
10158  float *nvwgt, *npwgts;
10159  PQueueType parts[MAXNCON][2];
10160  int higain, oldgain, mincut;
10161 
10162  nvtxs = graph->nvtxs;
10163  ncon = graph->ncon;
10164  xadj = graph->xadj;
10165  adjncy = graph->adjncy;
10166  nvwgt = graph->nvwgt;
10167  adjwgt = graph->adjwgt;
10168  where = graph->where;
10169  id = graph->id;
10170  ed = graph->ed;
10171  npwgts = graph->npwgts;
10172  bndptr = graph->bndptr;
10173  bndind = graph->bndind;
10174 
10175  perm = idxwspacemalloc(ctrl, nvtxs);
10176  qnum = idxwspacemalloc(ctrl, nvtxs);
10177 
10178  /* This is called for initial partitioning so we know from where to pick nodes */
10179  from = 1;
10180  to = (from+1)%2;
10181 
10182  if (ctrl->dbglvl&DBG_REFINE) {
10183  printf("Parts: [");
10184  for (l=0; l<ncon; l++)
10185  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
10186  printf("] T[%.3f %.3f], Nv-Nb[%5d, %5d]. ICut: %6d, LB: %.3f [B]\n", tpwgts[0], tpwgts[1],
10187  graph->nvtxs, graph->nbnd, graph->mincut,
10188  Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
10189  }
10190 
10191  for (i=0; i<ncon; i++) {
10192  PQueueInit(ctrl, &parts[i][0], nvtxs, PLUS_GAINSPAN+1);
10193  PQueueInit(ctrl, &parts[i][1], nvtxs, PLUS_GAINSPAN+1);
10194  }
10195 
10196  ASSERT(ComputeCut(graph, where) == graph->mincut);
10197  ASSERT(CheckBnd(graph));
10198  ASSERT(CheckGraph(graph));
10199 
10200  /* Compute the queues in which each vertex will be assigned to */
10201  for (i=0; i<nvtxs; i++)
10202  qnum[i] = samax(ncon, nvwgt+i*ncon);
10203 
10204  /* Insert the nodes of the proper partition in the appropriate priority queue */
10205  RandomPermute(nvtxs, perm, 1);
10206  for (ii=0; ii<nvtxs; ii++) {
10207  i = perm[ii];
10208  if (where[i] == from) {
10209  if (ed[i] > 0)
10210  PQueueInsert(&parts[qnum[i]][0], i, ed[i]-id[i]);
10211  else
10212  PQueueInsert(&parts[qnum[i]][1], i, ed[i]-id[i]);
10213  }
10214  }
10215 
10216 
10217  mincut = graph->mincut;
10218  nbnd = graph->nbnd;
10219  for (nswaps=0; nswaps<nvtxs; nswaps++) {
10220  if (AreAnyVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, tpwgts[from]))
10221  break;
10222 
10223  if ((cnum = SelectQueueOneWay(ncon, npwgts, tpwgts, from, parts)) == -1)
10224  break;
10225 
10226  if ((higain = PQueueGetMax(&parts[cnum][0])) == -1)
10227  higain = PQueueGetMax(&parts[cnum][1]);
10228 
10229  mincut -= (ed[higain]-id[higain]);
10230  saxpy(ncon, 1.0, nvwgt+higain*ncon, 1, npwgts+to*ncon, 1);
10231  saxpy(ncon, -1.0, nvwgt+higain*ncon, 1, npwgts+from*ncon, 1);
10232 
10233  where[higain] = to;
10234 
10235  if (ctrl->dbglvl&DBG_MOVEINFO) {
10236  printf("Moved %6d from %d(%d). [%5d] %5d, NPwgts: ", higain, from, cnum, ed[higain]-id[higain], mincut);
10237  for (l=0; l<ncon; l++)
10238  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
10239  printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
10240  if (ed[higain] == 0 && id[higain] > 0)
10241  printf("\t Pulled from the interior!\n");
10242  }
10243 
10244 
10245  /**************************************************************
10246  * Update the id[i]/ed[i] values of the affected nodes
10247  ***************************************************************/
10248  SWAP(id[higain], ed[higain], tmp);
10249  if (ed[higain] == 0 && bndptr[higain] != -1 && xadj[higain] < xadj[higain+1])
10250  BNDDelete(nbnd, bndind, bndptr, higain);
10251  if (ed[higain] > 0 && bndptr[higain] == -1)
10252  BNDInsert(nbnd, bndind, bndptr, higain);
10253 
10254  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
10255  k = adjncy[j];
10256  oldgain = ed[k]-id[k];
10257 
10258  kwgt = (to == where[k] ? adjwgt[j] : -adjwgt[j]);
10259  INC_DEC(id[k], ed[k], kwgt);
10260 
10261  /* Update the queue position */
10262  if (where[k] == from) {
10263  if (ed[k] > 0 && bndptr[k] == -1) { /* It moves in boundary */
10264  PQueueDelete(&parts[qnum[k]][1], k, oldgain);
10265  PQueueInsert(&parts[qnum[k]][0], k, ed[k]-id[k]);
10266  }
10267  else { /* It must be in the boundary already */
10268  if (bndptr[k] == -1)
10269  printf("What you thought was wrong!\n");
10270  PQueueUpdate(&parts[qnum[k]][0], k, oldgain, ed[k]-id[k]);
10271  }
10272  }
10273 
10274  /* Update its boundary information */
10275  if (ed[k] == 0 && bndptr[k] != -1)
10276  BNDDelete(nbnd, bndind, bndptr, k);
10277  else if (ed[k] > 0 && bndptr[k] == -1)
10278  BNDInsert(nbnd, bndind, bndptr, k);
10279  }
10280 
10281  ASSERTP(ComputeCut(graph, where) == mincut, ("%d != %d\n", ComputeCut(graph, where), mincut));
10282 
10283  }
10284 
10285  if (ctrl->dbglvl&DBG_REFINE) {
10286  printf("\tMincut: %6d, NBND: %6d, NPwgts: ", mincut, nbnd);
10287  for (l=0; l<ncon; l++)
10288  printf("(%.3f, %.3f) ", npwgts[l], npwgts[ncon+l]);
10289  printf(", LB: %.3f\n", Compute2WayHLoadImbalance(ncon, npwgts, tpwgts));
10290  }
10291 
10292  graph->mincut = mincut;
10293  graph->nbnd = nbnd;
10294 
10295  for (i=0; i<ncon; i++) {
10296  PQueueFree(ctrl, &parts[i][0]);
10297  PQueueFree(ctrl, &parts[i][1]);
10298  }
10299 
10300  ASSERT(ComputeCut(graph, where) == graph->mincut);
10301  ASSERT(CheckBnd(graph));
10302 
10303  idxwspacefree(ctrl, nvtxs);
10304  idxwspacefree(ctrl, nvtxs);
10305 }
10306 
10307 
10308 
10309 
10310 /*************************************************************************
10311 * This function selects the partition number and the queue from which
10312 * we will move vertices out
10313 **************************************************************************/
10314 int SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from, PQueueType queues[MAXNCON][2])
10315 {
10316  int i, cnum=-1;
10317  float max=0.0;
10318 
10319  for (i=0; i<ncon; i++) {
10320  if (npwgts[from*ncon+i]-tpwgts[from] >= max &&
10321  PQueueGetSize(&queues[i][0]) + PQueueGetSize(&queues[i][1]) > 0) {
10322  max = npwgts[from*ncon+i]-tpwgts[0];
10323  cnum = i;
10324  }
10325  }
10326 
10327  return cnum;
10328 }
10329 
10330 
10331 /*
10332  * Copyright 1997, Regents of the University of Minnesota
10333  *
10334  * mkmetis.c
10335  *
10336  * This file contains the top level routines for the multilevel k-way partitioning
10337  * algorithm KMETIS.
10338  *
10339  * Started 7/28/97
10340  * George
10341  *
10342  * $Id$
10343  *
10344  */
10345 
10346 
10347 
10348 
10349 
10350 /*************************************************************************
10351 * This function is the entry point for KWMETIS
10352 **************************************************************************/
10353 void METIS_mCPartGraphKway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
10354  idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag,
10355  int *nparts, float *rubvec, int *options, int *edgecut,
10356  idxtype *part)
10357 {
10358  GraphType graph;
10359  CtrlType ctrl;
10360 
10361  if (*numflag == 1)
10362  Change2CNumbering(*nvtxs, xadj, adjncy);
10363 
10364  SetUpGraph(&graph, OP_KMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
10365 
10366  if (options[0] == 0) { /* Use the default parameters */
10367  ctrl.CType = McKMETIS_CTYPE;
10368  ctrl.IType = McKMETIS_ITYPE;
10369  ctrl.RType = McKMETIS_RTYPE;
10370  ctrl.dbglvl = McKMETIS_DBGLVL;
10371  }
10372  else {
10373  ctrl.CType = options[OPTION_CTYPE];
10374  ctrl.IType = options[OPTION_ITYPE];
10375  ctrl.RType = options[OPTION_RTYPE];
10376  ctrl.dbglvl = options[OPTION_DBGLVL];
10377  }
10378  ctrl.optype = OP_KMETIS;
10379  ctrl.CoarsenTo = amax((*nvtxs)/(20*log2(*nparts)), 30*(*nparts));
10380 
10381  ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
10382 
10383  InitRandom(-1);
10384 
10385  AllocateWorkSpace(&ctrl, &graph, *nparts);
10386 
10387  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
10388  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
10389 
10390  *edgecut = MCMlevelKWayPartitioning(&ctrl, &graph, *nparts, part, rubvec);
10391 
10392  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
10393  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
10394 
10395  FreeWorkSpace(&ctrl, &graph);
10396 
10397  if (*numflag == 1)
10398  Change2FNumbering(*nvtxs, xadj, adjncy, part);
10399 }
10400 
10401 
10402 /*************************************************************************
10403 * This function takes a graph and produces a bisection of it
10404 **************************************************************************/
10405 int MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part,
10406  float *rubvec)
10407 {
10408  int i;
10409  GraphType *cgraph;
10410  int options[10], edgecut;
10411 
10412  cgraph = MCCoarsen2Way(ctrl, graph);
10413 
10414  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
10415  MocAllocateKWayPartitionMemory(ctrl, cgraph, nparts);
10416 
10417  options[0] = 1;
10418  options[OPTION_CTYPE] = MATCH_SBHEM_INFNORM;
10419  options[OPTION_ITYPE] = IPART_RANDOM;
10420  options[OPTION_RTYPE] = RTYPE_FM;
10421  options[OPTION_DBGLVL] = 0;
10422 
10423  /* Determine what you will use as the initial partitioner, based on tolerances */
10424  for (i=0; i<graph->ncon; i++) {
10425  if (rubvec[i] > 1.2)
10426  break;
10427  }
10428  if (i == graph->ncon)
10429  METIS_mCPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon,
10430  cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts,
10431  options, &edgecut, cgraph->where);
10432  else
10433  METIS_mCHPartGraphRecursiveInternal(&cgraph->nvtxs, &cgraph->ncon,
10434  cgraph->xadj, cgraph->adjncy, cgraph->nvwgt, cgraph->adjwgt, &nparts,
10435  rubvec, options, &edgecut, cgraph->where);
10436 
10437 
10438  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));
10439  IFSET(ctrl->dbglvl, DBG_IPART, printf("Initial %d-way partitioning cut: %d\n", nparts, edgecut));
10440 
10441  IFSET(ctrl->dbglvl, DBG_KWAYPINFO, ComputePartitionInfo(cgraph, nparts, cgraph->where));
10442 
10443  MocRefineKWayHorizontal(ctrl, graph, cgraph, nparts, rubvec);
10444 
10445  idxcopy(graph->nvtxs, graph->where, part);
10446 
10447  GKfree((void **) &graph->nvwgt, (void **) &graph->npwgts,
10448  (void **) &graph->gdata, (void **) &graph->rdata, LTERM);
10449 
10450  return graph->mincut;
10451 
10452 }
10453 
10454 /*
10455  * mkwayfmh.c
10456  *
10457  * This file contains code that implements the multilevel k-way refinement
10458  *
10459  * Started 7/28/97
10460  * George
10461  *
10462  * $Id$
10463  *
10464  */
10465 
10466 
10467 
10468 
10469 
10470 /*************************************************************************
10471 * This function performs k-way refinement
10472 **************************************************************************/
10474  float *orgubvec, int npasses)
10475 {
10476  int i, ii, iii, j, k, pass, nvtxs, ncon, nmoves, nbnd, myndegrees, same;
10477  int from, me, to, oldcut, gain;
10478  idxtype *xadj, *adjncy, *adjwgt;
10479  idxtype *where, *perm, *bndptr, *bndind;
10480  EDegreeType *myedegrees;
10481  RInfoType *myrinfo;
10482  float *npwgts, *nvwgt, *minwgt, *maxwgt, maxlb, minlb, ubvec[MAXNCON], tvec[MAXNCON];
10483 
10484  nvtxs = graph->nvtxs;
10485  ncon = graph->ncon;
10486  xadj = graph->xadj;
10487  adjncy = graph->adjncy;
10488  adjwgt = graph->adjwgt;
10489 
10490  bndptr = graph->bndptr;
10491  bndind = graph->bndind;
10492 
10493  where = graph->where;
10494  npwgts = graph->npwgts;
10495 
10496  /* Setup the weight intervals of the various subdomains */
10497  minwgt = fwspacemalloc(ctrl, nparts*ncon);
10498  maxwgt = fwspacemalloc(ctrl, nparts*ncon);
10499 
10500  /* See if the orgubvec consists of identical constraints */
10501  maxlb = minlb = orgubvec[0];
10502  for (i=1; i<ncon; i++) {
10503  minlb = (orgubvec[i] < minlb ? orgubvec[i] : minlb);
10504  maxlb = (orgubvec[i] > maxlb ? orgubvec[i] : maxlb);
10505  }
10506  same = (fabs(maxlb-minlb) < .01 ? 1 : 0);
10507 
10508 
10509  /* Let's not get very optimistic. Let Balancing do the work */
10510  ComputeHKWayLoadImbalance(ncon, nparts, npwgts, ubvec);
10511  for (i=0; i<ncon; i++)
10512  ubvec[i] = amax(ubvec[i], orgubvec[i]);
10513 
10514  if (!same) {
10515  for (i=0; i<nparts; i++) {
10516  for (j=0; j<ncon; j++) {
10517  maxwgt[i*ncon+j] = ubvec[j]/nparts;
10518  minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts);
10519  }
10520  }
10521  }
10522  else {
10523  maxlb = ubvec[0];
10524  for (i=1; i<ncon; i++)
10525  maxlb = (ubvec[i] > maxlb ? ubvec[i] : maxlb);
10526 
10527  for (i=0; i<nparts; i++) {
10528  for (j=0; j<ncon; j++) {
10529  maxwgt[i*ncon+j] = maxlb/nparts;
10530  minwgt[i*ncon+j] = 1.0/(maxlb*nparts);
10531  }
10532  }
10533  }
10534 
10535 
10536  perm = idxwspacemalloc(ctrl, nvtxs);
10537 
10538  if (ctrl->dbglvl&DBG_REFINE) {
10539  printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ",
10540  npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
10541  graph->nvtxs, graph->nbnd, graph->mincut);
10542  ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
10543  for (i=0; i<ncon; i++)
10544  printf("%.3f ", tvec[i]);
10545  printf("\n");
10546  }
10547 
10548  for (pass=0; pass<npasses; pass++) {
10549  ASSERT(ComputeCut(graph, where) == graph->mincut);
10550 
10551  oldcut = graph->mincut;
10552  nbnd = graph->nbnd;
10553 
10554  RandomPermute(nbnd, perm, 1);
10555  for (nmoves=iii=0; iii<graph->nbnd; iii++) {
10556  ii = perm[iii];
10557  if (ii >= nbnd)
10558  continue;
10559  i = bndind[ii];
10560 
10561  myrinfo = graph->rinfo+i;
10562 
10563  if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */
10564  from = where[i];
10565  nvwgt = graph->nvwgt+i*ncon;
10566 
10567  if (myrinfo->id > 0 && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon))
10568  continue; /* This cannot be moved! */
10569 
10570  myedegrees = myrinfo->edegrees;
10571  myndegrees = myrinfo->ndegrees;
10572 
10573  for (k=0; k<myndegrees; k++) {
10574  to = myedegrees[k].pid;
10575  gain = myedegrees[k].ed - myrinfo->id;
10576  if (gain >= 0 &&
10577  (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) ||
10578  IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec)))
10579  break;
10580  }
10581  if (k == myndegrees)
10582  continue; /* break out if you did not find a candidate */
10583 
10584  for (j=k+1; j<myndegrees; j++) {
10585  to = myedegrees[j].pid;
10586  if ((myedegrees[j].ed > myedegrees[k].ed &&
10587  (AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon) ||
10588  IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))) ||
10589  (myedegrees[j].ed == myedegrees[k].ed &&
10590  IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec)))
10591  k = j;
10592  }
10593 
10594  to = myedegrees[k].pid;
10595 
10596  if (myedegrees[k].ed-myrinfo->id == 0
10597  && !IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec)
10598  && AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, npwgts+from*ncon, maxwgt+from*ncon))
10599  continue;
10600 
10601  /*=====================================================================
10602  * If we got here, we can now move the vertex from 'from' to 'to'
10603  *======================================================================*/
10604  graph->mincut -= myedegrees[k].ed-myrinfo->id;
10605 
10606  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
10607 
10608  /* Update where, weight, and ID/ED information of the vertex you moved */
10609  saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1);
10610  saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1);
10611  where[i] = to;
10612  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
10613  SWAP(myrinfo->id, myedegrees[k].ed, j);
10614  if (myedegrees[k].ed == 0)
10615  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
10616  else
10617  myedegrees[k].pid = from;
10618 
10619  if (myrinfo->ed-myrinfo->id < 0)
10620  BNDDelete(nbnd, bndind, bndptr, i);
10621 
10622  /* Update the degrees of adjacent vertices */
10623  for (j=xadj[i]; j<xadj[i+1]; j++) {
10624  ii = adjncy[j];
10625  me = where[ii];
10626 
10627  myrinfo = graph->rinfo+ii;
10628  if (myrinfo->edegrees == NULL) {
10629  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
10630  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
10631  }
10632  myedegrees = myrinfo->edegrees;
10633 
10634  ASSERT(CheckRInfo(myrinfo));
10635 
10636  if (me == from) {
10637  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
10638 
10639  if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
10640  BNDInsert(nbnd, bndind, bndptr, ii);
10641  }
10642  else if (me == to) {
10643  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
10644 
10645  if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
10646  BNDDelete(nbnd, bndind, bndptr, ii);
10647  }
10648 
10649  /* Remove contribution from the .ed of 'from' */
10650  if (me != from) {
10651  for (k=0; k<myrinfo->ndegrees; k++) {
10652  if (myedegrees[k].pid == from) {
10653  if (myedegrees[k].ed == adjwgt[j])
10654  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
10655  else
10656  myedegrees[k].ed -= adjwgt[j];
10657  break;
10658  }
10659  }
10660  }
10661 
10662  /* Add contribution to the .ed of 'to' */
10663  if (me != to) {
10664  for (k=0; k<myrinfo->ndegrees; k++) {
10665  if (myedegrees[k].pid == to) {
10666  myedegrees[k].ed += adjwgt[j];
10667  break;
10668  }
10669  }
10670  if (k == myrinfo->ndegrees) {
10671  myedegrees[myrinfo->ndegrees].pid = to;
10672  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
10673  }
10674  }
10675 
10676  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
10677  ASSERT(CheckRInfo(myrinfo));
10678 
10679  }
10680  nmoves++;
10681  }
10682  }
10683 
10684  graph->nbnd = nbnd;
10685 
10686  if (ctrl->dbglvl&DBG_REFINE) {
10687  printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ",
10688  npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
10689  nbnd, nmoves, graph->mincut);
10690  ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
10691  for (i=0; i<ncon; i++)
10692  printf("%.3f ", tvec[i]);
10693  printf("\n");
10694  }
10695 
10696  if (graph->mincut == oldcut)
10697  break;
10698  }
10699 
10700  fwspacefree(ctrl, ncon*nparts);
10701  fwspacefree(ctrl, ncon*nparts);
10702  idxwspacefree(ctrl, nvtxs);
10703 }
10704 
10705 
10706 
10707 /*************************************************************************
10708 * This function performs k-way refinement
10709 **************************************************************************/
10711  float *ubvec, int npasses)
10712 {
10713  int i, ii, j, k, pass, nvtxs, ncon, nbnd, myndegrees, oldgain, gain, nmoves;
10714  int from, me, to, oldcut;
10715  idxtype *xadj, *adjncy, *adjwgt;
10716  idxtype *where, *perm, *bndptr, *bndind, *moved;
10717  EDegreeType *myedegrees;
10718  RInfoType *myrinfo;
10719  PQueueType queue;
10720  float *npwgts, *nvwgt, *minwgt, *maxwgt, tvec[MAXNCON];
10721 
10722  nvtxs = graph->nvtxs;
10723  ncon = graph->ncon;
10724  xadj = graph->xadj;
10725  adjncy = graph->adjncy;
10726  adjwgt = graph->adjwgt;
10727 
10728  bndind = graph->bndind;
10729  bndptr = graph->bndptr;
10730 
10731  where = graph->where;
10732  npwgts = graph->npwgts;
10733 
10734  /* Setup the weight intervals of the various subdomains */
10735  minwgt = fwspacemalloc(ctrl, ncon*nparts);
10736  maxwgt = fwspacemalloc(ctrl, ncon*nparts);
10737 
10738  for (i=0; i<nparts; i++) {
10739  for (j=0; j<ncon; j++) {
10740  maxwgt[i*ncon+j] = ubvec[j]/nparts;
10741  minwgt[i*ncon+j] = 1.0/(ubvec[j]*nparts);
10742  }
10743  }
10744 
10745  perm = idxwspacemalloc(ctrl, nvtxs);
10746  moved = idxwspacemalloc(ctrl, nvtxs);
10747 
10748  PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
10749 
10750  if (ctrl->dbglvl&DBG_REFINE) {
10751  printf("Partitions: [%5.4f %5.4f], Nv-Nb[%6d %6d]. Cut: %6d, LB: ",
10752  npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
10753  graph->nvtxs, graph->nbnd, graph->mincut);
10754  ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
10755  for (i=0; i<ncon; i++)
10756  printf("%.3f ", tvec[i]);
10757  printf("[B]\n");
10758  }
10759 
10760 
10761  for (pass=0; pass<npasses; pass++) {
10762  ASSERT(ComputeCut(graph, where) == graph->mincut);
10763 
10764  /* Check to see if things are out of balance, given the tolerance */
10765  if (MocIsHBalanced(ncon, nparts, npwgts, ubvec))
10766  break;
10767 
10768  PQueueReset(&queue);
10769  idxset(nvtxs, -1, moved);
10770 
10771  oldcut = graph->mincut;
10772  nbnd = graph->nbnd;
10773 
10774  RandomPermute(nbnd, perm, 1);
10775  for (ii=0; ii<nbnd; ii++) {
10776  i = bndind[perm[ii]];
10777  PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
10778  moved[i] = 2;
10779  }
10780 
10781  nmoves = 0;
10782  for (;;) {
10783  if ((i = PQueueGetMax(&queue)) == -1)
10784  break;
10785  moved[i] = 1;
10786 
10787  myrinfo = graph->rinfo+i;
10788  from = where[i];
10789  nvwgt = graph->nvwgt+i*ncon;
10790 
10791  if (AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, -1.0, nvwgt, minwgt+from*ncon))
10792  continue; /* This cannot be moved! */
10793 
10794  myedegrees = myrinfo->edegrees;
10795  myndegrees = myrinfo->ndegrees;
10796 
10797  for (k=0; k<myndegrees; k++) {
10798  to = myedegrees[k].pid;
10799  if (IsHBalanceBetterFT(ncon, nparts, npwgts+from*ncon, npwgts+to*ncon, nvwgt, ubvec))
10800  break;
10801  }
10802  if (k == myndegrees)
10803  continue; /* break out if you did not find a candidate */
10804 
10805  for (j=k+1; j<myndegrees; j++) {
10806  to = myedegrees[j].pid;
10807  if (IsHBalanceBetterTT(ncon, nparts, npwgts+myedegrees[k].pid*ncon, npwgts+to*ncon, nvwgt, ubvec))
10808  k = j;
10809  }
10810 
10811  to = myedegrees[k].pid;
10812 
10813  j = 0;
10814  if (!AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon))
10815  j++;
10816  if (myedegrees[k].ed-myrinfo->id >= 0)
10817  j++;
10818  if (!AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) &&
10819  AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon))
10820  j++;
10821  if (j == 0)
10822  continue;
10823 
10824 /* DELETE
10825  if (myedegrees[k].ed-myrinfo->id < 0 &&
10826  AreAllHVwgtsBelow(ncon, 1.0, npwgts+from*ncon, 0.0, nvwgt, maxwgt+from*ncon) &&
10827  AreAllHVwgtsAbove(ncon, 1.0, npwgts+to*ncon, 0.0, nvwgt, minwgt+to*ncon) &&
10828  AreAllHVwgtsBelow(ncon, 1.0, npwgts+to*ncon, 1.0, nvwgt, maxwgt+to*ncon))
10829  continue;
10830 */
10831  /*=====================================================================
10832  * If we got here, we can now move the vertex from 'from' to 'to'
10833  *======================================================================*/
10834  graph->mincut -= myedegrees[k].ed-myrinfo->id;
10835 
10836  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
10837 
10838  /* Update where, weight, and ID/ED information of the vertex you moved */
10839  saxpy(ncon, 1.0, nvwgt, 1, npwgts+to*ncon, 1);
10840  saxpy(ncon, -1.0, nvwgt, 1, npwgts+from*ncon, 1);
10841  where[i] = to;
10842  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
10843  SWAP(myrinfo->id, myedegrees[k].ed, j);
10844  if (myedegrees[k].ed == 0)
10845  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
10846  else
10847  myedegrees[k].pid = from;
10848 
10849  if (myrinfo->ed == 0)
10850  BNDDelete(nbnd, bndind, bndptr, i);
10851 
10852  /* Update the degrees of adjacent vertices */
10853  for (j=xadj[i]; j<xadj[i+1]; j++) {
10854  ii = adjncy[j];
10855  me = where[ii];
10856 
10857  myrinfo = graph->rinfo+ii;
10858  if (myrinfo->edegrees == NULL) {
10859  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
10860  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
10861  }
10862  myedegrees = myrinfo->edegrees;
10863 
10864  ASSERT(CheckRInfo(myrinfo));
10865 
10866  oldgain = (myrinfo->ed-myrinfo->id);
10867 
10868  if (me == from) {
10869  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
10870 
10871  if (myrinfo->ed > 0 && bndptr[ii] == -1)
10872  BNDInsert(nbnd, bndind, bndptr, ii);
10873  }
10874  else if (me == to) {
10875  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
10876 
10877  if (myrinfo->ed == 0 && bndptr[ii] != -1)
10878  BNDDelete(nbnd, bndind, bndptr, ii);
10879  }
10880 
10881  /* Remove contribution from the .ed of 'from' */
10882  if (me != from) {
10883  for (k=0; k<myrinfo->ndegrees; k++) {
10884  if (myedegrees[k].pid == from) {
10885  if (myedegrees[k].ed == adjwgt[j])
10886  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
10887  else
10888  myedegrees[k].ed -= adjwgt[j];
10889  break;
10890  }
10891  }
10892  }
10893 
10894  /* Add contribution to the .ed of 'to' */
10895  if (me != to) {
10896  for (k=0; k<myrinfo->ndegrees; k++) {
10897  if (myedegrees[k].pid == to) {
10898  myedegrees[k].ed += adjwgt[j];
10899  break;
10900  }
10901  }
10902  if (k == myrinfo->ndegrees) {
10903  myedegrees[myrinfo->ndegrees].pid = to;
10904  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
10905  }
10906  }
10907 
10908 
10909  /* Update the queue */
10910  if (me == to || me == from) {
10911  gain = myrinfo->ed-myrinfo->id;
10912  if (moved[ii] == 2) {
10913  if (myrinfo->ed > 0)
10914  PQueueUpdate(&queue, ii, oldgain, gain);
10915  else {
10916  PQueueDelete(&queue, ii, oldgain);
10917  moved[ii] = -1;
10918  }
10919  }
10920  else if (moved[ii] == -1 && myrinfo->ed > 0) {
10921  PQueueInsert(&queue, ii, gain);
10922  moved[ii] = 2;
10923  }
10924  }
10925 
10926  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
10927  ASSERT(CheckRInfo(myrinfo));
10928  }
10929  nmoves++;
10930  }
10931 
10932  graph->nbnd = nbnd;
10933 
10934  if (ctrl->dbglvl&DBG_REFINE) {
10935  printf("\t [%5.4f %5.4f], Nb: %6d, Nmoves: %5d, Cut: %6d, LB: ",
10936  npwgts[samin(ncon*nparts, npwgts)], npwgts[samax(ncon*nparts, npwgts)],
10937  nbnd, nmoves, graph->mincut);
10938  ComputeHKWayLoadImbalance(ncon, nparts, npwgts, tvec);
10939  for (i=0; i<ncon; i++)
10940  printf("%.3f ", tvec[i]);
10941  printf("\n");
10942  }
10943 
10944  if (nmoves == 0)
10945  break;
10946  }
10947 
10948  PQueueFree(ctrl, &queue);
10949 
10950  fwspacefree(ctrl, ncon*nparts);
10951  fwspacefree(ctrl, ncon*nparts);
10952  idxwspacefree(ctrl, nvtxs);
10953  idxwspacefree(ctrl, nvtxs);
10954 
10955 }
10956 
10957 
10958 
10959 
10960 
10961 /*************************************************************************
10962 * This function checks if the vertex weights of two vertices are below
10963 * a given set of values
10964 **************************************************************************/
10965 int AreAllHVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit)
10966 {
10967  int i;
10968 
10969  for (i=0; i<ncon; i++)
10970  if (alpha*vwgt1[i] + beta*vwgt2[i] > limit[i])
10971  return 0;
10972 
10973  return 1;
10974 }
10975 
10976 
10977 
10978 /*************************************************************************
10979 * This function checks if the vertex weights of two vertices are above
10980 * a given set of values
10981 **************************************************************************/
10982 int AreAllHVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit)
10983 {
10984  int i;
10985 
10986  for (i=0; i<ncon; i++)
10987  if (alpha*vwgt1[i] + beta*vwgt2[i] < limit[i])
10988  return 0;
10989 
10990  return 1;
10991 }
10992 
10993 
10994 /*************************************************************************
10995 * This function computes the load imbalance over all the constrains
10996 * For now assume that we just want balanced partitionings
10997 **************************************************************************/
10998 void ComputeHKWayLoadImbalance(int ncon, int nparts, float *npwgts, float *lbvec)
10999 {
11000  int i, j;
11001  float max;
11002 
11003  for (i=0; i<ncon; i++) {
11004  max = 0.0;
11005  for (j=0; j<nparts; j++) {
11006  if (npwgts[j*ncon+i] > max)
11007  max = npwgts[j*ncon+i];
11008  }
11009 
11010  lbvec[i] = max*nparts;
11011  }
11012 }
11013 
11014 
11015 /*************************************************************************
11016 * This function determines if a partitioning is horizontally balanced
11017 **************************************************************************/
11018 int MocIsHBalanced(int ncon, int nparts, float *npwgts, float *ubvec)
11019 {
11020  int i, j;
11021  float max;
11022 
11023  for (i=0; i<ncon; i++) {
11024  max = 0.0;
11025  for (j=0; j<nparts; j++) {
11026  if (npwgts[j*ncon+i] > max)
11027  max = npwgts[j*ncon+i];
11028  }
11029 
11030  if (ubvec[i] < max*nparts)
11031  return 0;
11032  }
11033 
11034  return 1;
11035 }
11036 
11037 
11038 
11039 
11040 
11041 /*************************************************************************
11042 * This function checks if the pairwise balance of the between the two
11043 * partitions will improve by moving the vertex v from pfrom to pto,
11044 * subject to the target partition weights of tfrom, and tto respectively
11045 **************************************************************************/
11046 int IsHBalanceBetterFT(int ncon, int nparts, float *pfrom, float *pto, float *vwgt, float *ubvec)
11047 {
11048  int i;
11049  float blb1=0.0, alb1=0.0, sblb=0.0, salb=0.0;
11050  float blb2=0.0, alb2=0.0;
11051  float temp;
11052 
11053  for (i=0; i<ncon; i++) {
11054  temp = amax(pfrom[i], pto[i])*nparts/ubvec[i];
11055  if (blb1 < temp) {
11056  blb2 = blb1;
11057  blb1 = temp;
11058  }
11059  else if (blb2 < temp)
11060  blb2 = temp;
11061  sblb += temp;
11062 
11063  temp = amax(pfrom[i]-vwgt[i], pto[i]+vwgt[i])*nparts/ubvec[i];
11064  if (alb1 < temp) {
11065  alb2 = alb1;
11066  alb1 = temp;
11067  }
11068  else if (alb2 < temp)
11069  alb2 = temp;
11070  salb += temp;
11071  }
11072 
11073  if (alb1 < blb1)
11074  return 1;
11075  if (blb1 < alb1)
11076  return 0;
11077  if (alb2 < blb2)
11078  return 1;
11079  if (blb2 < alb2)
11080  return 0;
11081 
11082  return salb < sblb;
11083 
11084 }
11085 
11086 
11087 
11088 
11089 /*************************************************************************
11090 * This function checks if it will be better to move a vertex to pt2 than
11091 * to pt1 subject to their target weights of tt1 and tt2, respectively
11092 * This routine takes into account the weight of the vertex in question
11093 **************************************************************************/
11094 int IsHBalanceBetterTT(int ncon, int nparts, float *pt1, float *pt2, float *vwgt, float *ubvec)
11095 {
11096  int i;
11097  float m11=0.0, m12=0.0, m21=0.0, m22=0.0, sm1=0.0, sm2=0.0, temp;
11098 
11099  for (i=0; i<ncon; i++) {
11100  temp = (pt1[i]+vwgt[i])*nparts/ubvec[i];
11101  if (m11 < temp) {
11102  m12 = m11;
11103  m11 = temp;
11104  }
11105  else if (m12 < temp)
11106  m12 = temp;
11107  sm1 += temp;
11108 
11109  temp = (pt2[i]+vwgt[i])*nparts/ubvec[i];
11110  if (m21 < temp) {
11111  m22 = m21;
11112  m21 = temp;
11113  }
11114  else if (m22 < temp)
11115  m22 = temp;
11116  sm2 += temp;
11117  }
11118 
11119  if (m21 < m11)
11120  return 1;
11121  if (m21 > m11)
11122  return 0;
11123  if (m22 < m12)
11124  return 1;
11125  if (m22 > m12)
11126  return 0;
11127 
11128  return sm2 < sm1;
11129 }
11130 
11131 /*
11132  * Copyright 1997, Regents of the University of Minnesota
11133  *
11134  * mkwayrefine.c
11135  *
11136  * This file contains the driving routines for multilevel k-way refinement
11137  *
11138  * Started 7/28/97
11139  * George
11140  *
11141  * $Id$
11142  */
11143 
11144 
11145 
11146 
11147 /*************************************************************************
11148 * This function is the entry point of refinement
11149 **************************************************************************/
11150 void MocRefineKWayHorizontal(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts,
11151  float *ubvec)
11152 {
11153 
11154  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
11155 
11156  /* Compute the parameters of the coarsest graph */
11157  MocComputeKWayPartitionParams(ctrl, graph, nparts);
11158 
11159  for (;;) {
11160  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
11161 
11162  if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) {
11163  MocComputeKWayBalanceBoundary(ctrl, graph, nparts);
11164  MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4);
11165  ComputeKWayBoundary(ctrl, graph, nparts);
11166  }
11167 
11168  MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10);
11169 
11170  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
11171 
11172  if (graph == orggraph)
11173  break;
11174 
11175  graph = graph->finer;
11176  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
11177  MocProjectKWayPartition(ctrl, graph, nparts);
11178  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
11179  }
11180 
11181  if (!MocIsHBalanced(graph->ncon, nparts, graph->npwgts, ubvec)) {
11182  MocComputeKWayBalanceBoundary(ctrl, graph, nparts);
11183  MCGreedy_KWayEdgeBalanceHorizontal(ctrl, graph, nparts, ubvec, 4);
11184  ComputeKWayBoundary(ctrl, graph, nparts);
11185  MCRandom_KWayEdgeRefineHorizontal(ctrl, graph, nparts, ubvec, 10);
11186  }
11187 
11188  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
11189 }
11190 
11191 
11192 
11193 
11194 /*************************************************************************
11195 * This function allocates memory for k-way edge refinement
11196 **************************************************************************/
11197 void MocAllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
11198 {
11199  int nvtxs, ncon, pad64;
11200 
11201  nvtxs = graph->nvtxs;
11202  ncon = graph->ncon;
11203 
11204  pad64 = (3*nvtxs)%2;
11205 
11206  graph->rdata = idxmalloc(3*nvtxs+(sizeof(RInfoType)/sizeof(idxtype))*nvtxs+pad64, "AllocateKWayPartitionMemory: rdata");
11207  graph->where = graph->rdata;
11208  graph->bndptr = graph->rdata + nvtxs;
11209  graph->bndind = graph->rdata + 2*nvtxs;
11210  graph->rinfo = (RInfoType *)(graph->rdata + 3*nvtxs + pad64);
11211 
11212  graph->npwgts = fmalloc(ncon*nparts, "MocAllocateKWayPartitionMemory: npwgts");
11213 }
11214 
11215 
11216 /*************************************************************************
11217 * This function computes the initial id/ed
11218 **************************************************************************/
11219 void MocComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
11220 {
11221  int i, j, k, nvtxs, ncon, nbnd, mincut, me, other;
11222  idxtype *xadj, *adjncy, *adjwgt, *where, *bndind, *bndptr;
11223  RInfoType *rinfo, *myrinfo;
11224  EDegreeType *myedegrees;
11225  float *nvwgt, *npwgts;
11226 
11227  nvtxs = graph->nvtxs;
11228  ncon = graph->ncon;
11229  xadj = graph->xadj;
11230  nvwgt = graph->nvwgt;
11231  adjncy = graph->adjncy;
11232  adjwgt = graph->adjwgt;
11233 
11234  where = graph->where;
11235  npwgts = sset(ncon*nparts, 0.0, graph->npwgts);
11236  bndind = graph->bndind;
11237  bndptr = idxset(nvtxs, -1, graph->bndptr);
11238  rinfo = graph->rinfo;
11239 
11240 
11241  /*------------------------------------------------------------
11242  / Compute now the id/ed degrees
11243  /------------------------------------------------------------*/
11244  ctrl->wspace.cdegree = 0;
11245  nbnd = mincut = 0;
11246  for (i=0; i<nvtxs; i++) {
11247  me = where[i];
11248  saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1);
11249 
11250  myrinfo = rinfo+i;
11251  myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
11252  myrinfo->edegrees = NULL;
11253 
11254  for (j=xadj[i]; j<xadj[i+1]; j++) {
11255  if (me != where[adjncy[j]])
11256  myrinfo->ed += adjwgt[j];
11257  }
11258  myrinfo->id = graph->adjwgtsum[i] - myrinfo->ed;
11259 
11260  if (myrinfo->ed > 0)
11261  mincut += myrinfo->ed;
11262 
11263  if (myrinfo->ed-myrinfo->id >= 0)
11264  BNDInsert(nbnd, bndind, bndptr, i);
11265 
11266  /* Time to compute the particular external degrees */
11267  if (myrinfo->ed > 0) {
11268  myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
11269  ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
11270 
11271  for (j=xadj[i]; j<xadj[i+1]; j++) {
11272  other = where[adjncy[j]];
11273  if (me != other) {
11274  for (k=0; k<myrinfo->ndegrees; k++) {
11275  if (myedegrees[k].pid == other) {
11276  myedegrees[k].ed += adjwgt[j];
11277  break;
11278  }
11279  }
11280  if (k == myrinfo->ndegrees) {
11281  myedegrees[myrinfo->ndegrees].pid = other;
11282  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
11283  }
11284  }
11285  }
11286 
11287  ASSERT(myrinfo->ndegrees <= xadj[i+1]-xadj[i]);
11288  }
11289  }
11290 
11291  graph->mincut = mincut/2;
11292  graph->nbnd = nbnd;
11293 
11294 }
11295 
11296 
11297 
11298 /*************************************************************************
11299 * This function projects a partition, and at the same time computes the
11300 * parameters for refinement.
11301 **************************************************************************/
11302 void MocProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
11303 {
11304  int i, j, k, nvtxs, nbnd, me, other, istart, iend, ndegrees;
11305  idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
11306  idxtype *cmap, *where, *bndptr, *bndind;
11307  idxtype *cwhere;
11308  GraphType *cgraph;
11309  RInfoType *crinfo, *rinfo, *myrinfo;
11310  EDegreeType *myedegrees;
11311  idxtype *htable;
11312 
11313  cgraph = graph->coarser;
11314  cwhere = cgraph->where;
11315  crinfo = cgraph->rinfo;
11316 
11317  nvtxs = graph->nvtxs;
11318  cmap = graph->cmap;
11319  xadj = graph->xadj;
11320  adjncy = graph->adjncy;
11321  adjwgt = graph->adjwgt;
11322  adjwgtsum = graph->adjwgtsum;
11323 
11324  MocAllocateKWayPartitionMemory(ctrl, graph, nparts);
11325  where = graph->where;
11326  rinfo = graph->rinfo;
11327  bndind = graph->bndind;
11328  bndptr = idxset(nvtxs, -1, graph->bndptr);
11329 
11330  /* Go through and project partition and compute id/ed for the nodes */
11331  for (i=0; i<nvtxs; i++) {
11332  k = cmap[i];
11333  where[i] = cwhere[k];
11334  cmap[i] = crinfo[k].ed; /* For optimization */
11335  }
11336 
11337  htable = idxset(nparts, -1, idxwspacemalloc(ctrl, nparts));
11338 
11339  ctrl->wspace.cdegree = 0;
11340  for (nbnd=0, i=0; i<nvtxs; i++) {
11341  me = where[i];
11342 
11343  myrinfo = rinfo+i;
11344  myrinfo->id = myrinfo->ed = myrinfo->ndegrees = 0;
11345  myrinfo->edegrees = NULL;
11346 
11347  myrinfo->id = adjwgtsum[i];
11348 
11349  if (cmap[i] > 0) { /* If it is an interface node. Note cmap[i] = crinfo[cmap[i]].ed */
11350  istart = xadj[i];
11351  iend = xadj[i+1];
11352 
11353  myedegrees = myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
11354  ctrl->wspace.cdegree += iend-istart;
11355 
11356  ndegrees = 0;
11357  for (j=istart; j<iend; j++) {
11358  other = where[adjncy[j]];
11359  if (me != other) {
11360  myrinfo->ed += adjwgt[j];
11361  if ((k = htable[other]) == -1) {
11362  htable[other] = ndegrees;
11363  myedegrees[ndegrees].pid = other;
11364  myedegrees[ndegrees++].ed = adjwgt[j];
11365  }
11366  else {
11367  myedegrees[k].ed += adjwgt[j];
11368  }
11369  }
11370  }
11371  myrinfo->id -= myrinfo->ed;
11372 
11373  /* Remove space for edegrees if it was interior */
11374  if (myrinfo->ed == 0) {
11375  myrinfo->edegrees = NULL;
11376  ctrl->wspace.cdegree -= iend-istart;
11377  }
11378  else {
11379  if (myrinfo->ed-myrinfo->id >= 0)
11380  BNDInsert(nbnd, bndind, bndptr, i);
11381 
11382  myrinfo->ndegrees = ndegrees;
11383 
11384  for (j=0; j<ndegrees; j++)
11385  htable[myedegrees[j].pid] = -1;
11386  }
11387  }
11388  }
11389 
11390  scopy(graph->ncon*nparts, cgraph->npwgts, graph->npwgts);
11391  graph->mincut = cgraph->mincut;
11392  graph->nbnd = nbnd;
11393 
11394  FreeGraph(graph->coarser);
11395  graph->coarser = NULL;
11396 
11397  idxwspacefree(ctrl, nparts);
11398 
11399  ASSERT(CheckBnd2(graph));
11400 
11401 }
11402 
11403 
11404 
11405 /*************************************************************************
11406 * This function computes the boundary definition for balancing
11407 **************************************************************************/
11408 void MocComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
11409 {
11410  int i, nvtxs, nbnd;
11411  idxtype *bndind, *bndptr;
11412 
11413  nvtxs = graph->nvtxs;
11414  bndind = graph->bndind;
11415  bndptr = idxset(nvtxs, -1, graph->bndptr);
11416 
11417 
11418  /* Compute the new boundary */
11419  nbnd = 0;
11420  for (i=0; i<nvtxs; i++) {
11421  if (graph->rinfo[i].ed > 0)
11422  BNDInsert(nbnd, bndind, bndptr, i);
11423  }
11424 
11425  graph->nbnd = nbnd;
11426 }
11427 
11428 /*
11429  * Copyright 1997, Regents of the University of Minnesota
11430  *
11431  * mmatch.c
11432  *
11433  * This file contains the code that computes matchings and creates the next
11434  * level coarse graph.
11435  *
11436  * Started 7/23/97
11437  * George
11438  *
11439  * $Id$
11440  *
11441  */
11442 
11443 
11444 
11445 
11446 /*************************************************************************
11447 * This function finds a matching using the HEM heuristic
11448 **************************************************************************/
11449 void MCMatch_RM(CtrlType *ctrl, GraphType *graph)
11450 {
11451  int i, ii, j, k, nvtxs, ncon, cnvtxs, maxidx;
11452  idxtype *xadj, *adjncy, *adjwgt;
11453  idxtype *match, *cmap, *perm;
11454  float *nvwgt;
11455 
11456  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
11457 
11458  nvtxs = graph->nvtxs;
11459  ncon = graph->ncon;
11460  xadj = graph->xadj;
11461  nvwgt = graph->nvwgt;
11462  adjncy = graph->adjncy;
11463  adjwgt = graph->adjwgt;
11464 
11465  cmap = graph->cmap;
11466  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
11467 
11468  perm = idxwspacemalloc(ctrl, nvtxs);
11469  RandomPermute(nvtxs, perm, 1);
11470 
11471  cnvtxs = 0;
11472  for (ii=0; ii<nvtxs; ii++) {
11473  i = perm[ii];
11474 
11475  if (match[i] == UNMATCHED) { /* Unmatched */
11476  maxidx = i;
11477 
11478  /* Find a random matching, subject to maxvwgt constraints */
11479  for (j=xadj[i]; j<xadj[i+1]; j++) {
11480  k = adjncy[j];
11481  if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
11482  maxidx = k;
11483  break;
11484  }
11485  }
11486 
11487  cmap[i] = cmap[maxidx] = cnvtxs++;
11488  match[i] = maxidx;
11489  match[maxidx] = i;
11490  }
11491  }
11492 
11493  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
11494 
11495  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
11496 
11497  idxwspacefree(ctrl, nvtxs);
11498  idxwspacefree(ctrl, nvtxs);
11499 }
11500 
11501 
11502 
11503 /*************************************************************************
11504 * This function finds a matching using the HEM heuristic
11505 **************************************************************************/
11506 void MCMatch_HEM(CtrlType *ctrl, GraphType *graph)
11507 {
11508  int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt;
11509  idxtype *xadj, *adjncy, *adjwgt;
11510  idxtype *match, *cmap, *perm;
11511  float *nvwgt;
11512 
11513  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
11514 
11515  nvtxs = graph->nvtxs;
11516  ncon = graph->ncon;
11517  xadj = graph->xadj;
11518  nvwgt = graph->nvwgt;
11519  adjncy = graph->adjncy;
11520  adjwgt = graph->adjwgt;
11521 
11522  cmap = graph->cmap;
11523  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
11524 
11525  perm = idxwspacemalloc(ctrl, nvtxs);
11526  RandomPermute(nvtxs, perm, 1);
11527 
11528  cnvtxs = 0;
11529  for (ii=0; ii<nvtxs; ii++) {
11530  i = perm[ii];
11531 
11532  if (match[i] == UNMATCHED) { /* Unmatched */
11533  maxidx = i;
11534  maxwgt = 0;
11535 
11536  /* Find a heavy-edge matching, subject to maxvwgt constraints */
11537  for (j=xadj[i]; j<xadj[i+1]; j++) {
11538  k = adjncy[j];
11539  if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] &&
11540  AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
11541  maxwgt = adjwgt[j];
11542  maxidx = adjncy[j];
11543  }
11544  }
11545 
11546  cmap[i] = cmap[maxidx] = cnvtxs++;
11547  match[i] = maxidx;
11548  match[maxidx] = i;
11549  }
11550  }
11551 
11552  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
11553 
11554  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
11555 
11556  idxwspacefree(ctrl, nvtxs);
11557  idxwspacefree(ctrl, nvtxs);
11558 }
11559 
11560 
11561 
11562 /*************************************************************************
11563 * This function finds a matching using the HEM heuristic
11564 **************************************************************************/
11565 void MCMatch_SHEM(CtrlType *ctrl, GraphType *graph)
11566 {
11567  int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree;
11568  idxtype *xadj, *adjncy, *adjwgt;
11569  idxtype *match, *cmap, *degrees, *perm, *tperm;
11570  float *nvwgt;
11571 
11572  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
11573 
11574  nvtxs = graph->nvtxs;
11575  ncon = graph->ncon;
11576  xadj = graph->xadj;
11577  nvwgt = graph->nvwgt;
11578  adjncy = graph->adjncy;
11579  adjwgt = graph->adjwgt;
11580 
11581  cmap = graph->cmap;
11582  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
11583 
11584  perm = idxwspacemalloc(ctrl, nvtxs);
11585  tperm = idxwspacemalloc(ctrl, nvtxs);
11586  degrees = idxwspacemalloc(ctrl, nvtxs);
11587 
11588  RandomPermute(nvtxs, tperm, 1);
11589  avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
11590  for (i=0; i<nvtxs; i++)
11591  degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
11592  BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
11593 
11594  cnvtxs = 0;
11595 
11596  /* Take care any islands. Islands are matched with non-islands due to coarsening */
11597  for (ii=0; ii<nvtxs; ii++) {
11598  i = perm[ii];
11599 
11600  if (match[i] == UNMATCHED) { /* Unmatched */
11601  if (xadj[i] < xadj[i+1])
11602  break;
11603 
11604  maxidx = i;
11605  for (j=nvtxs-1; j>ii; j--) {
11606  k = perm[j];
11607  if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
11608  maxidx = k;
11609  break;
11610  }
11611  }
11612 
11613  cmap[i] = cmap[maxidx] = cnvtxs++;
11614  match[i] = maxidx;
11615  match[maxidx] = i;
11616  }
11617  }
11618 
11619  /* Continue with normal matching */
11620  for (; ii<nvtxs; ii++) {
11621  i = perm[ii];
11622 
11623  if (match[i] == UNMATCHED) { /* Unmatched */
11624  maxidx = i;
11625  maxwgt = 0;
11626 
11627  /* Find a heavy-edge matching, subject to maxvwgt constraints */
11628  for (j=xadj[i]; j<xadj[i+1]; j++) {
11629  k = adjncy[j];
11630  if (match[k] == UNMATCHED && maxwgt <= adjwgt[j] &&
11631  AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
11632  maxwgt = adjwgt[j];
11633  maxidx = adjncy[j];
11634  }
11635  }
11636 
11637  cmap[i] = cmap[maxidx] = cnvtxs++;
11638  match[i] = maxidx;
11639  match[maxidx] = i;
11640  }
11641  }
11642 
11643  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
11644 
11645  idxwspacefree(ctrl, nvtxs); /* degrees */
11646  idxwspacefree(ctrl, nvtxs); /* tperm */
11647 
11648  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
11649 
11650  idxwspacefree(ctrl, nvtxs);
11651  idxwspacefree(ctrl, nvtxs);
11652 }
11653 
11654 
11655 
11656 /*************************************************************************
11657 * This function finds a matching using the HEM heuristic
11658 **************************************************************************/
11659 void MCMatch_SHEBM(CtrlType *ctrl, GraphType *graph, int norm)
11660 {
11661  int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree;
11662  idxtype *xadj, *adjncy, *adjwgt;
11663  idxtype *match, *cmap, *degrees, *perm, *tperm;
11664  float *nvwgt;
11665 
11666  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
11667 
11668  nvtxs = graph->nvtxs;
11669  ncon = graph->ncon;
11670  xadj = graph->xadj;
11671  nvwgt = graph->nvwgt;
11672  adjncy = graph->adjncy;
11673  adjwgt = graph->adjwgt;
11674 
11675  cmap = graph->cmap;
11676  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
11677 
11678  perm = idxwspacemalloc(ctrl, nvtxs);
11679  tperm = idxwspacemalloc(ctrl, nvtxs);
11680  degrees = idxwspacemalloc(ctrl, nvtxs);
11681 
11682  RandomPermute(nvtxs, tperm, 1);
11683  avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
11684  for (i=0; i<nvtxs; i++)
11685  degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
11686  BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
11687 
11688  cnvtxs = 0;
11689 
11690  /* Take care any islands. Islands are matched with non-islands due to coarsening */
11691  for (ii=0; ii<nvtxs; ii++) {
11692  i = perm[ii];
11693 
11694  if (match[i] == UNMATCHED) { /* Unmatched */
11695  if (xadj[i] < xadj[i+1])
11696  break;
11697 
11698  maxidx = i;
11699  for (j=nvtxs-1; j>ii; j--) {
11700  k = perm[j];
11701  if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
11702  maxidx = k;
11703  break;
11704  }
11705  }
11706 
11707  cmap[i] = cmap[maxidx] = cnvtxs++;
11708  match[i] = maxidx;
11709  match[maxidx] = i;
11710  }
11711  }
11712 
11713  /* Continue with normal matching */
11714  for (; ii<nvtxs; ii++) {
11715  i = perm[ii];
11716 
11717  if (match[i] == UNMATCHED) { /* Unmatched */
11718  maxidx = i;
11719  maxwgt = -1;
11720 
11721  /* Find a heavy-edge matching, subject to maxvwgt constraints */
11722  for (j=xadj[i]; j<xadj[i+1]; j++) {
11723  k = adjncy[j];
11724 
11725  if (match[k] == UNMATCHED &&
11726  AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt) &&
11727  (maxwgt < adjwgt[j] ||
11728  (maxwgt == adjwgt[j] &&
11729  BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon) >= 0
11730  )
11731  )
11732  ) {
11733  maxwgt = adjwgt[j];
11734  maxidx = k;
11735  }
11736  }
11737 
11738  cmap[i] = cmap[maxidx] = cnvtxs++;
11739  match[i] = maxidx;
11740  match[maxidx] = i;
11741  }
11742  }
11743 
11744  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
11745 
11746  idxwspacefree(ctrl, nvtxs); /* degrees */
11747  idxwspacefree(ctrl, nvtxs); /* tperm */
11748 
11749  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
11750 
11751  idxwspacefree(ctrl, nvtxs);
11752  idxwspacefree(ctrl, nvtxs);
11753 }
11754 
11755 
11756 
11757 /*************************************************************************
11758 * This function finds a matching using the HEM heuristic
11759 **************************************************************************/
11760 void MCMatch_SBHEM(CtrlType *ctrl, GraphType *graph, int norm)
11761 {
11762  int i, ii, j, k, nvtxs, cnvtxs, ncon, maxidx, maxwgt, avgdegree;
11763  idxtype *xadj, *adjncy, *adjwgt;
11764  idxtype *match, *cmap, *degrees, *perm, *tperm;
11765  float *nvwgt, vbal;
11766 
11767  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->MatchTmr));
11768 
11769  nvtxs = graph->nvtxs;
11770  ncon = graph->ncon;
11771  xadj = graph->xadj;
11772  nvwgt = graph->nvwgt;
11773  adjncy = graph->adjncy;
11774  adjwgt = graph->adjwgt;
11775 
11776  cmap = graph->cmap;
11777  match = idxset(nvtxs, UNMATCHED, idxwspacemalloc(ctrl, nvtxs));
11778 
11779  perm = idxwspacemalloc(ctrl, nvtxs);
11780  tperm = idxwspacemalloc(ctrl, nvtxs);
11781  degrees = idxwspacemalloc(ctrl, nvtxs);
11782 
11783  RandomPermute(nvtxs, tperm, 1);
11784  avgdegree = 0.7*(xadj[nvtxs]/nvtxs);
11785  for (i=0; i<nvtxs; i++)
11786  degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]);
11787  BucketSortKeysInc(nvtxs, avgdegree, degrees, tperm, perm);
11788 
11789  cnvtxs = 0;
11790 
11791  /* Take care any islands. Islands are matched with non-islands due to coarsening */
11792  for (ii=0; ii<nvtxs; ii++) {
11793  i = perm[ii];
11794 
11795  if (match[i] == UNMATCHED) { /* Unmatched */
11796  if (xadj[i] < xadj[i+1])
11797  break;
11798 
11799  maxidx = i;
11800  for (j=nvtxs-1; j>ii; j--) {
11801  k = perm[j];
11802  if (match[k] == UNMATCHED && xadj[k] < xadj[k+1]) {
11803  maxidx = k;
11804  break;
11805  }
11806  }
11807 
11808  cmap[i] = cmap[maxidx] = cnvtxs++;
11809  match[i] = maxidx;
11810  match[maxidx] = i;
11811  }
11812  }
11813 
11814  /* Continue with normal matching */
11815  for (; ii<nvtxs; ii++) {
11816  i = perm[ii];
11817 
11818  if (match[i] == UNMATCHED) { /* Unmatched */
11819  maxidx = i;
11820  maxwgt = -1;
11821  vbal = 0.0;
11822 
11823  /* Find a heavy-edge matching, subject to maxvwgt constraints */
11824  for (j=xadj[i]; j<xadj[i+1]; j++) {
11825  k = adjncy[j];
11826  if (match[k] == UNMATCHED && AreAllVwgtsBelowFast(ncon, nvwgt+i*ncon, nvwgt+k*ncon, ctrl->nmaxvwgt)) {
11827  if (maxidx != i)
11828  vbal = BetterVBalance(ncon, norm, nvwgt+i*ncon, nvwgt+maxidx*ncon, nvwgt+k*ncon);
11829 
11830  if (vbal > 0 || (vbal > -.01 && maxwgt < adjwgt[j])) {
11831  maxwgt = adjwgt[j];
11832  maxidx = k;
11833  }
11834  }
11835  }
11836 
11837  cmap[i] = cmap[maxidx] = cnvtxs++;
11838  match[i] = maxidx;
11839  match[maxidx] = i;
11840  }
11841  }
11842 
11843  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->MatchTmr));
11844 
11845  idxwspacefree(ctrl, nvtxs); /* degrees */
11846  idxwspacefree(ctrl, nvtxs); /* tperm */
11847 
11848  CreateCoarseGraph(ctrl, graph, cnvtxs, match, perm);
11849 
11850  idxwspacefree(ctrl, nvtxs);
11851  idxwspacefree(ctrl, nvtxs);
11852 }
11853 
11854 
11855 
11856 
11857 
11858 /*************************************************************************
11859 * This function checks if v+u2 provides a better balance in the weight
11860 * vector that v+u1
11861 **************************************************************************/
11862 float BetterVBalance(int ncon, int norm, float *vwgt, float *u1wgt, float *u2wgt)
11863 {
11864  int i;
11865  float sum1, sum2, max1, max2, min1, min2, diff1, diff2;
11866 
11867  if (norm == -1) {
11868  max1 = min1 = vwgt[0]+u1wgt[0];
11869  max2 = min2 = vwgt[0]+u2wgt[0];
11870  sum1 = vwgt[0]+u1wgt[0];
11871  sum2 = vwgt[0]+u2wgt[0];
11872 
11873  for (i=1; i<ncon; i++) {
11874  if (max1 < vwgt[i]+u1wgt[i])
11875  max1 = vwgt[i]+u1wgt[i];
11876  if (min1 > vwgt[i]+u1wgt[i])
11877  min1 = vwgt[i]+u1wgt[i];
11878 
11879  if (max2 < vwgt[i]+u2wgt[i])
11880  max2 = vwgt[i]+u2wgt[i];
11881  if (min2 > vwgt[i]+u2wgt[i])
11882  min2 = vwgt[i]+u2wgt[i];
11883 
11884  sum1 += vwgt[i]+u1wgt[i];
11885  sum2 += vwgt[i]+u2wgt[i];
11886  }
11887 
11888  if (sum1 == 0.0)
11889  return 1;
11890  else if (sum2 == 0.0)
11891  return -1;
11892  else
11893  return ((max1-min1)/sum1) - ((max2-min2)/sum2);
11894  }
11895  else if (norm == 1) {
11896  sum1 = sum2 = 0.0;
11897  for (i=0; i<ncon; i++) {
11898  sum1 += vwgt[i]+u1wgt[i];
11899  sum2 += vwgt[i]+u2wgt[i];
11900  }
11901  sum1 = sum1/(1.0*ncon);
11902  sum2 = sum2/(1.0*ncon);
11903 
11904  diff1 = diff2 = 0.0;
11905  for (i=0; i<ncon; i++) {
11906  diff1 += fabs(sum1 - (vwgt[i]+u1wgt[i]));
11907  diff2 += fabs(sum2 - (vwgt[i]+u2wgt[i]));
11908  }
11909 
11910  return diff1 - diff2;
11911  }
11912  else {
11913  errexit("Unknown norm: %d\n", norm);
11914  }
11915  return 0.0;
11916 }
11917 
11918 
11919 /*************************************************************************
11920 * This function checks if the vertex weights of two vertices are below
11921 * a given set of values
11922 **************************************************************************/
11923 int AreAllVwgtsBelowFast(int ncon, float *vwgt1, float *vwgt2, float limit)
11924 {
11925  int i;
11926 
11927  for (i=0; i<ncon; i++)
11928  if (vwgt1[i] + vwgt2[i] > limit)
11929  return 0;
11930 
11931  return 1;
11932 }
11933 
11934 /*
11935  * mmd.c
11936  *
11937  * **************************************************************
11938  * The following C function was developed from a FORTRAN subroutine
11939  * in SPARSPAK written by Eleanor Chu, Alan George, Joseph Liu
11940  * and Esmond Ng.
11941  *
11942  * The FORTRAN-to-C transformation and modifications such as dynamic
11943  * memory allocation and deallocation were performed by Chunguang
11944  * Sun.
11945  * **************************************************************
11946  *
11947  * Taken from SMMS, George 12/13/94
11948  *
11949  * The meaning of invperm, and perm vectors is different from that
11950  * in genqmd_ of SparsPak
11951  *
11952  * $Id$
11953  */
11954 
11955 
11956 
11957 
11958 /*************************************************************************
11959 * genmmd -- multiple minimum external degree
11960 * purpose -- this routine implements the minimum degree
11961 * algorithm. it makes use of the implicit representation
11962 * of elimination graphs by quotient graphs, and the notion
11963 * of indistinguishable nodes. It also implements the modifications
11964 * by multiple elimination and minimum external degree.
11965 * Caution -- the adjacency vector adjncy will be destroyed.
11966 * Input parameters --
11967 * neqns -- number of equations.
11968 * (xadj, adjncy) -- the adjacency structure.
11969 * delta -- tolerance value for multiple elimination.
11970 * maxint -- maximum machine representable (short) integer
11971 * (any smaller estimate will do) for marking nodes.
11972 * Output parameters --
11973 * perm -- the minimum degree ordering.
11974 * invp -- the inverse of perm.
11975 * *ncsub -- an upper bound on the number of nonzero subscripts
11976 * for the compressed storage scheme.
11977 * Working parameters --
11978 * head -- vector for head of degree lists.
11979 * invp -- used temporarily for degree forward link.
11980 * perm -- used temporarily for degree backward link.
11981 * qsize -- vector for size of supernodes.
11982 * list -- vector for temporary linked lists.
11983 * marker -- a temporary marker vector.
11984 * Subroutines used -- mmdelm, mmdint, mmdnum, mmdupd.
11985 **************************************************************************/
11986 void genmmd(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *invp, idxtype *perm,
11987  int delta, idxtype *head, idxtype *qsize, idxtype *list, idxtype *marker,
11988  int maxint, int *ncsub)
11989 {
11990  int ehead, i, mdeg, mdlmt, mdeg_node, nextmd, num, tag;
11991 
11992  if (neqns <= 0)
11993  return;
11994 
11995  /* Adjust from C to Fortran */
11996  xadj--; adjncy--; invp--; perm--; head--; qsize--; list--; marker--;
11997 
11998  /* initialization for the minimum degree algorithm. */
11999  *ncsub = 0;
12000  mmdint(neqns, xadj, adjncy, head, invp, perm, qsize, list, marker);
12001 
12002  /* 'num' counts the number of ordered nodes plus 1. */
12003  num = 1;
12004 
12005  /* eliminate all isolated nodes. */
12006  nextmd = head[1];
12007  while (nextmd > 0) {
12008  mdeg_node = nextmd;
12009  nextmd = invp[mdeg_node];
12010  marker[mdeg_node] = maxint;
12011  invp[mdeg_node] = -num;
12012  num = num + 1;
12013  }
12014 
12015  /* search for node of the minimum degree. 'mdeg' is the current */
12016  /* minimum degree; 'tag' is used to facilitate marking nodes. */
12017  if (num > neqns)
12018  goto n1000;
12019  tag = 1;
12020  head[1] = 0;
12021  mdeg = 2;
12022 
12023  /* infinite loop here ! */
12024  while (1) {
12025  while (head[mdeg] <= 0)
12026  mdeg++;
12027 
12028  /* use value of 'delta' to set up 'mdlmt', which governs */
12029  /* when a degree update is to be performed. */
12030  mdlmt = mdeg + delta;
12031  ehead = 0;
12032 
12033 n500:
12034  mdeg_node = head[mdeg];
12035  while (mdeg_node <= 0) {
12036  mdeg++;
12037 
12038  if (mdeg > mdlmt)
12039  goto n900;
12040  mdeg_node = head[mdeg];
12041  };
12042 
12043  /* remove 'mdeg_node' from the degree structure. */
12044  nextmd = invp[mdeg_node];
12045  head[mdeg] = nextmd;
12046  if (nextmd > 0)
12047  perm[nextmd] = -mdeg;
12048  invp[mdeg_node] = -num;
12049  *ncsub += mdeg + qsize[mdeg_node] - 2;
12050  if ((num+qsize[mdeg_node]) > neqns)
12051  goto n1000;
12052 
12053  /* eliminate 'mdeg_node' and perform quotient graph */
12054  /* transformation. reset 'tag' value if necessary. */
12055  tag++;
12056  if (tag >= maxint) {
12057  tag = 1;
12058  for (i = 1; i <= neqns; i++)
12059  if (marker[i] < maxint)
12060  marker[i] = 0;
12061  };
12062 
12063  mmdelm(mdeg_node, xadj, adjncy, head, invp, perm, qsize, list, marker, maxint, tag);
12064 
12065  num += qsize[mdeg_node];
12066  list[mdeg_node] = ehead;
12067  ehead = mdeg_node;
12068  if (delta >= 0)
12069  goto n500;
12070 
12071  n900:
12072  /* update degrees of the nodes involved in the */
12073  /* minimum degree nodes elimination. */
12074  if (num > neqns)
12075  goto n1000;
12076  mmdupd( ehead, neqns, xadj, adjncy, delta, &mdeg, head, invp, perm, qsize, list, marker, maxint, &tag);
12077  }; /* end of -- while ( 1 ) -- */
12078 
12079 n1000:
12080  mmdnum( neqns, perm, invp, qsize );
12081 
12082  /* Adjust from Fortran back to C*/
12083  xadj++; adjncy++; invp++; perm++; head++; qsize++; list++; marker++;
12084 }
12085 
12086 
12087 /**************************************************************************
12088 * mmdelm ...... multiple minimum degree elimination
12089 * Purpose -- This routine eliminates the node mdeg_node of minimum degree
12090 * from the adjacency structure, which is stored in the quotient
12091 * graph format. It also transforms the quotient graph representation
12092 * of the elimination graph.
12093 * Input parameters --
12094 * mdeg_node -- node of minimum degree.
12095 * maxint -- estimate of maximum representable (short) integer.
12096 * tag -- tag value.
12097 * Updated parameters --
12098 * (xadj, adjncy) -- updated adjacency structure.
12099 * (head, forward, backward) -- degree doubly linked structure.
12100 * qsize -- size of supernode.
12101 * marker -- marker vector.
12102 * list -- temporary linked list of eliminated nabors.
12103 ***************************************************************************/
12104 void mmdelm(int mdeg_node, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward,
12105  idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker, int maxint,int tag)
12106 {
12107  int element, i, istop, istart, j,
12108  jstop, jstart, link,
12109  nabor, node, npv, nqnbrs, nxnode,
12110  pvnode, rlmt, rloc, rnode, xqnbr;
12111 
12112  /* find the reachable set of 'mdeg_node' and */
12113  /* place it in the data structure. */
12114  marker[mdeg_node] = tag;
12115  istart = xadj[mdeg_node];
12116  istop = xadj[mdeg_node+1] - 1;
12117 
12118  /* 'element' points to the beginning of the list of */
12119  /* eliminated nabors of 'mdeg_node', and 'rloc' gives the */
12120  /* storage location for the next reachable node. */
12121  element = 0;
12122  rloc = istart;
12123  rlmt = istop;
12124  for ( i = istart; i <= istop; i++ ) {
12125  nabor = adjncy[i];
12126  if ( nabor == 0 ) break;
12127  if ( marker[nabor] < tag ) {
12128  marker[nabor] = tag;
12129  if ( forward[nabor] < 0 ) {
12130  list[nabor] = element;
12131  element = nabor;
12132  } else {
12133  adjncy[rloc] = nabor;
12134  rloc++;
12135  };
12136  }; /* end of -- if -- */
12137  }; /* end of -- for -- */
12138 
12139  /* merge with reachable nodes from generalized elements. */
12140  while ( element > 0 ) {
12141  adjncy[rlmt] = -element;
12142  link = element;
12143 
12144 n400:
12145  jstart = xadj[link];
12146  jstop = xadj[link+1] - 1;
12147  for ( j = jstart; j <= jstop; j++ ) {
12148  node = adjncy[j];
12149  link = -node;
12150  if ( node < 0 ) goto n400;
12151  if ( node == 0 ) break;
12152  if ((marker[node]<tag)&&(forward[node]>=0)) {
12153  marker[node] = tag;
12154  /*use storage from eliminated nodes if necessary.*/
12155  while ( rloc >= rlmt ) {
12156  link = -adjncy[rlmt];
12157  rloc = xadj[link];
12158  rlmt = xadj[link+1] - 1;
12159  };
12160  adjncy[rloc] = node;
12161  rloc++;
12162  };
12163  }; /* end of -- for ( j = jstart; -- */
12164  element = list[element];
12165  }; /* end of -- while ( element > 0 ) -- */
12166  if ( rloc <= rlmt ) adjncy[rloc] = 0;
12167  /* for each node in the reachable set, do the following. */
12168  link = mdeg_node;
12169 
12170 n1100:
12171  istart = xadj[link];
12172  istop = xadj[link+1] - 1;
12173  for ( i = istart; i <= istop; i++ ) {
12174  rnode = adjncy[i];
12175  link = -rnode;
12176  if ( rnode < 0 ) goto n1100;
12177  if ( rnode == 0 ) return;
12178 
12179  /* 'rnode' is in the degree list structure. */
12180  pvnode = backward[rnode];
12181  if (( pvnode != 0 ) && ( pvnode != (-maxint) )) {
12182  /* then remove 'rnode' from the structure. */
12183  nxnode = forward[rnode];
12184  if ( nxnode > 0 ) backward[nxnode] = pvnode;
12185  if ( pvnode > 0 ) forward[pvnode] = nxnode;
12186  npv = -pvnode;
12187  if ( pvnode < 0 ) head[npv] = nxnode;
12188  };
12189 
12190  /* purge inactive quotient nabors of 'rnode'. */
12191  jstart = xadj[rnode];
12192  jstop = xadj[rnode+1] - 1;
12193  xqnbr = jstart;
12194  for ( j = jstart; j <= jstop; j++ ) {
12195  nabor = adjncy[j];
12196  if ( nabor == 0 ) break;
12197  if ( marker[nabor] < tag ) {
12198  adjncy[xqnbr] = nabor;
12199  xqnbr++;
12200  };
12201  };
12202 
12203  /* no active nabor after the purging. */
12204  nqnbrs = xqnbr - jstart;
12205  if ( nqnbrs <= 0 ) {
12206  /* merge 'rnode' with 'mdeg_node'. */
12207  qsize[mdeg_node] += qsize[rnode];
12208  qsize[rnode] = 0;
12209  marker[rnode] = maxint;
12210  forward[rnode] = -mdeg_node;
12211  backward[rnode] = -maxint;
12212  } else {
12213  /* flag 'rnode' for degree update, and */
12214  /* add 'mdeg_node' as a nabor of 'rnode'. */
12215  forward[rnode] = nqnbrs + 1;
12216  backward[rnode] = 0;
12217  adjncy[xqnbr] = mdeg_node;
12218  xqnbr++;
12219  if ( xqnbr <= jstop ) adjncy[xqnbr] = 0;
12220  };
12221  }; /* end of -- for ( i = istart; -- */
12222  return;
12223  }
12224 
12225 /***************************************************************************
12226 * mmdint ---- mult minimum degree initialization
12227 * purpose -- this routine performs initialization for the
12228 * multiple elimination version of the minimum degree algorithm.
12229 * input parameters --
12230 * neqns -- number of equations.
12231 * (xadj, adjncy) -- adjacency structure.
12232 * output parameters --
12233 * (head, dfrow, backward) -- degree doubly linked structure.
12234 * qsize -- size of supernode ( initialized to one).
12235 * list -- linked list.
12236 * marker -- marker vector.
12237 ****************************************************************************/
12238 int mmdint(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward,
12239  idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker)
12240 {
12241  int fnode, ndeg, node;
12242 
12243  for ( node = 1; node <= neqns; node++ ) {
12244  head[node] = 0;
12245  qsize[node] = 1;
12246  marker[node] = 0;
12247  list[node] = 0;
12248  };
12249 
12250  /* initialize the degree doubly linked lists. */
12251  for ( node = 1; node <= neqns; node++ ) {
12252  ndeg = xadj[node+1] - xadj[node]/* + 1*/; /* george */
12253  if (ndeg == 0)
12254  ndeg = 1;
12255  fnode = head[ndeg];
12256  forward[node] = fnode;
12257  head[ndeg] = node;
12258  if ( fnode > 0 ) backward[fnode] = node;
12259  backward[node] = -ndeg;
12260  };
12261  return 0;
12262 }
12263 
12264 /****************************************************************************
12265 * mmdnum --- multi minimum degree numbering
12266 * purpose -- this routine performs the final step in producing
12267 * the permutation and inverse permutation vectors in the
12268 * multiple elimination version of the minimum degree
12269 * ordering algorithm.
12270 * input parameters --
12271 * neqns -- number of equations.
12272 * qsize -- size of supernodes at elimination.
12273 * updated parameters --
12274 * invp -- inverse permutation vector. on input,
12275 * if qsize[node] = 0, then node has been merged
12276 * into the node -invp[node]; otherwise,
12277 * -invp[node] is its inverse labelling.
12278 * output parameters --
12279 * perm -- the permutation vector.
12280 ****************************************************************************/
12281 void mmdnum(int neqns, idxtype *perm, idxtype *invp, idxtype *qsize)
12282 {
12283  int father, nextf, node, nqsize, num, root;
12284 
12285  for ( node = 1; node <= neqns; node++ ) {
12286  nqsize = qsize[node];
12287  if ( nqsize <= 0 ) perm[node] = invp[node];
12288  if ( nqsize > 0 ) perm[node] = -invp[node];
12289  };
12290 
12291  /* for each node which has been merged, do the following. */
12292  for ( node = 1; node <= neqns; node++ ) {
12293  if ( perm[node] <= 0 ) {
12294 
12295  /* trace the merged tree until one which has not */
12296  /* been merged, call it root. */
12297  father = node;
12298  while ( perm[father] <= 0 )
12299  father = - perm[father];
12300 
12301  /* number node after root. */
12302  root = father;
12303  num = perm[root] + 1;
12304  invp[node] = -num;
12305  perm[root] = num;
12306 
12307  /* shorten the merged tree. */
12308  father = node;
12309  nextf = - perm[father];
12310  while ( nextf > 0 ) {
12311  perm[father] = -root;
12312  father = nextf;
12313  nextf = -perm[father];
12314  };
12315  }; /* end of -- if ( perm[node] <= 0 ) -- */
12316  }; /* end of -- for ( node = 1; -- */
12317 
12318  /* ready to compute perm. */
12319  for ( node = 1; node <= neqns; node++ ) {
12320  num = -invp[node];
12321  invp[node] = num;
12322  perm[num] = node;
12323  };
12324  return;
12325 }
12326 
12327 /****************************************************************************
12328 * mmdupd ---- multiple minimum degree update
12329 * purpose -- this routine updates the degrees of nodes after a
12330 * multiple elimination step.
12331 * input parameters --
12332 * ehead -- the beginning of the list of eliminated nodes
12333 * (i.e., newly formed elements).
12334 * neqns -- number of equations.
12335 * (xadj, adjncy) -- adjacency structure.
12336 * delta -- tolerance value for multiple elimination.
12337 * maxint -- maximum machine representable (short) integer.
12338 * updated parameters --
12339 * mdeg -- new minimum degree after degree update.
12340 * (head, forward, backward) -- degree doubly linked structure.
12341 * qsize -- size of supernode.
12342 * list -- marker vector for degree update.
12343 * *tag -- tag value.
12344 ****************************************************************************/
12345 void mmdupd(int ehead, int neqns, idxtype *xadj, idxtype *adjncy, int delta, int *mdeg,
12346  idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list,
12347  idxtype *marker, int maxint,int *tag)
12348 {
12349  int deg, deg0, element, enode, fnode, i, iq2, istop,
12350  istart, j, jstop, jstart, link, mdeg0, mtag, nabor,
12351  node, q2head, qxhead;
12352 
12353  mdeg0 = *mdeg + delta;
12354  element = ehead;
12355 
12356 n100:
12357  if ( element <= 0 ) return;
12358 
12359  /* for each of the newly formed element, do the following. */
12360  /* reset tag value if necessary. */
12361  mtag = *tag + mdeg0;
12362  if ( mtag >= maxint ) {
12363  *tag = 1;
12364  for ( i = 1; i <= neqns; i++ )
12365  if ( marker[i] < maxint ) marker[i] = 0;
12366  mtag = *tag + mdeg0;
12367  };
12368 
12369  /* create two linked lists from nodes associated with 'element': */
12370  /* one with two nabors (q2head) in the adjacency structure, and the*/
12371  /* other with more than two nabors (qxhead). also compute 'deg0',*/
12372  /* number of nodes in this element. */
12373  q2head = 0;
12374  qxhead = 0;
12375  deg0 = 0;
12376  link =element;
12377 
12378 n400:
12379  istart = xadj[link];
12380  istop = xadj[link+1] - 1;
12381  for ( i = istart; i <= istop; i++ ) {
12382  enode = adjncy[i];
12383  link = -enode;
12384  if ( enode < 0 ) goto n400;
12385  if ( enode == 0 ) break;
12386  if ( qsize[enode] != 0 ) {
12387  deg0 += qsize[enode];
12388  marker[enode] = mtag;
12389 
12390  /*'enode' requires a degree update*/
12391  if ( backward[enode] == 0 ) {
12392  /* place either in qxhead or q2head list. */
12393  if ( forward[enode] != 2 ) {
12394  list[enode] = qxhead;
12395  qxhead = enode;
12396  } else {
12397  list[enode] = q2head;
12398  q2head = enode;
12399  };
12400  };
12401  }; /* enf of -- if ( qsize[enode] != 0 ) -- */
12402  }; /* end of -- for ( i = istart; -- */
12403 
12404  /* for each node in q2 list, do the following. */
12405  enode = q2head;
12406  iq2 = 1;
12407 
12408 n900:
12409  if ( enode <= 0 ) goto n1500;
12410  if ( backward[enode] != 0 ) goto n2200;
12411  (*tag)++;
12412  deg = deg0;
12413 
12414  /* identify the other adjacent element nabor. */
12415  istart = xadj[enode];
12416  nabor = adjncy[istart];
12417  if ( nabor == element ) nabor = adjncy[istart+1];
12418  link = nabor;
12419  if ( forward[nabor] >= 0 ) {
12420  /* nabor is uneliminated, increase degree count. */
12421  deg += qsize[nabor];
12422  goto n2100;
12423  };
12424 
12425  /* the nabor is eliminated. for each node in the 2nd element */
12426  /* do the following. */
12427 n1000:
12428  istart = xadj[link];
12429  istop = xadj[link+1] - 1;
12430  for ( i = istart; i <= istop; i++ ) {
12431  node = adjncy[i];
12432  link = -node;
12433  if ( node != enode ) {
12434  if ( node < 0 ) goto n1000;
12435  if ( node == 0 ) goto n2100;
12436  if ( qsize[node] != 0 ) {
12437  if ( marker[node] < *tag ) {
12438  /* 'node' is not yet considered. */
12439  marker[node] = *tag;
12440  deg += qsize[node];
12441  } else {
12442  if ( backward[node] == 0 ) {
12443  if ( forward[node] == 2 ) {
12444  /* 'node' is indistinguishable from 'enode'.*/
12445  /* merge them into a new supernode. */
12446  qsize[enode] += qsize[node];
12447  qsize[node] = 0;
12448  marker[node] = maxint;
12449  forward[node] = -enode;
12450  backward[node] = -maxint;
12451  } else {
12452  /* 'node' is outmacthed by 'enode' */
12453  if (backward[node]==0) backward[node] = -maxint;
12454  };
12455  }; /* end of -- if ( backward[node] == 0 ) -- */
12456  }; /* end of -- if ( marker[node] < *tag ) -- */
12457  }; /* end of -- if ( qsize[node] != 0 ) -- */
12458  }; /* end of -- if ( node != enode ) -- */
12459  }; /* end of -- for ( i = istart; -- */
12460  goto n2100;
12461 
12462 n1500:
12463  /* for each 'enode' in the 'qx' list, do the following. */
12464  enode = qxhead;
12465  iq2 = 0;
12466 
12467 n1600: if ( enode <= 0 ) goto n2300;
12468  if ( backward[enode] != 0 ) goto n2200;
12469  (*tag)++;
12470  deg = deg0;
12471 
12472  /*for each unmarked nabor of 'enode', do the following.*/
12473  istart = xadj[enode];
12474  istop = xadj[enode+1] - 1;
12475  for ( i = istart; i <= istop; i++ ) {
12476  nabor = adjncy[i];
12477  if ( nabor == 0 ) break;
12478  if ( marker[nabor] < *tag ) {
12479  marker[nabor] = *tag;
12480  link = nabor;
12481  if ( forward[nabor] >= 0 )
12482  /*if uneliminated, include it in deg count.*/
12483  deg += qsize[nabor];
12484  else {
12485 n1700:
12486  /* if eliminated, include unmarked nodes in this*/
12487  /* element into the degree count. */
12488  jstart = xadj[link];
12489  jstop = xadj[link+1] - 1;
12490  for ( j = jstart; j <= jstop; j++ ) {
12491  node = adjncy[j];
12492  link = -node;
12493  if ( node < 0 ) goto n1700;
12494  if ( node == 0 ) break;
12495  if ( marker[node] < *tag ) {
12496  marker[node] = *tag;
12497  deg += qsize[node];
12498  };
12499  }; /* end of -- for ( j = jstart; -- */
12500  }; /* end of -- if ( forward[nabor] >= 0 ) -- */
12501  }; /* end of -- if ( marker[nabor] < *tag ) -- */
12502  }; /* end of -- for ( i = istart; -- */
12503 
12504 n2100:
12505  /* update external degree of 'enode' in degree structure, */
12506  /* and '*mdeg' if necessary. */
12507  deg = deg - qsize[enode] + 1;
12508  fnode = head[deg];
12509  forward[enode] = fnode;
12510  backward[enode] = -deg;
12511  if ( fnode > 0 ) backward[fnode] = enode;
12512  head[deg] = enode;
12513  if ( deg < *mdeg ) *mdeg = deg;
12514 
12515 n2200:
12516  /* get next enode in current element. */
12517  enode = list[enode];
12518  if ( iq2 == 1 ) goto n900;
12519  goto n1600;
12520 
12521 n2300:
12522  /* get next element in the list. */
12523  *tag = mtag;
12524  element = list[element];
12525  goto n100;
12526  }
12527 /*
12528  * Copyright 1997, Regents of the University of Minnesota
12529  *
12530  * mpmetis.c
12531  *
12532  * This file contains the top level routines for the multilevel recursive
12533  * bisection algorithm PMETIS.
12534  *
12535  * Started 7/24/97
12536  * George
12537  *
12538  * $Id$
12539  *
12540  */
12541 
12542 
12543 
12544 
12545 
12546 /*************************************************************************
12547 * This function is the entry point for PWMETIS that accepts exact weights
12548 * for the target partitions
12549 **************************************************************************/
12550 void METIS_mCPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
12551  idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
12552  int *options, int *edgecut, idxtype *part)
12553 {
12554  GraphType graph;
12555  CtrlType ctrl;
12556 
12557  if (*numflag == 1)
12558  Change2CNumbering(*nvtxs, xadj, adjncy);
12559 
12560  SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
12561 
12562  if (options[0] == 0) { /* Use the default parameters */
12563  ctrl.CType = McPMETIS_CTYPE;
12564  ctrl.IType = McPMETIS_ITYPE;
12565  ctrl.RType = McPMETIS_RTYPE;
12566  ctrl.dbglvl = McPMETIS_DBGLVL;
12567  }
12568  else {
12569  ctrl.CType = options[OPTION_CTYPE];
12570  ctrl.IType = options[OPTION_ITYPE];
12571  ctrl.RType = options[OPTION_RTYPE];
12572  ctrl.dbglvl = options[OPTION_DBGLVL];
12573  }
12574  ctrl.optype = OP_PMETIS;
12575  ctrl.CoarsenTo = 100;
12576 
12577  ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
12578 
12579  InitRandom(-1);
12580 
12581  AllocateWorkSpace(&ctrl, &graph, *nparts);
12582 
12583  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
12584  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
12585 
12586  *edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0);
12587 
12588  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
12589  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
12590 
12591  FreeWorkSpace(&ctrl, &graph);
12592 
12593  if (*numflag == 1)
12594  Change2FNumbering(*nvtxs, xadj, adjncy, part);
12595 }
12596 
12597 
12598 
12599 /*************************************************************************
12600 * This function is the entry point for PWMETIS that accepts exact weights
12601 * for the target partitions
12602 **************************************************************************/
12603 void METIS_mCHPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
12604  idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
12605  float *ubvec, int *options, int *edgecut, idxtype *part)
12606 {
12607  GraphType graph;
12608  CtrlType ctrl;
12609  float *myubvec;
12610 
12611  if (*numflag == 1)
12612  Change2CNumbering(*nvtxs, xadj, adjncy);
12613 
12614  SetUpGraph(&graph, OP_PMETIS, *nvtxs, *ncon, xadj, adjncy, vwgt, adjwgt, *wgtflag);
12615 
12616  if (options[0] == 0) { /* Use the default parameters */
12617  ctrl.CType = PMETIS_CTYPE;
12618  ctrl.IType = PMETIS_ITYPE;
12619  ctrl.RType = PMETIS_RTYPE;
12620  ctrl.dbglvl = PMETIS_DBGLVL;
12621  }
12622  else {
12623  ctrl.CType = options[OPTION_CTYPE];
12624  ctrl.IType = options[OPTION_ITYPE];
12625  ctrl.RType = options[OPTION_RTYPE];
12626  ctrl.dbglvl = options[OPTION_DBGLVL];
12627  }
12628  ctrl.optype = OP_PMETIS;
12629  ctrl.CoarsenTo = 100;
12630 
12631  ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
12632 
12633  myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts");
12634  scopy(*ncon, ubvec, myubvec);
12635 
12636  InitRandom(-1);
12637 
12638  AllocateWorkSpace(&ctrl, &graph, *nparts);
12639 
12640  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
12641  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
12642 
12643  *edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0);
12644 
12645  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
12646  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
12647 
12648  FreeWorkSpace(&ctrl, &graph);
12649  GKfree((void **) &myubvec, LTERM);
12650 
12651  if (*numflag == 1)
12652  Change2FNumbering(*nvtxs, xadj, adjncy, part);
12653 }
12654 
12655 
12656 
12657 /*************************************************************************
12658 * This function is the entry point for PWMETIS that accepts exact weights
12659 * for the target partitions
12660 **************************************************************************/
12661 void METIS_mCPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
12662  float *nvwgt, idxtype *adjwgt, int *nparts, int *options, int *edgecut, idxtype *part)
12663 {
12664  GraphType graph;
12665  CtrlType ctrl;
12666 
12667  SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt);
12668 
12669  if (options[0] == 0) { /* Use the default parameters */
12670  ctrl.CType = PMETIS_CTYPE;
12671  ctrl.IType = PMETIS_ITYPE;
12672  ctrl.RType = PMETIS_RTYPE;
12673  ctrl.dbglvl = PMETIS_DBGLVL;
12674  }
12675  else {
12676  ctrl.CType = options[OPTION_CTYPE];
12677  ctrl.IType = options[OPTION_ITYPE];
12678  ctrl.RType = options[OPTION_RTYPE];
12679  ctrl.dbglvl = options[OPTION_DBGLVL];
12680  }
12681  ctrl.optype = OP_PMETIS;
12682  ctrl.CoarsenTo = 100;
12683 
12684  ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
12685 
12686  InitRandom(-1);
12687 
12688  AllocateWorkSpace(&ctrl, &graph, *nparts);
12689 
12690  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
12691  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
12692 
12693  *edgecut = MCMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, 1.000, 0);
12694 
12695  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
12696  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
12697 
12698  FreeWorkSpace(&ctrl, &graph);
12699 
12700 }
12701 
12702 
12703 /*************************************************************************
12704 * This function is the entry point for PWMETIS that accepts exact weights
12705 * for the target partitions
12706 **************************************************************************/
12707 void METIS_mCHPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy,
12708  float *nvwgt, idxtype *adjwgt, int *nparts, float *ubvec, int *options, int *edgecut,
12709  idxtype *part)
12710 {
12711  GraphType graph;
12712  CtrlType ctrl;
12713  float *myubvec;
12714 
12715  SetUpGraph2(&graph, *nvtxs, *ncon, xadj, adjncy, nvwgt, adjwgt);
12716 
12717  if (options[0] == 0) { /* Use the default parameters */
12718  ctrl.CType = PMETIS_CTYPE;
12719  ctrl.IType = PMETIS_ITYPE;
12720  ctrl.RType = PMETIS_RTYPE;
12721  ctrl.dbglvl = PMETIS_DBGLVL;
12722  }
12723  else {
12724  ctrl.CType = options[OPTION_CTYPE];
12725  ctrl.IType = options[OPTION_ITYPE];
12726  ctrl.RType = options[OPTION_RTYPE];
12727  ctrl.dbglvl = options[OPTION_DBGLVL];
12728  }
12729  ctrl.optype = OP_PMETIS;
12730  ctrl.CoarsenTo = 100;
12731 
12732  ctrl.nmaxvwgt = 1.5/(1.0*ctrl.CoarsenTo);
12733 
12734  myubvec = fmalloc(*ncon, "PWMETIS: mytpwgts");
12735  scopy(*ncon, ubvec, myubvec);
12736 
12737  InitRandom(-1);
12738 
12739  AllocateWorkSpace(&ctrl, &graph, *nparts);
12740 
12741  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
12742  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
12743 
12744  *edgecut = MCHMlevelRecursiveBisection(&ctrl, &graph, *nparts, part, myubvec, 0);
12745 
12746  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
12747  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
12748 
12749  FreeWorkSpace(&ctrl, &graph);
12750  GKfree((void **) &myubvec, LTERM);
12751 
12752 }
12753 
12754 
12755 
12756 
12757 /*************************************************************************
12758 * This function takes a graph and produces a bisection of it
12759 **************************************************************************/
12761  float ubfactor, int fpart)
12762 {
12763  int i, nvtxs, cut;
12764  idxtype *label, *where;
12765  GraphType lgraph, rgraph;
12766  float tpwgts[2];
12767 
12768  nvtxs = graph->nvtxs;
12769  if (nvtxs == 0) {
12770  printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n");
12771  return 0;
12772  }
12773 
12774  /* Determine the weights of the partitions */
12775  tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts);
12776  tpwgts[1] = 1.0 - tpwgts[0];
12777 
12778  MCMlevelEdgeBisection(ctrl, graph, tpwgts, ubfactor);
12779  cut = graph->mincut;
12780 
12781  label = graph->label;
12782  where = graph->where;
12783  for (i=0; i<nvtxs; i++)
12784  part[label[i]] = where[i] + fpart;
12785 
12786  if (nparts > 2)
12787  SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
12788 
12789  /* Free the memory of the top level graph */
12790  GKfree((void **) &graph->gdata, (void **) &graph->nvwgt, (void **) &graph->rdata,
12791  (void **) &graph->npwgts, (void **) &graph->label, LTERM);
12792 
12793 
12794  /* Do the recursive call */
12795  if (nparts > 3) {
12796  cut += MCMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, ubfactor, fpart);
12797  cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2);
12798  }
12799  else if (nparts == 3) {
12800  cut += MCMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, ubfactor, fpart+nparts/2);
12801  GKfree((void **) &lgraph.gdata, (void **) &lgraph.nvwgt, (void **) &lgraph.label, LTERM);
12802  }
12803 
12804  return cut;
12805 
12806 }
12807 
12808 
12809 
12810 /*************************************************************************
12811 * This function takes a graph and produces a bisection of it
12812 **************************************************************************/
12814  float *ubvec, int fpart)
12815 {
12816  int i, nvtxs, ncon, cut;
12817  idxtype *label, *where;
12818  GraphType lgraph, rgraph;
12819  float tpwgts[2], *npwgts, *lubvec, *rubvec;
12820 
12821  lubvec = rubvec = NULL;
12822 
12823  nvtxs = graph->nvtxs;
12824  ncon = graph->ncon;
12825  if (nvtxs == 0) {
12826  printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n");
12827  return 0;
12828  }
12829 
12830  /* Determine the weights of the partitions */
12831  tpwgts[0] = 1.0*(nparts>>1)/(1.0*nparts);
12832  tpwgts[1] = 1.0 - tpwgts[0];
12833 
12834  /* For now, relax at the coarsest level only */
12835  if (nparts == 2)
12836  MCHMlevelEdgeBisection(ctrl, graph, tpwgts, ubvec);
12837  else
12838  MCMlevelEdgeBisection(ctrl, graph, tpwgts, 1.000);
12839  cut = graph->mincut;
12840 
12841  label = graph->label;
12842  where = graph->where;
12843  for (i=0; i<nvtxs; i++)
12844  part[label[i]] = where[i] + fpart;
12845 
12846  if (nparts > 2) {
12847  /* Adjust the ubvecs before the split */
12848  npwgts = graph->npwgts;
12849  lubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection");
12850  rubvec = fmalloc(ncon, "MCHMlevelRecursiveBisection");
12851 
12852  for (i=0; i<ncon; i++) {
12853  lubvec[i] = ubvec[i]*tpwgts[0]/npwgts[i];
12854  lubvec[i] = amax(lubvec[i], 1.01);
12855 
12856  rubvec[i] = ubvec[i]*tpwgts[1]/npwgts[ncon+i];
12857  rubvec[i] = amax(rubvec[i], 1.01);
12858  }
12859 
12860  SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
12861  }
12862 
12863  /* Free the memory of the top level graph */
12864  GKfree((void **) &graph->gdata, (void **) &graph->nvwgt, (void **) &graph->rdata,
12865  (void **) &graph->npwgts, (void **) &graph->label, LTERM);
12866 
12867 
12868  /* Do the recursive call */
12869  if (nparts > 3) {
12870  cut += MCHMlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, lubvec, fpart);
12871  cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2);
12872  }
12873  else if (nparts == 3) {
12874  cut += MCHMlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, rubvec, fpart+nparts/2);
12875  GKfree((void **) &lgraph.gdata, (void **) &lgraph.nvwgt, (void **) &lgraph.label, LTERM);
12876  }
12877 
12878  GKfree((void **) &lubvec, (void **) &rubvec, LTERM);
12879 
12880  return cut;
12881 
12882 }
12883 
12884 
12885 
12886 
12887 /*************************************************************************
12888 * This function performs multilevel bisection
12889 **************************************************************************/
12890 void MCMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
12891 {
12892  GraphType *cgraph;
12893 
12894  cgraph = MCCoarsen2Way(ctrl, graph);
12895 
12896  MocInit2WayPartition(ctrl, cgraph, tpwgts, ubfactor);
12897 
12898  MocRefine2Way(ctrl, graph, cgraph, tpwgts, ubfactor);
12899 
12900 }
12901 
12902 
12903 
12904 /*************************************************************************
12905 * This function performs multilevel bisection
12906 **************************************************************************/
12907 void MCHMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
12908 {
12909  GraphType *cgraph;
12910 
12911  cgraph = MCCoarsen2Way(ctrl, graph);
12912 
12913  MocInit2WayPartition2(ctrl, cgraph, tpwgts, ubvec);
12914 
12915  MocRefine2Way2(ctrl, graph, cgraph, tpwgts, ubvec);
12916 
12917 }
12918 
12919 
12920 /*
12921  * Copyright 1997, Regents of the University of Minnesota
12922  *
12923  * mrefine2.c
12924  *
12925  * This file contains the driving routines for multilevel refinement
12926  *
12927  * Started 7/24/97
12928  * George
12929  *
12930  * $Id$
12931  */
12932 
12933 
12934 
12935 
12936 /*************************************************************************
12937 * This function is the entry point of refinement
12938 **************************************************************************/
12939 void MocRefine2Way2(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts,
12940  float *ubvec)
12941 {
12942 
12943  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
12944 
12945  /* Compute the parameters of the coarsest graph */
12946  MocCompute2WayPartitionParams(ctrl, graph);
12947 
12948  for (;;) {
12949  ASSERT(CheckBnd(graph));
12950 
12951  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
12952  switch (ctrl->RType) {
12953  case RTYPE_FM:
12954  MocBalance2Way2(ctrl, graph, tpwgts, ubvec);
12955  MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, ubvec, 8);
12956  break;
12957  default:
12958  errexit("Unknown refinement type: %d\n", ctrl->RType);
12959  }
12960  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
12961 
12962  if (graph == orggraph)
12963  break;
12964 
12965  graph = graph->finer;
12966  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
12967  MocProject2WayPartition(ctrl, graph);
12968  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
12969  }
12970 
12971  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
12972 }
12973 
12974 
12975 /*
12976  * Copyright 1997, Regents of the University of Minnesota
12977  *
12978  * refine.c
12979  *
12980  * This file contains the driving routines for multilevel refinement
12981  *
12982  * Started 7/24/97
12983  * George
12984  *
12985  * $Id$
12986  */
12987 
12988 
12989 
12990 
12991 /*************************************************************************
12992 * This function is the entry point of refinement
12993 **************************************************************************/
12994 void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor)
12995 {
12996  int i;
12997  float tubvec[MAXNCON];
12998 
12999  for (i=0; i<graph->ncon; i++)
13000  tubvec[i] = 1.0;
13001 
13002  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
13003 
13004  /* Compute the parameters of the coarsest graph */
13005  MocCompute2WayPartitionParams(ctrl, graph);
13006 
13007  for (;;) {
13008  ASSERT(CheckBnd(graph));
13009 
13010  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
13011  switch (ctrl->RType) {
13012  case RTYPE_FM:
13013  MocBalance2Way(ctrl, graph, tpwgts, 1.03);
13014  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
13015  break;
13016  case 2:
13017  MocBalance2Way(ctrl, graph, tpwgts, 1.03);
13018  MocFM_2WayEdgeRefine2(ctrl, graph, tpwgts, tubvec, 8);
13019  break;
13020  default:
13021  errexit("Unknown refinement type: %d\n", ctrl->RType);
13022  }
13023  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
13024 
13025  if (graph == orggraph)
13026  break;
13027 
13028  graph = graph->finer;
13029  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
13030  MocProject2WayPartition(ctrl, graph);
13031  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
13032  }
13033 
13034  MocBalance2Way(ctrl, graph, tpwgts, 1.01);
13035  MocFM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
13036 
13037  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
13038 }
13039 
13040 
13041 /*************************************************************************
13042 * This function allocates memory for 2-way edge refinement
13043 **************************************************************************/
13045 {
13046  int nvtxs, ncon;
13047 
13048  nvtxs = graph->nvtxs;
13049  ncon = graph->ncon;
13050 
13051  graph->rdata = idxmalloc(5*nvtxs, "Allocate2WayPartitionMemory: rdata");
13052  graph->where = graph->rdata;
13053  graph->id = graph->rdata + nvtxs;
13054  graph->ed = graph->rdata + 2*nvtxs;
13055  graph->bndptr = graph->rdata + 3*nvtxs;
13056  graph->bndind = graph->rdata + 4*nvtxs;
13057 
13058  graph->npwgts = fmalloc(2*ncon, "npwgts");
13059 }
13060 
13061 
13062 /*************************************************************************
13063 * This function computes the initial id/ed
13064 **************************************************************************/
13066 {
13067  int i, j, nvtxs, ncon, nbnd, mincut;
13068  idxtype *xadj, *adjncy, *adjwgt;
13069  float *nvwgt, *npwgts;
13070  idxtype *id, *ed, *where;
13071  idxtype *bndptr, *bndind;
13072  int me;
13073 
13074  nvtxs = graph->nvtxs;
13075  ncon = graph->ncon;
13076  xadj = graph->xadj;
13077  nvwgt = graph->nvwgt;
13078  adjncy = graph->adjncy;
13079  adjwgt = graph->adjwgt;
13080 
13081  where = graph->where;
13082  npwgts = sset(2*ncon, 0.0, graph->npwgts);
13083  id = idxset(nvtxs, 0, graph->id);
13084  ed = idxset(nvtxs, 0, graph->ed);
13085  bndptr = idxset(nvtxs, -1, graph->bndptr);
13086  bndind = graph->bndind;
13087 
13088 
13089  /*------------------------------------------------------------
13090  / Compute now the id/ed degrees
13091  /------------------------------------------------------------*/
13092  nbnd = mincut = 0;
13093  for (i=0; i<nvtxs; i++) {
13094  ASSERT(where[i] >= 0 && where[i] <= 1);
13095  me = where[i];
13096  /*printf("saxpy: %d",i);*/
13097  saxpy(ncon, 1.0, nvwgt+i*ncon, 1, npwgts+me*ncon, 1);
13098 
13099  for (j=xadj[i]; j<xadj[i+1]; j++) {
13100  if (me == where[adjncy[j]])
13101  id[i] += adjwgt[j];
13102  else
13103  ed[i] += adjwgt[j];
13104  }
13105 
13106  if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
13107  mincut += ed[i];
13108  bndptr[i] = nbnd;
13109  bndind[nbnd++] = i;
13110  }
13111  }
13112 
13113  graph->mincut = mincut/2;
13114  graph->nbnd = nbnd;
13115 
13116 }
13117 
13118 
13119 
13120 /*************************************************************************
13121 * This function projects a partition, and at the same time computes the
13122 * parameters for refinement.
13123 **************************************************************************/
13125 {
13126  int i, j, k, nvtxs, nbnd, me;
13127  idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
13128  idxtype *cmap, *where, *id, *ed, *bndptr, *bndind;
13129  idxtype *cwhere, *cid, *ced, *cbndptr;
13130  GraphType *cgraph;
13131 
13132  cgraph = graph->coarser;
13133  cwhere = cgraph->where;
13134  cid = cgraph->id;
13135  ced = cgraph->ed;
13136  cbndptr = cgraph->bndptr;
13137 
13138  nvtxs = graph->nvtxs;
13139  cmap = graph->cmap;
13140  xadj = graph->xadj;
13141  adjncy = graph->adjncy;
13142  adjwgt = graph->adjwgt;
13143  adjwgtsum = graph->adjwgtsum;
13144 
13145  MocAllocate2WayPartitionMemory(ctrl, graph);
13146 
13147  where = graph->where;
13148  id = idxset(nvtxs, 0, graph->id);
13149  ed = idxset(nvtxs, 0, graph->ed);
13150  bndptr = idxset(nvtxs, -1, graph->bndptr);
13151  bndind = graph->bndind;
13152 
13153 
13154  /* Go through and project partition and compute id/ed for the nodes */
13155  for (i=0; i<nvtxs; i++) {
13156  k = cmap[i];
13157  where[i] = cwhere[k];
13158  cmap[i] = cbndptr[k];
13159  }
13160 
13161  for (nbnd=0, i=0; i<nvtxs; i++) {
13162  me = where[i];
13163 
13164  id[i] = adjwgtsum[i];
13165 
13166  if (xadj[i] == xadj[i+1]) {
13167  bndptr[i] = nbnd;
13168  bndind[nbnd++] = i;
13169  }
13170  else {
13171  if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */
13172  for (j=xadj[i]; j<xadj[i+1]; j++) {
13173  if (me != where[adjncy[j]])
13174  ed[i] += adjwgt[j];
13175  }
13176  id[i] -= ed[i];
13177 
13178  if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
13179  bndptr[i] = nbnd;
13180  bndind[nbnd++] = i;
13181  }
13182  }
13183  }
13184  }
13185 
13186  graph->mincut = cgraph->mincut;
13187  graph->nbnd = nbnd;
13188  scopy(2*graph->ncon, cgraph->npwgts, graph->npwgts);
13189 
13190  FreeGraph(graph->coarser);
13191  graph->coarser = NULL;
13192 
13193 }
13194 
13195 /*
13196  * mutil.c
13197  *
13198  * This file contains various utility functions for the MOC portion of the
13199  * code
13200  *
13201  * Started 2/15/98
13202  * George
13203  *
13204  * $Id$
13205  *
13206  */
13207 
13208 
13209 
13210 
13211 /*************************************************************************
13212 * This function checks if the vertex weights of two vertices are below
13213 * a given set of values
13214 **************************************************************************/
13215 int AreAllVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
13216 {
13217  int i;
13218 
13219  for (i=0; i<ncon; i++)
13220  if (alpha*vwgt1[i] + beta*vwgt2[i] > limit)
13221  return 0;
13222 
13223  return 1;
13224 }
13225 
13226 
13227 /*************************************************************************
13228 * This function checks if the vertex weights of two vertices are below
13229 * a given set of values
13230 **************************************************************************/
13231 int AreAnyVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
13232 {
13233  int i;
13234 
13235  for (i=0; i<ncon; i++)
13236  if (alpha*vwgt1[i] + beta*vwgt2[i] < limit)
13237  return 1;
13238 
13239  return 0;
13240 }
13241 
13242 
13243 
13244 /*************************************************************************
13245 * This function checks if the vertex weights of two vertices are above
13246 * a given set of values
13247 **************************************************************************/
13248 int AreAllVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
13249 {
13250  int i;
13251 
13252  for (i=0; i<ncon; i++)
13253  if (alpha*vwgt1[i] + beta*vwgt2[i] < limit)
13254  return 0;
13255 
13256  return 1;
13257 }
13258 
13259 
13260 /*************************************************************************
13261 * This function computes the load imbalance over all the constrains
13262 * For now assume that we just want balanced partitionings
13263 **************************************************************************/
13264 float ComputeLoadImbalance(int ncon, int nparts, float *npwgts, float *tpwgts)
13265 {
13266  int i, j;
13267  float max, lb=0.0;
13268 
13269  for (i=0; i<ncon; i++) {
13270  max = 0.0;
13271  for (j=0; j<nparts; j++) {
13272  if (npwgts[j*ncon+i] > max)
13273  max = npwgts[j*ncon+i];
13274  }
13275  if (max*nparts > lb)
13276  lb = max*nparts;
13277  }
13278 
13279  return lb;
13280 }
13281 
13282 /*************************************************************************
13283 * This function checks if the vertex weights of two vertices are below
13284 * a given set of values
13285 **************************************************************************/
13286 int AreAllBelow(int ncon, float *v1, float *v2)
13287 {
13288  int i;
13289 
13290  for (i=0; i<ncon; i++)
13291  if (v1[i] > v2[i])
13292  return 0;
13293 
13294  return 1;
13295 }
13296 /*
13297  * Copyright 1997, Regents of the University of Minnesota
13298  *
13299  * myqsort.c
13300  *
13301  * This file contains a fast idxtype increasing qsort algorithm.
13302  * Addopted from TeX
13303  *
13304  * Started 10/18/96
13305  * George
13306  *
13307  * $Id$
13308  */
13309 
13310  /* only for type declarations */
13311 
13312 #define THRESH 1 /* threshold for insertion */
13313 #define MTHRESH 6 /* threshold for median */
13314 
13315 
13316 
13317 
13318 static void siqst(idxtype *, idxtype *);
13319 static void iiqst(int *, int *);
13320 static void keyiqst(KeyValueType *, KeyValueType *);
13321 static void keyvaliqst(KeyValueType *, KeyValueType *);
13322 
13323 
13324 /*************************************************************************
13325 * Entry point of idxtype increasing sort
13326 **************************************************************************/
13327 void iidxsort(int n, idxtype *base)
13328 {
13329  register idxtype *i;
13330  register idxtype *j;
13331  register idxtype *lo;
13332  register idxtype *hi;
13333  register idxtype *min;
13334  register idxtype c;
13335  idxtype *max;
13336 
13337  if (n <= 1)
13338  return;
13339 
13340  max = base + n;
13341 
13342  if (n >= THRESH) {
13343  siqst(base, max);
13344  hi = base + THRESH;
13345  }
13346  else
13347  hi = max;
13348 
13349  for (j = lo = base; lo++ < hi;) {
13350  if (*j > *lo)
13351  j = lo;
13352  }
13353  if (j != base) { /* swap j into place */
13354  c = *base;
13355  *base = *j;
13356  *j = c;
13357  }
13358 
13359  for (min = base; (hi = min += 1) < max;) {
13360  while (*(--hi) > *min);
13361  if ((hi += 1) != min) {
13362  for (lo = min + 1; --lo >= min;) {
13363  c = *lo;
13364  for (i = j = lo; (j -= 1) >= hi; i = j)
13365  *i = *j;
13366  *i = c;
13367  }
13368  }
13369  }
13370 }
13371 
13372 static void siqst(idxtype *base, idxtype *max)
13373 {
13374  register idxtype *i;
13375  register idxtype *j;
13376  register idxtype *jj;
13377  register idxtype *mid;
13378  register idxtype c;
13379  idxtype *tmp;
13380  int lo;
13381  int hi;
13382 
13383  lo = max - base; /* number of elements as idxtype */
13384  do {
13385  mid = base + ((unsigned) lo>>1);
13386  if (lo >= MTHRESH) {
13387  j = (*base > *mid ? base : mid);
13388  tmp = max - 1;
13389  if (*j > *tmp) {
13390  j = (j == base ? mid : base); /* switch to first loser */
13391  if (*j < *tmp)
13392  j = tmp;
13393  }
13394 
13395  if (j != mid) { /* SWAP */
13396  c = *mid;
13397  *mid = *j;
13398  *j = c;
13399  }
13400  }
13401 
13402  /* Semi-standard quicksort partitioning/swapping */
13403  for (i = base, j = max - 1;;) {
13404  while (i < mid && *i <= *mid)
13405  i++;
13406  while (j > mid) {
13407  if (*mid <= *j) {
13408  j--;
13409  continue;
13410  }
13411  tmp = i + 1; /* value of i after swap */
13412  if (i == mid) /* j <-> mid, new mid is j */
13413  mid = jj = j;
13414  else /* i <-> j */
13415  jj = j--;
13416  goto swap;
13417  }
13418 
13419  if (i == mid)
13420  break;
13421  else { /* i <-> mid, new mid is i */
13422  jj = mid;
13423  tmp = mid = i; /* value of i after swap */
13424  j--;
13425  }
13426 swap:
13427  c = *i;
13428  *i = *jj;
13429  *jj = c;
13430  i = tmp;
13431  }
13432 
13433  i = (j = mid) + 1;
13434  if ((lo = j - base) <= (hi = max - i)) {
13435  if (lo >= THRESH)
13436  siqst(base, j);
13437  base = i;
13438  lo = hi;
13439  }
13440  else {
13441  if (hi >= THRESH)
13442  siqst(i, max);
13443  max = j;
13444  }
13445  } while (lo >= THRESH);
13446 }
13447 
13448 
13449 
13450 
13451 
13452 /*************************************************************************
13453 * Entry point of int increasing sort
13454 **************************************************************************/
13455 void iintsort(int n, int *base)
13456 {
13457  register int *i;
13458  register int *j;
13459  register int *lo;
13460  register int *hi;
13461  register int *min;
13462  register int c;
13463  int *max;
13464 
13465  if (n <= 1)
13466  return;
13467 
13468  max = base + n;
13469 
13470  if (n >= THRESH) {
13471  iiqst(base, max);
13472  hi = base + THRESH;
13473  }
13474  else
13475  hi = max;
13476 
13477  for (j = lo = base; lo++ < hi;) {
13478  if (*j > *lo)
13479  j = lo;
13480  }
13481  if (j != base) { /* swap j into place */
13482  c = *base;
13483  *base = *j;
13484  *j = c;
13485  }
13486 
13487  for (min = base; (hi = min += 1) < max;) {
13488  while (*(--hi) > *min);
13489  if ((hi += 1) != min) {
13490  for (lo = min + 1; --lo >= min;) {
13491  c = *lo;
13492  for (i = j = lo; (j -= 1) >= hi; i = j)
13493  *i = *j;
13494  *i = c;
13495  }
13496  }
13497  }
13498 }
13499 
13500 
13501 static void iiqst(int *base, int *max)
13502 {
13503  register int *i;
13504  register int *j;
13505  register int *jj;
13506  register int *mid;
13507  register int c;
13508  int *tmp;
13509  int lo;
13510  int hi;
13511 
13512  lo = max - base; /* number of elements as ints */
13513  do {
13514  mid = base + ((unsigned) lo>>1);
13515  if (lo >= MTHRESH) {
13516  j = (*base > *mid ? base : mid);
13517  tmp = max - 1;
13518  if (*j > *tmp) {
13519  j = (j == base ? mid : base); /* switch to first loser */
13520  if (*j < *tmp)
13521  j = tmp;
13522  }
13523 
13524  if (j != mid) { /* SWAP */
13525  c = *mid;
13526  *mid = *j;
13527  *j = c;
13528  }
13529  }
13530 
13531  /* Semi-standard quicksort partitioning/swapping */
13532  for (i = base, j = max - 1;;) {
13533  while (i < mid && *i <= *mid)
13534  i++;
13535  while (j > mid) {
13536  if (*mid <= *j) {
13537  j--;
13538  continue;
13539  }
13540  tmp = i + 1; /* value of i after swap */
13541  if (i == mid) /* j <-> mid, new mid is j */
13542  mid = jj = j;
13543  else /* i <-> j */
13544  jj = j--;
13545  goto swap;
13546  }
13547 
13548  if (i == mid)
13549  break;
13550  else { /* i <-> mid, new mid is i */
13551  jj = mid;
13552  tmp = mid = i; /* value of i after swap */
13553  j--;
13554  }
13555 swap:
13556  c = *i;
13557  *i = *jj;
13558  *jj = c;
13559  i = tmp;
13560  }
13561 
13562  i = (j = mid) + 1;
13563  if ((lo = j - base) <= (hi = max - i)) {
13564  if (lo >= THRESH)
13565  iiqst(base, j);
13566  base = i;
13567  lo = hi;
13568  }
13569  else {
13570  if (hi >= THRESH)
13571  iiqst(i, max);
13572  max = j;
13573  }
13574  } while (lo >= THRESH);
13575 }
13576 
13577 
13578 
13579 
13580 
13581 /*************************************************************************
13582 * Entry point of KeyVal increasing sort, ONLY key part
13583 **************************************************************************/
13584 void ikeysort(int n, KeyValueType *base)
13585 {
13586  register KeyValueType *i;
13587  register KeyValueType *j;
13588  register KeyValueType *lo;
13589  register KeyValueType *hi;
13590  register KeyValueType *min;
13591  register KeyValueType c;
13592  KeyValueType *max;
13593 
13594  if (n <= 1)
13595  return;
13596 
13597  max = base + n;
13598 
13599  if (n >= THRESH) {
13600  keyiqst(base, max);
13601  hi = base + THRESH;
13602  }
13603  else
13604  hi = max;
13605 
13606  for (j = lo = base; lo++ < hi;) {
13607  if (j->key > lo->key)
13608  j = lo;
13609  }
13610  if (j != base) { /* swap j into place */
13611  c = *base;
13612  *base = *j;
13613  *j = c;
13614  }
13615 
13616  for (min = base; (hi = min += 1) < max;) {
13617  while ((--hi)->key > min->key);
13618  if ((hi += 1) != min) {
13619  for (lo = min + 1; --lo >= min;) {
13620  c = *lo;
13621  for (i = j = lo; (j -= 1) >= hi; i = j)
13622  *i = *j;
13623  *i = c;
13624  }
13625  }
13626  }
13627 
13628  /* Sanity check */
13629  {
13630  int i;
13631  for (i=0; i<n-1; i++)
13632  if (base[i].key > base[i+1].key)
13633  printf("Something went wrong!\n");
13634  }
13635 }
13636 
13637 
13638 static void keyiqst(KeyValueType *base, KeyValueType *max)
13639 {
13640  register KeyValueType *i;
13641  register KeyValueType *j;
13642  register KeyValueType *jj;
13643  register KeyValueType *mid;
13644  register KeyValueType c;
13645  KeyValueType *tmp;
13646  int lo;
13647  int hi;
13648 
13649  lo = (max - base)>>1; /* number of elements as KeyValueType */
13650  do {
13651  mid = base + ((unsigned) lo>>1);
13652  if (lo >= MTHRESH) {
13653  j = (base->key > mid->key ? base : mid);
13654  tmp = max - 1;
13655  if (j->key > tmp->key) {
13656  j = (j == base ? mid : base); /* switch to first loser */
13657  if (j->key < tmp->key)
13658  j = tmp;
13659  }
13660 
13661  if (j != mid) { /* SWAP */
13662  c = *mid;
13663  *mid = *j;
13664  *j = c;
13665  }
13666  }
13667 
13668  /* Semi-standard quicksort partitioning/swapping */
13669  for (i = base, j = max - 1;;) {
13670  while (i < mid && i->key <= mid->key)
13671  i++;
13672  while (j > mid) {
13673  if (mid->key <= j->key) {
13674  j--;
13675  continue;
13676  }
13677  tmp = i + 1; /* value of i after swap */
13678  if (i == mid) /* j <-> mid, new mid is j */
13679  mid = jj = j;
13680  else /* i <-> j */
13681  jj = j--;
13682  goto swap;
13683  }
13684 
13685  if (i == mid)
13686  break;
13687  else { /* i <-> mid, new mid is i */
13688  jj = mid;
13689  tmp = mid = i; /* value of i after swap */
13690  j--;
13691  }
13692 swap:
13693  c = *i;
13694  *i = *jj;
13695  *jj = c;
13696  i = tmp;
13697  }
13698 
13699  i = (j = mid) + 1;
13700  if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) {
13701  if (lo >= THRESH)
13702  keyiqst(base, j);
13703  base = i;
13704  lo = hi;
13705  }
13706  else {
13707  if (hi >= THRESH)
13708  keyiqst(i, max);
13709  max = j;
13710  }
13711  } while (lo >= THRESH);
13712 }
13713 
13714 
13715 
13716 
13717 /*************************************************************************
13718 * Entry point of KeyVal increasing sort, BOTH key and val part
13719 **************************************************************************/
13720 void ikeyvalsort(int n, KeyValueType *base)
13721 {
13722  register KeyValueType *i;
13723  register KeyValueType *j;
13724  register KeyValueType *lo;
13725  register KeyValueType *hi;
13726  register KeyValueType *min;
13727  register KeyValueType c;
13728  KeyValueType *max;
13729 
13730  if (n <= 1)
13731  return;
13732 
13733  max = base + n;
13734 
13735  if (n >= THRESH) {
13736  keyvaliqst(base, max);
13737  hi = base + THRESH;
13738  }
13739  else
13740  hi = max;
13741 
13742  for (j = lo = base; lo++ < hi;) {
13743  if ((j->key > lo->key) || (j->key == lo->key && j->val > lo->val))
13744  j = lo;
13745  }
13746  if (j != base) { /* swap j into place */
13747  c = *base;
13748  *base = *j;
13749  *j = c;
13750  }
13751 
13752  for (min = base; (hi = min += 1) < max;) {
13753  while ((--hi)->key > min->key || (hi->key == min->key && hi->val > min->val));
13754  if ((hi += 1) != min) {
13755  for (lo = min + 1; --lo >= min;) {
13756  c = *lo;
13757  for (i = j = lo; (j -= 1) >= hi; i = j)
13758  *i = *j;
13759  *i = c;
13760  }
13761  }
13762  }
13763 }
13764 
13765 
13766 static void keyvaliqst(KeyValueType *base, KeyValueType *max)
13767 {
13768  register KeyValueType *i;
13769  register KeyValueType *j;
13770  register KeyValueType *jj;
13771  register KeyValueType *mid;
13772  register KeyValueType c;
13773  KeyValueType *tmp;
13774  int lo;
13775  int hi;
13776 
13777  lo = (max - base)>>1; /* number of elements as KeyValueType */
13778  do {
13779  mid = base + ((unsigned) lo>>1);
13780  if (lo >= MTHRESH) {
13781  j = (base->key > mid->key || (base->key == mid->key && base->val > mid->val) ? base : mid);
13782  tmp = max - 1;
13783  if (j->key > tmp->key || (j->key == tmp->key && j->val > tmp->val)) {
13784  j = (j == base ? mid : base); /* switch to first loser */
13785  if (j->key < tmp->key || (j->key == tmp->key && j->val < tmp->val))
13786  j = tmp;
13787  }
13788 
13789  if (j != mid) { /* SWAP */
13790  c = *mid;
13791  *mid = *j;
13792  *j = c;
13793  }
13794  }
13795 
13796  /* Semi-standard quicksort partitioning/swapping */
13797  for (i = base, j = max - 1;;) {
13798  while (i < mid && (i->key < mid->key || (i->key == mid->key && i->val <= mid->val)))
13799  i++;
13800  while (j > mid) {
13801  if (mid->key < j->key || (mid->key == j->key && mid->val <= j->val)) {
13802  j--;
13803  continue;
13804  }
13805  tmp = i + 1; /* value of i after swap */
13806  if (i == mid) /* j <-> mid, new mid is j */
13807  mid = jj = j;
13808  else /* i <-> j */
13809  jj = j--;
13810  goto swap;
13811  }
13812 
13813  if (i == mid)
13814  break;
13815  else { /* i <-> mid, new mid is i */
13816  jj = mid;
13817  tmp = mid = i; /* value of i after swap */
13818  j--;
13819  }
13820 swap:
13821  c = *i;
13822  *i = *jj;
13823  *jj = c;
13824  i = tmp;
13825  }
13826 
13827  i = (j = mid) + 1;
13828  if ((lo = (j - base)>>1) <= (hi = (max - i)>>1)) {
13829  if (lo >= THRESH)
13830  keyvaliqst(base, j);
13831  base = i;
13832  lo = hi;
13833  }
13834  else {
13835  if (hi >= THRESH)
13836  keyvaliqst(i, max);
13837  max = j;
13838  }
13839  } while (lo >= THRESH);
13840 }
13841 /*
13842  * Copyright 1997, Regents of the University of Minnesota
13843  *
13844  * ometis.c
13845  *
13846  * This file contains the top level routines for the multilevel recursive
13847  * bisection algorithm PMETIS.
13848  *
13849  * Started 7/24/97
13850  * George
13851  *
13852  * $Id$
13853  *
13854  */
13855 
13856 
13857 
13858 
13859 /*************************************************************************
13860 * This function is the entry point for OEMETIS
13861 **************************************************************************/
13862 void METIS_EdgeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
13863  idxtype *perm, idxtype *iperm)
13864 {
13865  int i;
13866  GraphType graph;
13867  CtrlType ctrl;
13868 
13869  if (*numflag == 1)
13870  Change2CNumbering(*nvtxs, xadj, adjncy);
13871 
13872  SetUpGraph(&graph, OP_OEMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0);
13873 
13874  if (options[0] == 0) { /* Use the default parameters */
13875  ctrl.CType = OEMETIS_CTYPE;
13876  ctrl.IType = OEMETIS_ITYPE;
13877  ctrl.RType = OEMETIS_RTYPE;
13878  ctrl.dbglvl = OEMETIS_DBGLVL;
13879  }
13880  else {
13881  ctrl.CType = options[OPTION_CTYPE];
13882  ctrl.IType = options[OPTION_ITYPE];
13883  ctrl.RType = options[OPTION_RTYPE];
13884  ctrl.dbglvl = options[OPTION_DBGLVL];
13885  }
13886  ctrl.oflags = 0;
13887  ctrl.pfactor = -1;
13888  ctrl.nseps = 1;
13889 
13890  ctrl.optype = OP_OEMETIS;
13891  ctrl.CoarsenTo = 20;
13892  ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo);
13893 
13894  InitRandom(-1);
13895 
13896  AllocateWorkSpace(&ctrl, &graph, 2);
13897 
13898  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
13899  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
13900 
13901  MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs);
13902 
13903  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
13904  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
13905 
13906  for (i=0; i<*nvtxs; i++)
13907  perm[iperm[i]] = i;
13908 
13909  FreeWorkSpace(&ctrl, &graph);
13910 
13911  if (*numflag == 1)
13912  Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
13913 }
13914 
13915 
13916 /*************************************************************************
13917 * This function is the entry point for ONCMETIS
13918 **************************************************************************/
13919 void METIS_NodeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options,
13920  idxtype *perm, idxtype *iperm)
13921 {
13922  int i, ii, j, l;
13923  GraphType graph;
13924  CtrlType ctrl;
13925  idxtype *cptr, *cind, *piperm;
13926 
13927  if (*numflag == 1)
13928  Change2CNumbering(*nvtxs, xadj, adjncy);
13929 
13930  if (options[0] == 0) { /* Use the default parameters */
13931  ctrl.CType = ONMETIS_CTYPE;
13932  ctrl.IType = ONMETIS_ITYPE;
13933  ctrl.RType = ONMETIS_RTYPE;
13934  ctrl.dbglvl = ONMETIS_DBGLVL;
13935  ctrl.oflags = ONMETIS_OFLAGS;
13936  ctrl.pfactor = ONMETIS_PFACTOR;
13937  ctrl.nseps = ONMETIS_NSEPS;
13938  }
13939  else {
13940  ctrl.CType = options[OPTION_CTYPE];
13941  ctrl.IType = options[OPTION_ITYPE];
13942  ctrl.RType = options[OPTION_RTYPE];
13943  ctrl.dbglvl = options[OPTION_DBGLVL];
13944  ctrl.oflags = options[OPTION_OFLAGS];
13945  ctrl.pfactor = options[OPTION_PFACTOR];
13946  ctrl.nseps = options[OPTION_NSEPS];
13947  }
13948  if (ctrl.nseps < 1)
13949  ctrl.nseps = 1;
13950 
13951  ctrl.optype = OP_ONMETIS;
13952  ctrl.CoarsenTo = 100;
13953 
13954  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
13955  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
13956 
13957  InitRandom(-1);
13958 
13959  if (ctrl.pfactor > 0) {
13960  /*============================================================
13961  * Prune the dense columns
13962  ==============================================================*/
13963  piperm = idxmalloc(*nvtxs, "ONMETIS: piperm");
13964 
13965  PruneGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, piperm, (float)(0.1*ctrl.pfactor));
13966  }
13967  else if (ctrl.oflags&OFLAG_COMPRESS) {
13968  /*============================================================
13969  * Compress the graph
13970  ==============================================================*/
13971  cptr = idxmalloc(*nvtxs+1, "ONMETIS: cptr");
13972  cind = idxmalloc(*nvtxs, "ONMETIS: cind");
13973 
13974  CompressGraph(&ctrl, &graph, *nvtxs, xadj, adjncy, cptr, cind);
13975 
13976  if (graph.nvtxs >= COMPRESSION_FRACTION*(*nvtxs)) {
13977  ctrl.oflags--; /* We actually performed no compression */
13978  GKfree((void **) &cptr, &cind, LTERM);
13979  }
13980  else if (2*graph.nvtxs < *nvtxs && ctrl.nseps == 1)
13981  ctrl.nseps = 2;
13982  }
13983  else {
13984  SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, NULL, NULL, 0);
13985  }
13986 
13987 
13988  /*=============================================================
13989  * Do the nested dissection ordering
13990  --=============================================================*/
13991  ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo);
13992  AllocateWorkSpace(&ctrl, &graph, 2);
13993 
13994  if (ctrl.oflags&OFLAG_CCMP)
13995  MlevelNestedDissectionCC(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs);
13996  else
13997  MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, graph.nvtxs);
13998 
13999  FreeWorkSpace(&ctrl, &graph);
14000 
14001  if (ctrl.pfactor > 0) { /* Order any prunned vertices */
14002  if (graph.nvtxs < *nvtxs) {
14003  idxcopy(graph.nvtxs, iperm, perm); /* Use perm as an auxiliary array */
14004  for (i=0; i<graph.nvtxs; i++)
14005  iperm[piperm[i]] = perm[i];
14006  for (i=graph.nvtxs; i<*nvtxs; i++)
14007  iperm[piperm[i]] = i;
14008  }
14009 
14010  GKfree((void **) &piperm, LTERM);
14011  }
14012  else if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */
14013  if (graph.nvtxs < COMPRESSION_FRACTION*(*nvtxs)) {
14014  /* construct perm from iperm */
14015  for (i=0; i<graph.nvtxs; i++)
14016  perm[iperm[i]] = i;
14017  for (l=ii=0; ii<graph.nvtxs; ii++) {
14018  i = perm[ii];
14019  for (j=cptr[i]; j<cptr[i+1]; j++)
14020  iperm[cind[j]] = l++;
14021  }
14022  }
14023 
14024  GKfree((void **) &cptr, &cind, LTERM);
14025  }
14026 
14027 
14028  for (i=0; i<*nvtxs; i++)
14029  perm[iperm[i]] = i;
14030 
14031  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
14032  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
14033 
14034  if (*numflag == 1)
14035  Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
14036 
14037 }
14038 
14039 
14040 /*************************************************************************
14041 * This function is the entry point for ONWMETIS. It requires weights on the
14042 * vertices. It is for the case that the matrix has been pre-compressed.
14043 **************************************************************************/
14044 void METIS_NodeWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag,
14045  int *options, idxtype *perm, idxtype *iperm)
14046 {
14047  int i;
14048  GraphType graph;
14049  CtrlType ctrl;
14050 
14051  if (*numflag == 1)
14052  Change2CNumbering(*nvtxs, xadj, adjncy);
14053 
14054  SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, NULL, 2);
14055 
14056  if (options[0] == 0) { /* Use the default parameters */
14057  ctrl.CType = ONMETIS_CTYPE;
14058  ctrl.IType = ONMETIS_ITYPE;
14059  ctrl.RType = ONMETIS_RTYPE;
14060  ctrl.dbglvl = ONMETIS_DBGLVL;
14061  }
14062  else {
14063  ctrl.CType = options[OPTION_CTYPE];
14064  ctrl.IType = options[OPTION_ITYPE];
14065  ctrl.RType = options[OPTION_RTYPE];
14066  ctrl.dbglvl = options[OPTION_DBGLVL];
14067  }
14068 
14069  ctrl.oflags = OFLAG_COMPRESS;
14070  ctrl.pfactor = 0;
14071  ctrl.nseps = 2;
14072  ctrl.optype = OP_ONMETIS;
14073  ctrl.CoarsenTo = 100;
14074  ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo);
14075 
14076  InitRandom(-1);
14077 
14078  AllocateWorkSpace(&ctrl, &graph, 2);
14079 
14080  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
14081  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
14082 
14083  MlevelNestedDissection(&ctrl, &graph, iperm, ORDER_UNBALANCE_FRACTION, *nvtxs);
14084 
14085  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
14086  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
14087 
14088  for (i=0; i<*nvtxs; i++)
14089  perm[iperm[i]] = i;
14090 
14091  FreeWorkSpace(&ctrl, &graph);
14092 
14093  if (*numflag == 1)
14094  Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
14095 }
14096 
14097 
14098 
14099 
14100 /*************************************************************************
14101 * This function takes a graph and produces a bisection of it
14102 **************************************************************************/
14103 void MlevelNestedDissection(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx)
14104 {
14105  int i, nvtxs, nbnd, tvwgt, tpwgts2[2];
14106  idxtype *label, *bndind;
14107  GraphType lgraph, rgraph;
14108 
14109  nvtxs = graph->nvtxs;
14110 
14111  /* Determine the weights of the partitions */
14112  tvwgt = idxsum(nvtxs, graph->vwgt);
14113  tpwgts2[0] = tvwgt/2;
14114  tpwgts2[1] = tvwgt-tpwgts2[0];
14115 
14116  switch (ctrl->optype) {
14117  case OP_OEMETIS:
14118  MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor);
14119 
14120  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr));
14121  ConstructMinCoverSeparator(ctrl, graph, ubfactor);
14122  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr));
14123 
14124  break;
14125  case OP_ONMETIS:
14126  MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor);
14127 
14128  IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
14129 
14130  break;
14131  }
14132 
14133  /* Order the nodes in the separator */
14134  nbnd = graph->nbnd;
14135  bndind = graph->bndind;
14136  label = graph->label;
14137  for (i=0; i<nbnd; i++)
14138  order[label[bndind[i]]] = --lastvtx;
14139 
14140  SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);
14141 
14142  /* Free the memory of the top level graph */
14143  GKfree((void **) &graph->gdata, (void **) &graph->rdata,
14144  (void **) &graph->label, LTERM);
14145 
14146  if (rgraph.nvtxs > MMDSWITCH)
14147  MlevelNestedDissection(ctrl, &rgraph, order, ubfactor, lastvtx);
14148  else {
14149  MMDOrder(ctrl, &rgraph, order, lastvtx);
14150  GKfree((void **) &rgraph.gdata, (void **) &rgraph.rdata,
14151  (void **) &rgraph.label, LTERM);
14152  }
14153  if (lgraph.nvtxs > MMDSWITCH)
14154  MlevelNestedDissection(ctrl, &lgraph, order, ubfactor, lastvtx-rgraph.nvtxs);
14155  else {
14156  MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs);
14157  GKfree((void **) &lgraph.gdata, (void **) &lgraph.rdata,
14158  (void **) &lgraph.label, LTERM);
14159  }
14160 }
14161 
14162 
14163 /*************************************************************************
14164 * This function takes a graph and produces a bisection of it
14165 **************************************************************************/
14166 void MlevelNestedDissectionCC(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx)
14167 {
14168  int i, nvtxs, nbnd, tvwgt, tpwgts2[2], nsgraphs, ncmps, rnvtxs;
14169  idxtype *label, *bndind;
14170  idxtype *cptr, *cind;
14171  GraphType *sgraphs;
14172 
14173  nvtxs = graph->nvtxs;
14174 
14175  /* Determine the weights of the partitions */
14176  tvwgt = idxsum(nvtxs, graph->vwgt);
14177  tpwgts2[0] = tvwgt/2;
14178  tpwgts2[1] = tvwgt-tpwgts2[0];
14179 
14180  MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor);
14181  IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
14182 
14183  /* Order the nodes in the separator */
14184  nbnd = graph->nbnd;
14185  bndind = graph->bndind;
14186  label = graph->label;
14187  for (i=0; i<nbnd; i++)
14188  order[label[bndind[i]]] = --lastvtx;
14189 
14190  cptr = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cptr");
14191  cind = idxmalloc(nvtxs, "MlevelNestedDissectionCC: cind");
14192  ncmps = FindComponents(ctrl, graph, cptr, cind);
14193 
14194 /*
14195  if (ncmps > 2)
14196  printf("[%5d] has %3d components\n", nvtxs, ncmps);
14197 */
14198 
14199  sgraphs = (GraphType *)GKmalloc(ncmps*sizeof(GraphType), "MlevelNestedDissectionCC: sgraphs");
14200 
14201  nsgraphs = SplitGraphOrderCC(ctrl, graph, sgraphs, ncmps, cptr, cind);
14202 
14203  GKfree((void **) &cptr, (void **) &cind, LTERM);
14204 
14205  /* Free the memory of the top level graph */
14206  GKfree((void **) &graph->gdata, (void **) &graph->rdata,
14207  (void **) &graph->label, LTERM);
14208 
14209  /* Go and process the subgraphs */
14210  for (rnvtxs=i=0; i<nsgraphs; i++) {
14211  if (sgraphs[i].adjwgt == NULL) {
14212  MMDOrder(ctrl, sgraphs+i, order, lastvtx-rnvtxs);
14213  GKfree((void **) &sgraphs[i].gdata, (void **) &sgraphs[i].label, LTERM);
14214  }
14215  else {
14216  MlevelNestedDissectionCC(ctrl, sgraphs+i, order, ubfactor, lastvtx-rnvtxs);
14217  }
14218  rnvtxs += sgraphs[i].nvtxs;
14219  }
14220 
14221  free(sgraphs);
14222 }
14223 
14224 
14225 
14226 /*************************************************************************
14227 * This function performs multilevel bisection. It performs multiple
14228 * bisections and selects the best.
14229 **************************************************************************/
14230 void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
14231 {
14232  int i, nvtxs, cnvtxs, mincut;
14233  GraphType *cgraph;
14234  idxtype *bestwhere;
14235 
14236  if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->oflags&OFLAG_COMPRESS ? 1000 : 2000)) {
14237  MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor);
14238  return;
14239  }
14240 
14241  nvtxs = graph->nvtxs;
14242 
14243  if (ctrl->oflags&OFLAG_COMPRESS) { /* Multiple separators at the original graph */
14244  bestwhere = idxmalloc(nvtxs, "MlevelNodeBisection2: bestwhere");
14245  mincut = nvtxs;
14246 
14247  for (i=ctrl->nseps; i>0; i--) {
14248  MlevelNodeBisection(ctrl, graph, tpwgts, ubfactor);
14249 
14250  /* printf("%5d ", cgraph->mincut); */
14251 
14252  if (graph->mincut < mincut) {
14253  mincut = graph->mincut;
14254  idxcopy(nvtxs, graph->where, bestwhere);
14255  }
14256 
14257  GKfree((void **) &graph->rdata, LTERM);
14258 
14259  if (mincut == 0)
14260  break;
14261  }
14262  /* printf("[%5d]\n", mincut); */
14263 
14264  Allocate2WayNodePartitionMemory(ctrl, graph);
14265  idxcopy(nvtxs, bestwhere, graph->where);
14266  free(bestwhere);
14267 
14268  Compute2WayNodePartitionParams(ctrl, graph);
14269  }
14270  else { /* Coarsen it a bit */
14271  ctrl->CoarsenTo = nvtxs-1;
14272 
14273  cgraph = Coarsen2Way(ctrl, graph);
14274 
14275  cnvtxs = cgraph->nvtxs;
14276 
14277  bestwhere = idxmalloc(cnvtxs, "MlevelNodeBisection2: bestwhere");
14278  mincut = nvtxs;
14279 
14280  for (i=ctrl->nseps; i>0; i--) {
14281  ctrl->CType += 20; /* This is a hack. Look at coarsen.c */
14282  MlevelNodeBisection(ctrl, cgraph, tpwgts, ubfactor);
14283 
14284  /* printf("%5d ", cgraph->mincut); */
14285 
14286  if (cgraph->mincut < mincut) {
14287  mincut = cgraph->mincut;
14288  idxcopy(cnvtxs, cgraph->where, bestwhere);
14289  }
14290 
14291  GKfree((void **) &cgraph->rdata, LTERM);
14292 
14293  if (mincut == 0)
14294  break;
14295  }
14296  /* printf("[%5d]\n", mincut); */
14297 
14298  Allocate2WayNodePartitionMemory(ctrl, cgraph);
14299  idxcopy(cnvtxs, bestwhere, cgraph->where);
14300  free(bestwhere);
14301 
14302  Compute2WayNodePartitionParams(ctrl, cgraph);
14303 
14304  Refine2WayNode(ctrl, graph, cgraph, ubfactor);
14305  }
14306 
14307 }
14308 
14309 /*************************************************************************
14310 * This function performs multilevel bisection
14311 **************************************************************************/
14312 void MlevelNodeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
14313 {
14314  GraphType *cgraph;
14315 
14316  ctrl->CoarsenTo = graph->nvtxs/8;
14317  if (ctrl->CoarsenTo > 100)
14318  ctrl->CoarsenTo = 100;
14319  else if (ctrl->CoarsenTo < 40)
14320  ctrl->CoarsenTo = 40;
14321  ctrl->maxvwgt = 1.5*((tpwgts[0]+tpwgts[1])/ctrl->CoarsenTo);
14322 
14323  cgraph = Coarsen2Way(ctrl, graph);
14324 
14325  switch (ctrl->IType) {
14326  case IPART_GGPKL:
14327  Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor);
14328 
14329  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SepTmr));
14330 
14331  Compute2WayPartitionParams(ctrl, cgraph);
14332  ConstructSeparator(ctrl, cgraph, ubfactor);
14333 
14334  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SepTmr));
14335  break;
14336  case IPART_GGPKLNODE:
14337  InitSeparator(ctrl, cgraph, ubfactor);
14338  break;
14339  }
14340 
14341  Refine2WayNode(ctrl, graph, cgraph, ubfactor);
14342 
14343 }
14344 
14345 
14346 
14347 
14348 /*************************************************************************
14349 * This function takes a graph and a bisection and splits it into two graphs.
14350 * This function relies on the fact that adjwgt is all equal to 1.
14351 **************************************************************************/
14352 void SplitGraphOrder(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph)
14353 {
14354  int i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3];
14355  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind;
14356  idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2];
14357  idxtype *rename;
14358  idxtype *auxadjncy;
14359 
14360  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr));
14361 
14362  nvtxs = graph->nvtxs;
14363  xadj = graph->xadj;
14364  vwgt = graph->vwgt;
14365  adjncy = graph->adjncy;
14366  adjwgt = graph->adjwgt;
14367  adjwgtsum = graph->adjwgtsum;
14368  label = graph->label;
14369  where = graph->where;
14370  bndptr = graph->bndptr;
14371  bndind = graph->bndind;
14372  ASSERT(bndptr != NULL);
14373 
14374  rename = idxwspacemalloc(ctrl, nvtxs);
14375 
14376  snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0;
14377  for (i=0; i<nvtxs; i++) {
14378  k = where[i];
14379  rename[i] = snvtxs[k]++;
14380  snedges[k] += xadj[i+1]-xadj[i];
14381  }
14382 
14383  SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]);
14384  sxadj[0] = lgraph->xadj;
14385  svwgt[0] = lgraph->vwgt;
14386  sadjwgtsum[0] = lgraph->adjwgtsum;
14387  sadjncy[0] = lgraph->adjncy;
14388  sadjwgt[0] = lgraph->adjwgt;
14389  slabel[0] = lgraph->label;
14390 
14391  SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]);
14392  sxadj[1] = rgraph->xadj;
14393  svwgt[1] = rgraph->vwgt;
14394  sadjwgtsum[1] = rgraph->adjwgtsum;
14395  sadjncy[1] = rgraph->adjncy;
14396  sadjwgt[1] = rgraph->adjwgt;
14397  slabel[1] = rgraph->label;
14398 
14399  /* Go and use bndptr to also mark the boundary nodes in the two partitions */
14400  for (ii=0; ii<graph->nbnd; ii++) {
14401  i = bndind[ii];
14402  for (j=xadj[i]; j<xadj[i+1]; j++)
14403  bndptr[adjncy[j]] = 1;
14404  }
14405 
14406  snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
14407  sxadj[0][0] = sxadj[1][0] = 0;
14408  for (i=0; i<nvtxs; i++) {
14409  if ((mypart = where[i]) == 2)
14410  continue;
14411 
14412  istart = xadj[i];
14413  iend = xadj[i+1];
14414  if (bndptr[i] == -1) { /* This is an interior vertex */
14415  auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;
14416  for(j=istart; j<iend; j++)
14417  auxadjncy[j] = adjncy[j];
14418  snedges[mypart] += iend-istart;
14419  }
14420  else {
14421  auxadjncy = sadjncy[mypart];
14422  l = snedges[mypart];
14423  for (j=istart; j<iend; j++) {
14424  k = adjncy[j];
14425  if (where[k] == mypart)
14426  auxadjncy[l++] = k;
14427  }
14428  snedges[mypart] = l;
14429  }
14430 
14431  svwgt[mypart][snvtxs[mypart]] = vwgt[i];
14432  sadjwgtsum[mypart][snvtxs[mypart]] = snedges[mypart]-sxadj[mypart][snvtxs[mypart]];
14433  slabel[mypart][snvtxs[mypart]] = label[i];
14434  sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];
14435  }
14436 
14437  for (mypart=0; mypart<2; mypart++) {
14438  iend = snedges[mypart];
14439  idxset(iend, 1, sadjwgt[mypart]);
14440 
14441  auxadjncy = sadjncy[mypart];
14442  for (i=0; i<iend; i++)
14443  auxadjncy[i] = rename[auxadjncy[i]];
14444  }
14445 
14446  lgraph->nvtxs = snvtxs[0];
14447  lgraph->nedges = snedges[0];
14448  rgraph->nvtxs = snvtxs[1];
14449  rgraph->nedges = snedges[1];
14450 
14451  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr));
14452 
14453  idxwspacefree(ctrl, nvtxs);
14454 
14455 }
14456 
14457 /*************************************************************************
14458 * This function uses MMD to order the graph. The vertices are numbered
14459 * from lastvtx downwards
14460 **************************************************************************/
14461 void MMDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx)
14462 {
14463  int i, k, nvtxs, nofsub, firstvtx;
14464  idxtype *xadj, *adjncy, *label;
14465  idxtype *perm, *iperm, *head, *qsize, *list, *marker;
14466 
14467  nvtxs = graph->nvtxs;
14468  xadj = graph->xadj;
14469  adjncy = graph->adjncy;
14470 
14471  /* Relabel the vertices so that it starts from 1 */
14472  k = xadj[nvtxs];
14473  for (i=0; i<k; i++)
14474  adjncy[i]++;
14475  for (i=0; i<nvtxs+1; i++)
14476  xadj[i]++;
14477 
14478  perm = idxmalloc(6*(nvtxs+5), "MMDOrder: perm");
14479  iperm = perm + nvtxs + 5;
14480  head = iperm + nvtxs + 5;
14481  qsize = head + nvtxs + 5;
14482  list = qsize + nvtxs + 5;
14483  marker = list + nvtxs + 5;
14484 
14485  genmmd(nvtxs, xadj, adjncy, iperm, perm, 1, head, qsize, list, marker, MAXIDX, &nofsub);
14486 
14487  label = graph->label;
14488  firstvtx = lastvtx-nvtxs;
14489  for (i=0; i<nvtxs; i++)
14490  order[label[i]] = firstvtx+iperm[i]-1;
14491 
14492  free(perm);
14493 
14494  /* Relabel the vertices so that it starts from 0 */
14495  for (i=0; i<nvtxs+1; i++)
14496  xadj[i]--;
14497  k = xadj[nvtxs];
14498  for (i=0; i<k; i++)
14499  adjncy[i]--;
14500 }
14501 
14502 
14503 /*************************************************************************
14504 * This function takes a graph and a bisection and splits it into two graphs.
14505 * It relies on the fact that adjwgt is all set to 1.
14506 **************************************************************************/
14507 int SplitGraphOrderCC(CtrlType *ctrl, GraphType *graph, GraphType *sgraphs, int ncmps, idxtype *cptr, idxtype *cind)
14508 {
14509  int i, ii, iii, j, k, l, istart, iend, nvtxs, snvtxs, snedges;
14510  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr, *bndind;
14511  idxtype *sxadj, *svwgt, *sadjncy, *sadjwgt, *sadjwgtsum, *slabel;
14512  idxtype *rename;
14513  idxtype *auxadjncy, *auxadjwgt;
14514 
14515  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr));
14516 
14517  nvtxs = graph->nvtxs;
14518  xadj = graph->xadj;
14519  vwgt = graph->vwgt;
14520  adjncy = graph->adjncy;
14521  adjwgt = graph->adjwgt;
14522  adjwgtsum = graph->adjwgtsum;
14523  label = graph->label;
14524  where = graph->where;
14525  bndptr = graph->bndptr;
14526  bndind = graph->bndind;
14527  ASSERT(bndptr != NULL);
14528 
14529  /* Go and use bndptr to also mark the boundary nodes in the two partitions */
14530  for (ii=0; ii<graph->nbnd; ii++) {
14531  i = bndind[ii];
14532  for (j=xadj[i]; j<xadj[i+1]; j++)
14533  bndptr[adjncy[j]] = 1;
14534  }
14535 
14536  rename = idxwspacemalloc(ctrl, nvtxs);
14537 
14538  /* Go and split the graph a component at a time */
14539  for (iii=0; iii<ncmps; iii++) {
14540  RandomPermute(cptr[iii+1]-cptr[iii], cind+cptr[iii], 0);
14541  snvtxs = snedges = 0;
14542  for (j=cptr[iii]; j<cptr[iii+1]; j++) {
14543  i = cind[j];
14544  rename[i] = snvtxs++;
14545  snedges += xadj[i+1]-xadj[i];
14546  }
14547 
14548  SetUpSplitGraph(graph, sgraphs+iii, snvtxs, snedges);
14549  sxadj = sgraphs[iii].xadj;
14550  svwgt = sgraphs[iii].vwgt;
14551  sadjwgtsum = sgraphs[iii].adjwgtsum;
14552  sadjncy = sgraphs[iii].adjncy;
14553  sadjwgt = sgraphs[iii].adjwgt;
14554  slabel = sgraphs[iii].label;
14555 
14556  snvtxs = snedges = sxadj[0] = 0;
14557  for (ii=cptr[iii]; ii<cptr[iii+1]; ii++) {
14558  i = cind[ii];
14559 
14560  istart = xadj[i];
14561  iend = xadj[i+1];
14562  if (bndptr[i] == -1) { /* This is an interior vertex */
14563  auxadjncy = sadjncy + snedges - istart;
14564  auxadjwgt = sadjwgt + snedges - istart;
14565  for(j=istart; j<iend; j++)
14566  auxadjncy[j] = adjncy[j];
14567  snedges += iend-istart;
14568  }
14569  else {
14570  l = snedges;
14571  for (j=istart; j<iend; j++) {
14572  k = adjncy[j];
14573  if (where[k] != 2)
14574  sadjncy[l++] = k;
14575  }
14576  snedges = l;
14577  }
14578 
14579  svwgt[snvtxs] = vwgt[i];
14580  sadjwgtsum[snvtxs] = snedges-sxadj[snvtxs];
14581  slabel[snvtxs] = label[i];
14582  sxadj[++snvtxs] = snedges;
14583  }
14584 
14585  idxset(snedges, 1, sadjwgt);
14586  for (i=0; i<snedges; i++)
14587  sadjncy[i] = rename[sadjncy[i]];
14588 
14589  sgraphs[iii].nvtxs = snvtxs;
14590  sgraphs[iii].nedges = snedges;
14591  sgraphs[iii].ncon = 1;
14592 
14593  if (snvtxs < MMDSWITCH)
14594  sgraphs[iii].adjwgt = NULL; /* A marker to call MMD on the driver */
14595  }
14596 
14597  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr));
14598 
14599  idxwspacefree(ctrl, nvtxs);
14600 
14601  return ncmps;
14602 
14603 }
14604 
14605 
14606 
14607 
14608 
14609 /*
14610  * Copyright 1997, Regents of the University of Minnesota
14611  *
14612  * parmetis.c
14613  *
14614  * This file contains top level routines that are used by ParMETIS
14615  *
14616  * Started 10/14/97
14617  * George
14618  *
14619  * $Id$
14620  *
14621  */
14622 
14623 
14624 
14625 
14626 /*************************************************************************
14627 * This function is the entry point for KMETIS with seed specification
14628 * in options[7]
14629 **************************************************************************/
14630 void METIS_PartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
14631  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
14632  int *options, int *edgecut, idxtype *part)
14633 {
14634  int i;
14635  float *tpwgts;
14636 
14637  tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
14638  for (i=0; i<*nparts; i++)
14639  tpwgts[i] = 1.0/(1.0*(*nparts));
14640 
14641  METIS_WPartGraphKway2(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
14642  tpwgts, options, edgecut, part);
14643 
14644  free(tpwgts);
14645 }
14646 
14647 
14648 /*************************************************************************
14649 * This function is the entry point for KWMETIS with seed specification
14650 * in options[7]
14651 **************************************************************************/
14652 void METIS_WPartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
14653  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
14654  float *tpwgts, int *options, int *edgecut, idxtype *part)
14655 {
14656  GraphType graph;
14657  CtrlType ctrl;
14658 
14659  if (*numflag == 1)
14660  Change2CNumbering(*nvtxs, xadj, adjncy);
14661 
14662  SetUpGraph(&graph, OP_KMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag);
14663 
14664  if (options[0] == 0) { /* Use the default parameters */
14665  ctrl.CType = KMETIS_CTYPE;
14666  ctrl.IType = KMETIS_ITYPE;
14667  ctrl.RType = KMETIS_RTYPE;
14668  ctrl.dbglvl = KMETIS_DBGLVL;
14669  }
14670  else {
14671  ctrl.CType = options[OPTION_CTYPE];
14672  ctrl.IType = options[OPTION_ITYPE];
14673  ctrl.RType = options[OPTION_RTYPE];
14674  ctrl.dbglvl = options[OPTION_DBGLVL];
14675  }
14676  ctrl.optype = OP_KMETIS;
14677  ctrl.CoarsenTo = 20*(*nparts);
14678  ctrl.maxvwgt = 1.5*((graph.vwgt ? idxsum(*nvtxs, graph.vwgt) : (*nvtxs))/ctrl.CoarsenTo);
14679 
14680  InitRandom(options[7]);
14681 
14682  AllocateWorkSpace(&ctrl, &graph, *nparts);
14683 
14684  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
14685  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
14686 
14687  *edgecut = MlevelKWayPartitioning(&ctrl, &graph, *nparts, part, tpwgts, 1.03);
14688 
14689  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
14690  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
14691 
14692  FreeWorkSpace(&ctrl, &graph);
14693 
14694  if (*numflag == 1)
14695  Change2FNumbering(*nvtxs, xadj, adjncy, part);
14696 }
14697 
14698 
14699 /*************************************************************************
14700 * This function is the entry point for the node ND code for ParMETIS
14701 **************************************************************************/
14702 void METIS_NodeNDP(int nvtxs, idxtype *xadj, idxtype *adjncy, int npes,
14703  int *options, idxtype *perm, idxtype *iperm, idxtype *sizes)
14704 {
14705  int i, ii, j, l;
14706  GraphType graph;
14707  CtrlType ctrl;
14708  idxtype *cptr, *cind;
14709 
14710  if (options[0] == 0) { /* Use the default parameters */
14711  ctrl.CType = ONMETIS_CTYPE;
14712  ctrl.IType = ONMETIS_ITYPE;
14713  ctrl.RType = ONMETIS_RTYPE;
14714  ctrl.dbglvl = ONMETIS_DBGLVL;
14715  ctrl.oflags = ONMETIS_OFLAGS;
14716  ctrl.pfactor = ONMETIS_PFACTOR;
14717  ctrl.nseps = ONMETIS_NSEPS;
14718  }
14719  else {
14720  ctrl.CType = options[OPTION_CTYPE];
14721  ctrl.IType = options[OPTION_ITYPE];
14722  ctrl.RType = options[OPTION_RTYPE];
14723  ctrl.dbglvl = options[OPTION_DBGLVL];
14724  ctrl.oflags = options[OPTION_OFLAGS];
14725  ctrl.pfactor = options[OPTION_PFACTOR];
14726  ctrl.nseps = options[OPTION_NSEPS];
14727  }
14728  if (ctrl.nseps < 1)
14729  ctrl.nseps = 1;
14730 
14731  ctrl.optype = OP_ONMETIS;
14732  ctrl.CoarsenTo = 100;
14733 
14734  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
14735  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
14736 
14737  InitRandom(-1);
14738 
14739  if (ctrl.oflags&OFLAG_COMPRESS) {
14740  /*============================================================
14741  * Compress the graph
14742  ==============================================================*/
14743  cptr = idxmalloc(nvtxs+1, "ONMETIS: cptr");
14744  cind = idxmalloc(nvtxs, "ONMETIS: cind");
14745 
14746  CompressGraph(&ctrl, &graph, nvtxs, xadj, adjncy, cptr, cind);
14747 
14748  if (graph.nvtxs >= COMPRESSION_FRACTION*(nvtxs)) {
14749  ctrl.oflags--; /* We actually performed no compression */
14750  GKfree((void **) &cptr, &cind, LTERM);
14751  }
14752  else if (2*graph.nvtxs < nvtxs && ctrl.nseps == 1)
14753  ctrl.nseps = 2;
14754  }
14755  else {
14756  SetUpGraph(&graph, OP_ONMETIS, nvtxs, 1, xadj, adjncy, NULL, NULL, 0);
14757  }
14758 
14759 
14760  /*=============================================================
14761  * Do the nested dissection ordering
14762  --=============================================================*/
14763  ctrl.maxvwgt = 1.5*(idxsum(graph.nvtxs, graph.vwgt)/ctrl.CoarsenTo);
14764  AllocateWorkSpace(&ctrl, &graph, 2);
14765 
14766  idxset(2*npes-1, 0, sizes);
14767  MlevelNestedDissectionP(&ctrl, &graph, iperm, graph.nvtxs, npes, 0, sizes);
14768 
14769  FreeWorkSpace(&ctrl, &graph);
14770 
14771  if (ctrl.oflags&OFLAG_COMPRESS) { /* Uncompress the ordering */
14772  if (graph.nvtxs < COMPRESSION_FRACTION*(nvtxs)) {
14773  /* construct perm from iperm */
14774  for (i=0; i<graph.nvtxs; i++)
14775  perm[iperm[i]] = i;
14776  for (l=ii=0; ii<graph.nvtxs; ii++) {
14777  i = perm[ii];
14778  for (j=cptr[i]; j<cptr[i+1]; j++)
14779  iperm[cind[j]] = l++;
14780  }
14781  }
14782 
14783  GKfree((void **) &cptr, (void **) &cind, LTERM);
14784  }
14785 
14786 
14787  for (i=0; i<nvtxs; i++)
14788  perm[iperm[i]] = i;
14789 
14790  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
14791  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
14792 
14793 }
14794 
14795 
14796 
14797 /*************************************************************************
14798 * This function takes a graph and produces a bisection of it
14799 **************************************************************************/
14800 void MlevelNestedDissectionP(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx,
14801  int npes, int cpos, idxtype *sizes)
14802 {
14803  int i, nvtxs, nbnd, tvwgt, tpwgts2[2];
14804  idxtype *label, *bndind;
14805  GraphType lgraph, rgraph;
14806  float ubfactor;
14807 
14808  nvtxs = graph->nvtxs;
14809 
14810  if (nvtxs == 0) {
14811  GKfree((void **) &graph->gdata, (void **) &graph->rdata,
14812  (void **) &graph->label, LTERM);
14813  return;
14814  }
14815 
14816  /* Determine the weights of the partitions */
14817  tvwgt = idxsum(nvtxs, graph->vwgt);
14818  tpwgts2[0] = tvwgt/2;
14819  tpwgts2[1] = tvwgt-tpwgts2[0];
14820 
14821  if (cpos >= npes-1)
14822  ubfactor = ORDER_UNBALANCE_FRACTION;
14823  else
14824  ubfactor = 1.05;
14825 
14826 
14827  MlevelNodeBisectionMultiple(ctrl, graph, tpwgts2, ubfactor);
14828 
14829  IFSET(ctrl->dbglvl, DBG_SEPINFO, printf("Nvtxs: %6d, [%6d %6d %6d]\n", graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
14830 
14831  if (cpos < npes-1) {
14832  sizes[2*npes-2-cpos] = graph->pwgts[2];
14833  sizes[2*npes-2-(2*cpos+1)] = graph->pwgts[1];
14834  sizes[2*npes-2-(2*cpos+2)] = graph->pwgts[0];
14835  }
14836 
14837  /* Order the nodes in the separator */
14838  nbnd = graph->nbnd;
14839  bndind = graph->bndind;
14840  label = graph->label;
14841  for (i=0; i<nbnd; i++)
14842  order[label[bndind[i]]] = --lastvtx;
14843 
14844  SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);
14845 
14846  /* Free the memory of the top level graph */
14847  GKfree((void **) &graph->gdata, (void **) &graph->rdata,
14848  (void **) &graph->label, LTERM);
14849 
14850  if (rgraph.nvtxs > MMDSWITCH || 2*cpos+1 < npes-1)
14851  MlevelNestedDissectionP(ctrl, &rgraph, order, lastvtx, npes, 2*cpos+1, sizes);
14852  else {
14853  MMDOrder(ctrl, &rgraph, order, lastvtx);
14854  GKfree((void **) &rgraph.gdata, (void **) &rgraph.rdata,
14855  (void **) &rgraph.label, LTERM);
14856  }
14857  if (lgraph.nvtxs > MMDSWITCH || 2*cpos+2 < npes-1)
14858  MlevelNestedDissectionP(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs, npes, 2*cpos+2, sizes);
14859  else {
14860  MMDOrder(ctrl, &lgraph, order, lastvtx-rgraph.nvtxs);
14861  GKfree((void **) &lgraph.gdata, (void **) &lgraph.rdata,
14862  (void **) &lgraph.label, LTERM);
14863  }
14864 }
14865 
14866 
14867 
14868 
14869 /*************************************************************************
14870 * This function is the entry point for ONWMETIS. It requires weights on the
14871 * vertices. It is for the case that the matrix has been pre-compressed.
14872 **************************************************************************/
14873 void METIS_NodeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
14874  idxtype *adjwgt, int *options, int *sepsize, idxtype *part)
14875 {
14876  int tvwgt, tpwgts[2];
14877  GraphType graph;
14878  CtrlType ctrl;
14879 
14880  SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3);
14881  tvwgt = idxsum(*nvtxs, graph.vwgt);
14882 
14883  if (options[0] == 0) { /* Use the default parameters */
14884  ctrl.CType = ONMETIS_CTYPE;
14885  ctrl.IType = ONMETIS_ITYPE;
14886  ctrl.RType = ONMETIS_RTYPE;
14887  ctrl.dbglvl = ONMETIS_DBGLVL;
14888  }
14889  else {
14890  ctrl.CType = options[OPTION_CTYPE];
14891  ctrl.IType = options[OPTION_ITYPE];
14892  ctrl.RType = options[OPTION_RTYPE];
14893  ctrl.dbglvl = options[OPTION_DBGLVL];
14894  }
14895 
14896  ctrl.oflags = 0;
14897  ctrl.pfactor = 0;
14898  ctrl.nseps = 1;
14899  ctrl.optype = OP_ONMETIS;
14900  ctrl.CoarsenTo = amin(100, *nvtxs-1);
14901  ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo;
14902 
14903  InitRandom(options[7]);
14904 
14905  AllocateWorkSpace(&ctrl, &graph, 2);
14906 
14907  /*============================================================
14908  * Perform the bisection
14909  *============================================================*/
14910  tpwgts[0] = tvwgt/2;
14911  tpwgts[1] = tvwgt-tpwgts[0];
14912 
14913  MlevelNodeBisectionMultiple(&ctrl, &graph, tpwgts, 1.05);
14914 
14915  *sepsize = graph.pwgts[2];
14916  idxcopy(*nvtxs, graph.where, part);
14917 
14918  GKfree((void **) &graph.gdata, (void **) &graph.rdata,
14919  (void **) &graph.label, LTERM);
14920 
14921 
14922  FreeWorkSpace(&ctrl, &graph);
14923 
14924 }
14925 
14926 
14927 
14928 /*************************************************************************
14929 * This function is the entry point for ONWMETIS. It requires weights on the
14930 * vertices. It is for the case that the matrix has been pre-compressed.
14931 **************************************************************************/
14932 void METIS_EdgeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
14933  idxtype *adjwgt, int *options, int *sepsize, idxtype *part)
14934 {
14935  int tvwgt, tpwgts[2];
14936  GraphType graph;
14937  CtrlType ctrl;
14938 
14939  SetUpGraph(&graph, OP_ONMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, 3);
14940  tvwgt = idxsum(*nvtxs, graph.vwgt);
14941 
14942  if (options[0] == 0) { /* Use the default parameters */
14943  ctrl.CType = ONMETIS_CTYPE;
14944  ctrl.IType = ONMETIS_ITYPE;
14945  ctrl.RType = ONMETIS_RTYPE;
14946  ctrl.dbglvl = ONMETIS_DBGLVL;
14947  }
14948  else {
14949  ctrl.CType = options[OPTION_CTYPE];
14950  ctrl.IType = options[OPTION_ITYPE];
14951  ctrl.RType = options[OPTION_RTYPE];
14952  ctrl.dbglvl = options[OPTION_DBGLVL];
14953  }
14954 
14955  ctrl.oflags = 0;
14956  ctrl.pfactor = 0;
14957  ctrl.nseps = 1;
14958  ctrl.optype = OP_OEMETIS;
14959  ctrl.CoarsenTo = amin(100, *nvtxs-1);
14960  ctrl.maxvwgt = 1.5*tvwgt/ctrl.CoarsenTo;
14961 
14962  InitRandom(options[7]);
14963 
14964  AllocateWorkSpace(&ctrl, &graph, 2);
14965 
14966  /*============================================================
14967  * Perform the bisection
14968  *============================================================*/
14969  tpwgts[0] = tvwgt/2;
14970  tpwgts[1] = tvwgt-tpwgts[0];
14971 
14972  MlevelEdgeBisection(&ctrl, &graph, tpwgts, 1.05);
14973  ConstructMinCoverSeparator(&ctrl, &graph, 1.05);
14974 
14975  *sepsize = graph.pwgts[2];
14976  idxcopy(*nvtxs, graph.where, part);
14977 
14978  GKfree((void **) &graph.gdata, (void **) &graph.rdata,
14979  (void **) &graph.label, LTERM);
14980 
14981 
14982  FreeWorkSpace(&ctrl, &graph);
14983 
14984 }
14985 /*
14986  * Copyright 1997, Regents of the University of Minnesota
14987  *
14988  * pmetis.c
14989  *
14990  * This file contains the top level routines for the multilevel recursive
14991  * bisection algorithm PMETIS.
14992  *
14993  * Started 7/24/97
14994  * George
14995  *
14996  * $Id$
14997  *
14998  */
14999 
15000 
15001 
15002 
15003 /*************************************************************************
15004 * This function is the entry point for PMETIS
15005 **************************************************************************/
15006 void METIS_PartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
15007  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
15008  int *options, int *edgecut, idxtype *part)
15009 {
15010  int i;
15011  float *tpwgts;
15012 
15013  tpwgts = fmalloc(*nparts, "KMETIS: tpwgts");
15014  for (i=0; i<*nparts; i++)
15015  tpwgts[i] = 1.0/(1.0*(*nparts));
15016 
15017  METIS_WPartGraphRecursive(nvtxs, xadj, adjncy, vwgt, adjwgt, wgtflag, numflag, nparts,
15018  tpwgts, options, edgecut, part);
15019 
15020  free(tpwgts);
15021 }
15022 
15023 
15024 
15025 /*************************************************************************
15026 * This function is the entry point for PWMETIS that accepts exact weights
15027 * for the target partitions
15028 **************************************************************************/
15029 void METIS_WPartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
15030  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
15031  float *tpwgts, int *options, int *edgecut, idxtype *part)
15032 {
15033  int i;
15034  GraphType graph;
15035  CtrlType ctrl;
15036  float *mytpwgts;
15037 
15038  if (*numflag == 1)
15039  Change2CNumbering(*nvtxs, xadj, adjncy);
15040 
15041  SetUpGraph(&graph, OP_PMETIS, *nvtxs, 1, xadj, adjncy, vwgt, adjwgt, *wgtflag);
15042 
15043  if (options[0] == 0) { /* Use the default parameters */
15044  ctrl.CType = PMETIS_CTYPE;
15045  ctrl.IType = PMETIS_ITYPE;
15046  ctrl.RType = PMETIS_RTYPE;
15047  ctrl.dbglvl = PMETIS_DBGLVL;
15048  }
15049  else {
15050  ctrl.CType = options[OPTION_CTYPE];
15051  ctrl.IType = options[OPTION_ITYPE];
15052  ctrl.RType = options[OPTION_RTYPE];
15053  ctrl.dbglvl = options[OPTION_DBGLVL];
15054  }
15055  ctrl.optype = OP_PMETIS;
15056  ctrl.CoarsenTo = 20;
15057  ctrl.maxvwgt = 1.5*(idxsum(*nvtxs, graph.vwgt)/ctrl.CoarsenTo);
15058 
15059  mytpwgts = fmalloc(*nparts, "PWMETIS: mytpwgts");
15060  for (i=0; i<*nparts; i++)
15061  mytpwgts[i] = tpwgts[i];
15062 
15063  InitRandom(-1);
15064 
15065  AllocateWorkSpace(&ctrl, &graph, *nparts);
15066 
15067  IFSET(ctrl.dbglvl, DBG_TIME, InitTimers(&ctrl));
15068  IFSET(ctrl.dbglvl, DBG_TIME, starttimer(ctrl.TotalTmr));
15069 
15070  *edgecut = MlevelRecursiveBisection(&ctrl, &graph, *nparts, part, mytpwgts, 1.000, 0);
15071 
15072  IFSET(ctrl.dbglvl, DBG_TIME, stoptimer(ctrl.TotalTmr));
15073  IFSET(ctrl.dbglvl, DBG_TIME, PrintTimers(&ctrl));
15074 
15075  FreeWorkSpace(&ctrl, &graph);
15076  free(mytpwgts);
15077 
15078  if (*numflag == 1)
15079  Change2FNumbering(*nvtxs, xadj, adjncy, part);
15080 }
15081 
15082 
15083 
15084 /*************************************************************************
15085 * This function takes a graph and produces a bisection of it
15086 **************************************************************************/
15087 int MlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor, int fpart)
15088 {
15089  int i, nvtxs, cut, tvwgt, tpwgts2[2];
15090  idxtype *label, *where;
15091  GraphType lgraph, rgraph;
15092  float wsum;
15093 
15094  nvtxs = graph->nvtxs;
15095  if (nvtxs == 0) {
15096  printf("\t***Cannot bisect a graph with 0 vertices!\n\t***You are trying to partition a graph into too many parts!\n");
15097  return 0;
15098  }
15099 
15100  /* Determine the weights of the partitions */
15101  tvwgt = idxsum(nvtxs, graph->vwgt);
15102  tpwgts2[0] = tvwgt*ssum(nparts/2, tpwgts);
15103  tpwgts2[1] = tvwgt-tpwgts2[0];
15104 
15105  MlevelEdgeBisection(ctrl, graph, tpwgts2, ubfactor);
15106  cut = graph->mincut;
15107 
15108  /* printf("%5d %5d %5d [%5d %f]\n", tpwgts2[0], tpwgts2[1], cut, tvwgt, ssum(nparts/2, tpwgts));*/
15109 
15110  label = graph->label;
15111  where = graph->where;
15112  for (i=0; i<nvtxs; i++)
15113  part[label[i]] = where[i] + fpart;
15114 
15115  if (nparts > 2) {
15116  SplitGraphPart(ctrl, graph, &lgraph, &rgraph);
15117  /* printf("%d %d\n", lgraph.nvtxs, rgraph.nvtxs); */
15118  }
15119 
15120 
15121  /* Free the memory of the top level graph */
15122  GKfree((void **) &graph->gdata, (void **) &graph->rdata,
15123  (void **) &graph->label, LTERM);
15124 
15125  /* Scale the fractions in the tpwgts according to the true weight */
15126  wsum = ssum(nparts/2, tpwgts);
15127  sscale(nparts/2, 1.0/wsum, tpwgts);
15128  sscale(nparts-nparts/2, 1.0/(1.0-wsum), tpwgts+nparts/2);
15129  /*
15130  for (i=0; i<nparts; i++)
15131  printf("%5.3f ", tpwgts[i]);
15132  printf("[%5.3f]\n", wsum);
15133  */
15134 
15135  /* Do the recursive call */
15136  if (nparts > 3) {
15137  cut += MlevelRecursiveBisection(ctrl, &lgraph, nparts/2, part, tpwgts, ubfactor, fpart);
15138  cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2);
15139  }
15140  else if (nparts == 3) {
15141  cut += MlevelRecursiveBisection(ctrl, &rgraph, nparts-nparts/2, part, tpwgts+nparts/2, ubfactor, fpart+nparts/2);
15142  GKfree((void **) &lgraph.gdata, (void **) &lgraph.label, LTERM);
15143  }
15144 
15145  return cut;
15146 
15147 }
15148 
15149 
15150 /*************************************************************************
15151 * This function performs multilevel bisection
15152 **************************************************************************/
15153 void MlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
15154 {
15155  GraphType *cgraph;
15156 
15157  cgraph = Coarsen2Way(ctrl, graph);
15158 
15159  Init2WayPartition(ctrl, cgraph, tpwgts, ubfactor);
15160 
15161  Refine2Way(ctrl, graph, cgraph, tpwgts, ubfactor);
15162 
15163 /*
15164  IsConnectedSubdomain(ctrl, graph, 0);
15165  IsConnectedSubdomain(ctrl, graph, 1);
15166 */
15167 }
15168 
15169 
15170 
15171 
15172 /*************************************************************************
15173 * This function takes a graph and a bisection and splits it into two graphs.
15174 **************************************************************************/
15175 void SplitGraphPart(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph)
15176 {
15177  int i, j, k, kk, l, istart, iend, mypart, nvtxs, ncon, snvtxs[2], snedges[2], sum;
15178  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *adjwgtsum, *label, *where, *bndptr;
15179  idxtype *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *sadjwgtsum[2], *slabel[2];
15180  idxtype *rename;
15181  idxtype *auxadjncy, *auxadjwgt;
15182  float *nvwgt, *snvwgt[2], *npwgts;
15183 
15184 
15185  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->SplitTmr));
15186 
15187  nvtxs = graph->nvtxs;
15188  ncon = graph->ncon;
15189  xadj = graph->xadj;
15190  vwgt = graph->vwgt;
15191  nvwgt = graph->nvwgt;
15192  adjncy = graph->adjncy;
15193  adjwgt = graph->adjwgt;
15194  adjwgtsum = graph->adjwgtsum;
15195  label = graph->label;
15196  where = graph->where;
15197  bndptr = graph->bndptr;
15198  npwgts = graph->npwgts;
15199 
15200  ASSERT(bndptr != NULL);
15201 
15202  rename = idxwspacemalloc(ctrl, nvtxs);
15203 
15204  snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
15205  for (i=0; i<nvtxs; i++) {
15206  k = where[i];
15207  rename[i] = snvtxs[k]++;
15208  snedges[k] += xadj[i+1]-xadj[i];
15209  }
15210 
15211  SetUpSplitGraph(graph, lgraph, snvtxs[0], snedges[0]);
15212  sxadj[0] = lgraph->xadj;
15213  svwgt[0] = lgraph->vwgt;
15214  snvwgt[0] = lgraph->nvwgt;
15215  sadjwgtsum[0] = lgraph->adjwgtsum;
15216  sadjncy[0] = lgraph->adjncy;
15217  sadjwgt[0] = lgraph->adjwgt;
15218  slabel[0] = lgraph->label;
15219 
15220  SetUpSplitGraph(graph, rgraph, snvtxs[1], snedges[1]);
15221  sxadj[1] = rgraph->xadj;
15222  svwgt[1] = rgraph->vwgt;
15223  snvwgt[1] = rgraph->nvwgt;
15224  sadjwgtsum[1] = rgraph->adjwgtsum;
15225  sadjncy[1] = rgraph->adjncy;
15226  sadjwgt[1] = rgraph->adjwgt;
15227  slabel[1] = rgraph->label;
15228 
15229  snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
15230  sxadj[0][0] = sxadj[1][0] = 0;
15231  for (i=0; i<nvtxs; i++) {
15232  mypart = where[i];
15233  sum = adjwgtsum[i];
15234 
15235  istart = xadj[i];
15236  iend = xadj[i+1];
15237  if (bndptr[i] == -1) { /* This is an interior vertex */
15238  auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;
15239  auxadjwgt = sadjwgt[mypart] + snedges[mypart] - istart;
15240  for(j=istart; j<iend; j++) {
15241  auxadjncy[j] = adjncy[j];
15242  auxadjwgt[j] = adjwgt[j];
15243  }
15244  snedges[mypart] += iend-istart;
15245  }
15246  else {
15247  auxadjncy = sadjncy[mypart];
15248  auxadjwgt = sadjwgt[mypart];
15249  l = snedges[mypart];
15250  for (j=istart; j<iend; j++) {
15251  k = adjncy[j];
15252  if (where[k] == mypart) {
15253  auxadjncy[l] = k;
15254  auxadjwgt[l++] = adjwgt[j];
15255  }
15256  else {
15257  sum -= adjwgt[j];
15258  }
15259  }
15260  snedges[mypart] = l;
15261  }
15262 
15263  if (ncon == 1)
15264  svwgt[mypart][snvtxs[mypart]] = vwgt[i];
15265  else {
15266  for (kk=0; kk<ncon; kk++)
15267  snvwgt[mypart][snvtxs[mypart]*ncon+kk] = nvwgt[i*ncon+kk]/npwgts[mypart*ncon+kk];
15268  }
15269 
15270  sadjwgtsum[mypart][snvtxs[mypart]] = sum;
15271  slabel[mypart][snvtxs[mypart]] = label[i];
15272  sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];
15273  }
15274 
15275  for (mypart=0; mypart<2; mypart++) {
15276  iend = sxadj[mypart][snvtxs[mypart]];
15277  auxadjncy = sadjncy[mypart];
15278  for (i=0; i<iend; i++)
15279  auxadjncy[i] = rename[auxadjncy[i]];
15280  }
15281 
15282  lgraph->nedges = snedges[0];
15283  rgraph->nedges = snedges[1];
15284 
15285  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->SplitTmr));
15286 
15287  idxwspacefree(ctrl, nvtxs);
15288 }
15289 
15290 
15291 /*************************************************************************
15292 * Setup the various arrays for the splitted graph
15293 **************************************************************************/
15294 void SetUpSplitGraph(GraphType *graph, GraphType *sgraph, int snvtxs, int snedges)
15295 {
15296  InitGraph(sgraph);
15297  sgraph->nvtxs = snvtxs;
15298  sgraph->nedges = snedges;
15299  sgraph->ncon = graph->ncon;
15300 
15301  /* Allocate memory for the splitted graph */
15302  if (graph->ncon == 1) {
15303  sgraph->gdata = idxmalloc(4*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata");
15304 
15305  sgraph->xadj = sgraph->gdata;
15306  sgraph->vwgt = sgraph->gdata + snvtxs+1;
15307  sgraph->adjwgtsum = sgraph->gdata + 2*snvtxs+1;
15308  sgraph->cmap = sgraph->gdata + 3*snvtxs+1;
15309  sgraph->adjncy = sgraph->gdata + 4*snvtxs+1;
15310  sgraph->adjwgt = sgraph->gdata + 4*snvtxs+1 + snedges;
15311  }
15312  else {
15313  sgraph->gdata = idxmalloc(3*snvtxs+1 + 2*snedges, "SetUpSplitGraph: gdata");
15314 
15315  sgraph->xadj = sgraph->gdata;
15316  sgraph->adjwgtsum = sgraph->gdata + snvtxs+1;
15317  sgraph->cmap = sgraph->gdata + 2*snvtxs+1;
15318  sgraph->adjncy = sgraph->gdata + 3*snvtxs+1;
15319  sgraph->adjwgt = sgraph->gdata + 3*snvtxs+1 + snedges;
15320 
15321  sgraph->nvwgt = fmalloc(graph->ncon*snvtxs, "SetUpSplitGraph: nvwgt");
15322  }
15323 
15324  sgraph->label = idxmalloc(snvtxs, "SetUpSplitGraph: sgraph->label");
15325 }
15326 
15327 /*
15328  * Copyright 1997, Regents of the University of Minnesota
15329  *
15330  * pqueue.c
15331  *
15332  * This file contains functions for manipulating the bucket list
15333  * representation of the gains associated with each vertex in a graph.
15334  * These functions are used by the refinement algorithms
15335  *
15336  * Started 9/2/94
15337  * George
15338  *
15339  * $Id$
15340  *
15341  */
15342 
15343 
15344 
15345 
15346 /*************************************************************************
15347 * This function initializes the data structures of the priority queue
15348 **************************************************************************/
15349 void PQueueInit(CtrlType *ctrl, PQueueType *queue, int maxnodes, int maxgain)
15350 {
15351  int i, j, ncore;
15352 
15353  queue->nnodes = 0;
15354  queue->maxnodes = maxnodes;
15355 
15356  queue->buckets = NULL;
15357  queue->nodes = NULL;
15358  queue->heap = NULL;
15359  queue->locator = NULL;
15360 
15361  if (maxgain > PLUS_GAINSPAN || maxnodes < 500)
15362  queue->type = 2;
15363  else
15364  queue->type = 1;
15365 
15366  if (queue->type == 1) {
15367  queue->pgainspan = amin(PLUS_GAINSPAN, maxgain);
15368  queue->ngainspan = amin(NEG_GAINSPAN, maxgain);
15369 
15370  j = queue->ngainspan+queue->pgainspan+1;
15371 
15372  ncore = 2 + (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes + (sizeof(ListNodeType *)/sizeof(idxtype))*j;
15373 
15374  if (WspaceAvail(ctrl) > ncore) {
15375  queue->nodes = (ListNodeType *)idxwspacemalloc(ctrl, (sizeof(ListNodeType)/sizeof(idxtype))*maxnodes);
15376  queue->buckets = (ListNodeType **)idxwspacemalloc(ctrl, (sizeof(ListNodeType *)/sizeof(idxtype))*j);
15377  queue->mustfree = 0;
15378  }
15379  else { /* Not enough memory in the wspace, allocate it */
15380  queue->nodes = (ListNodeType *)idxmalloc((sizeof(ListNodeType)/sizeof(idxtype))*maxnodes, "PQueueInit: queue->nodes");
15381  queue->buckets = (ListNodeType **)idxmalloc((sizeof(ListNodeType *)/sizeof(idxtype))*j, "PQueueInit: queue->buckets");
15382  queue->mustfree = 1;
15383  }
15384 
15385  for (i=0; i<maxnodes; i++)
15386  queue->nodes[i].id = i;
15387 
15388  for (i=0; i<j; i++)
15389  queue->buckets[i] = NULL;
15390 
15391  queue->buckets += queue->ngainspan; /* Advance buckets by the ngainspan proper indexing */
15392  queue->maxgain = -queue->ngainspan;
15393  }
15394  else {
15395  queue->heap = (KeyValueType *)idxwspacemalloc(ctrl, (sizeof(KeyValueType)/sizeof(idxtype))*maxnodes);
15396  queue->locator = idxwspacemalloc(ctrl, maxnodes);
15397  idxset(maxnodes, -1, queue->locator);
15398  }
15399 
15400 }
15401 
15402 
15403 /*************************************************************************
15404 * This function resets the buckets
15405 **************************************************************************/
15407 {
15408  int i, j;
15409  queue->nnodes = 0;
15410 
15411  if (queue->type == 1) {
15412  queue->maxgain = -queue->ngainspan;
15413 
15414  j = queue->ngainspan+queue->pgainspan+1;
15415  queue->buckets -= queue->ngainspan;
15416  for (i=0; i<j; i++)
15417  queue->buckets[i] = NULL;
15418  queue->buckets += queue->ngainspan;
15419  }
15420  else {
15421  idxset(queue->maxnodes, -1, queue->locator);
15422  }
15423 
15424 }
15425 
15426 
15427 /*************************************************************************
15428 * This function frees the buckets
15429 **************************************************************************/
15430 void PQueueFree(CtrlType *ctrl, PQueueType *queue)
15431 {
15432 
15433  if (queue->type == 1) {
15434  if (queue->mustfree) {
15435  queue->buckets -= queue->ngainspan;
15436  GKfree((void **) &queue->nodes, (void **) &queue->buckets, LTERM);
15437  }
15438  else {
15439  idxwspacefree(ctrl, sizeof(ListNodeType *)*(queue->ngainspan+queue->pgainspan+1)/sizeof(idxtype));
15440  idxwspacefree(ctrl, sizeof(ListNodeType)*queue->maxnodes/sizeof(idxtype));
15441  }
15442  }
15443  else {
15444  idxwspacefree(ctrl, sizeof(KeyValueType)*queue->maxnodes/sizeof(idxtype));
15445  idxwspacefree(ctrl, queue->maxnodes);
15446  }
15447 
15448  queue->maxnodes = 0;
15449 }
15450 
15451 
15452 /*************************************************************************
15453 * This function returns the number of nodes in the queue
15454 **************************************************************************/
15456 {
15457  return queue->nnodes;
15458 }
15459 
15460 
15461 /*************************************************************************
15462 * This function adds a node of certain gain into a partition
15463 **************************************************************************/
15464 int PQueueInsert(PQueueType *queue, int node, int gain)
15465 {
15466  int i, j;
15467  idxtype *locator;
15468  ListNodeType *newnode;
15469  KeyValueType *heap;
15470 
15471  if (queue->type == 1) {
15472  ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan);
15473 
15474  /* Allocate and add the node */
15475  queue->nnodes++;
15476  newnode = queue->nodes + node;
15477 
15478  /* Attach this node in the doubly-linked list */
15479  newnode->next = queue->buckets[gain];
15480  newnode->prev = NULL;
15481  if (newnode->next != NULL)
15482  newnode->next->prev = newnode;
15483  queue->buckets[gain] = newnode;
15484 
15485  if (queue->maxgain < gain)
15486  queue->maxgain = gain;
15487  }
15488  else {
15489  ASSERT(CheckHeap(queue));
15490 
15491  heap = queue->heap;
15492  locator = queue->locator;
15493 
15494  ASSERT(locator[node] == -1);
15495 
15496  i = queue->nnodes++;
15497  while (i > 0) {
15498  j = (i-1)/2;
15499  if (heap[j].key < gain) {
15500  heap[i] = heap[j];
15501  locator[heap[i].val] = i;
15502  i = j;
15503  }
15504  else
15505  break;
15506  }
15507  ASSERT(i >= 0);
15508  heap[i].key = gain;
15509  heap[i].val = node;
15510  locator[node] = i;
15511 
15512  ASSERT(CheckHeap(queue));
15513  }
15514 
15515  return 0;
15516 }
15517 
15518 
15519 /*************************************************************************
15520 * This function deletes a node from a partition and reinserts it with
15521 * an updated gain
15522 **************************************************************************/
15523 int PQueueDelete(PQueueType *queue, int node, int gain)
15524 {
15525  int i, j, newgain, oldgain;
15526  idxtype *locator;
15527  ListNodeType *newnode, **buckets;
15528  KeyValueType *heap;
15529 
15530  if (queue->type == 1) {
15531  ASSERT(gain >= -queue->ngainspan && gain <= queue->pgainspan);
15532  ASSERT(queue->nnodes > 0);
15533 
15534  buckets = queue->buckets;
15535  queue->nnodes--;
15536  newnode = queue->nodes+node;
15537 
15538  /* Remove newnode from the doubly-linked list */
15539  if (newnode->prev != NULL)
15540  newnode->prev->next = newnode->next;
15541  else
15542  buckets[gain] = newnode->next;
15543  if (newnode->next != NULL)
15544  newnode->next->prev = newnode->prev;
15545 
15546  if (buckets[gain] == NULL && gain == queue->maxgain) {
15547  if (queue->nnodes == 0)
15548  queue->maxgain = -queue->ngainspan;
15549  else
15550  for (; buckets[queue->maxgain]==NULL; queue->maxgain--);
15551  }
15552  }
15553  else { /* Heap Priority Queue */
15554  heap = queue->heap;
15555  locator = queue->locator;
15556 
15557  ASSERT(locator[node] != -1);
15558  ASSERT(heap[locator[node]].val == node);
15559 
15560  ASSERT(CheckHeap(queue));
15561 
15562  i = locator[node];
15563  locator[node] = -1;
15564 
15565  if (--queue->nnodes > 0 && heap[queue->nnodes].val != node) {
15566  node = heap[queue->nnodes].val;
15567  newgain = heap[queue->nnodes].key;
15568  oldgain = heap[i].key;
15569 
15570  if (oldgain < newgain) { /* Filter-up */
15571  while (i > 0) {
15572  j = (i-1)>>1;
15573  if (heap[j].key < newgain) {
15574  heap[i] = heap[j];
15575  locator[heap[i].val] = i;
15576  i = j;
15577  }
15578  else
15579  break;
15580  }
15581  }
15582  else { /* Filter down */
15583  while ((j=2*i+1) < queue->nnodes) {
15584  if (heap[j].key > newgain) {
15585  if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key)
15586  j = j+1;
15587  heap[i] = heap[j];
15588  locator[heap[i].val] = i;
15589  i = j;
15590  }
15591  else if (j+1 < queue->nnodes && heap[j+1].key > newgain) {
15592  j = j+1;
15593  heap[i] = heap[j];
15594  locator[heap[i].val] = i;
15595  i = j;
15596  }
15597  else
15598  break;
15599  }
15600  }
15601 
15602  heap[i].key = newgain;
15603  heap[i].val = node;
15604  locator[node] = i;
15605  }
15606 
15607  ASSERT(CheckHeap(queue));
15608  }
15609 
15610  return 0;
15611 }
15612 
15613 
15614 
15615 /*************************************************************************
15616 * This function deletes a node from a partition and reinserts it with
15617 * an updated gain
15618 **************************************************************************/
15619 int PQueueUpdate(PQueueType *queue, int node, int oldgain, int newgain)
15620 {
15621  int i, j;
15622  idxtype *locator;
15623  KeyValueType *heap;
15624 
15625  if (oldgain == newgain)
15626  return 0;
15627 
15628  if (queue->type == 1) {
15629  /* First delete the node and then insert it */
15630  PQueueDelete(queue, node, oldgain);
15631  return PQueueInsert(queue, node, newgain);
15632  }
15633  else { /* Heap Priority Queue */
15634  heap = queue->heap;
15635  locator = queue->locator;
15636 
15637  ASSERT(locator[node] != -1);
15638  ASSERT(heap[locator[node]].val == node);
15639  ASSERT(heap[locator[node]].key == oldgain);
15640  ASSERT(CheckHeap(queue));
15641 
15642  i = locator[node];
15643 
15644  if (oldgain < newgain) { /* Filter-up */
15645  while (i > 0) {
15646  j = (i-1)>>1;
15647  if (heap[j].key < newgain) {
15648  heap[i] = heap[j];
15649  locator[heap[i].val] = i;
15650  i = j;
15651  }
15652  else
15653  break;
15654  }
15655  }
15656  else { /* Filter down */
15657  while ((j=2*i+1) < queue->nnodes) {
15658  if (heap[j].key > newgain) {
15659  if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key)
15660  j = j+1;
15661  heap[i] = heap[j];
15662  locator[heap[i].val] = i;
15663  i = j;
15664  }
15665  else if (j+1 < queue->nnodes && heap[j+1].key > newgain) {
15666  j = j+1;
15667  heap[i] = heap[j];
15668  locator[heap[i].val] = i;
15669  i = j;
15670  }
15671  else
15672  break;
15673  }
15674  }
15675 
15676  heap[i].key = newgain;
15677  heap[i].val = node;
15678  locator[node] = i;
15679 
15680  ASSERT(CheckHeap(queue));
15681  }
15682 
15683  return 0;
15684 }
15685 
15686 
15687 
15688 /*************************************************************************
15689 * This function deletes a node from a partition and reinserts it with
15690 * an updated gain
15691 **************************************************************************/
15692 void PQueueUpdateUp(PQueueType *queue, int node, int oldgain, int newgain)
15693 {
15694  int i, j;
15695  idxtype *locator;
15696  ListNodeType *newnode, **buckets;
15697  KeyValueType *heap;
15698 
15699  if (oldgain == newgain)
15700  return;
15701 
15702  if (queue->type == 1) {
15703  ASSERT(oldgain >= -queue->ngainspan && oldgain <= queue->pgainspan);
15704  ASSERT(newgain >= -queue->ngainspan && newgain <= queue->pgainspan);
15705  ASSERT(queue->nnodes > 0);
15706 
15707  buckets = queue->buckets;
15708  newnode = queue->nodes+node;
15709 
15710  /* First delete the node */
15711  if (newnode->prev != NULL)
15712  newnode->prev->next = newnode->next;
15713  else
15714  buckets[oldgain] = newnode->next;
15715  if (newnode->next != NULL)
15716  newnode->next->prev = newnode->prev;
15717 
15718  /* Attach this node in the doubly-linked list */
15719  newnode->next = buckets[newgain];
15720  newnode->prev = NULL;
15721  if (newnode->next != NULL)
15722  newnode->next->prev = newnode;
15723  buckets[newgain] = newnode;
15724 
15725  if (queue->maxgain < newgain)
15726  queue->maxgain = newgain;
15727  }
15728  else { /* Heap Priority Queue */
15729  heap = queue->heap;
15730  locator = queue->locator;
15731 
15732  ASSERT(locator[node] != -1);
15733  ASSERT(heap[locator[node]].val == node);
15734  ASSERT(heap[locator[node]].key == oldgain);
15735  ASSERT(CheckHeap(queue));
15736 
15737 
15738  /* Here we are just filtering up since the newgain is greater than the oldgain */
15739  i = locator[node];
15740  while (i > 0) {
15741  j = (i-1)>>1;
15742  if (heap[j].key < newgain) {
15743  heap[i] = heap[j];
15744  locator[heap[i].val] = i;
15745  i = j;
15746  }
15747  else
15748  break;
15749  }
15750 
15751  heap[i].key = newgain;
15752  heap[i].val = node;
15753  locator[node] = i;
15754 
15755  ASSERT(CheckHeap(queue));
15756  }
15757 
15758 }
15759 
15760 
15761 /*************************************************************************
15762 * This function returns the vertex with the largest gain from a partition
15763 * and removes the node from the bucket list
15764 **************************************************************************/
15766 {
15767  int vtx, i, j, gain, node;
15768  idxtype *locator;
15769  ListNodeType *tptr;
15770  KeyValueType *heap;
15771 
15772  if (queue->nnodes == 0)
15773  return -1;
15774 
15775  queue->nnodes--;
15776 
15777  if (queue->type == 1) {
15778  tptr = queue->buckets[queue->maxgain];
15779  queue->buckets[queue->maxgain] = tptr->next;
15780  if (tptr->next != NULL) {
15781  tptr->next->prev = NULL;
15782  }
15783  else {
15784  if (queue->nnodes == 0) {
15785  queue->maxgain = -queue->ngainspan;
15786  }
15787  else
15788  for (; queue->buckets[queue->maxgain]==NULL; queue->maxgain--);
15789  }
15790 
15791  return tptr->id;
15792  }
15793  else {
15794  heap = queue->heap;
15795  locator = queue->locator;
15796 
15797  vtx = heap[0].val;
15798  locator[vtx] = -1;
15799 
15800  if ((i = queue->nnodes) > 0) {
15801  gain = heap[i].key;
15802  node = heap[i].val;
15803  i = 0;
15804  while ((j=2*i+1) < queue->nnodes) {
15805  if (heap[j].key > gain) {
15806  if (j+1 < queue->nnodes && heap[j+1].key > heap[j].key)
15807  j = j+1;
15808  heap[i] = heap[j];
15809  locator[heap[i].val] = i;
15810  i = j;
15811  }
15812  else if (j+1 < queue->nnodes && heap[j+1].key > gain) {
15813  j = j+1;
15814  heap[i] = heap[j];
15815  locator[heap[i].val] = i;
15816  i = j;
15817  }
15818  else
15819  break;
15820  }
15821 
15822  heap[i].key = gain;
15823  heap[i].val = node;
15824  locator[node] = i;
15825  }
15826 
15827  ASSERT(CheckHeap(queue));
15828  return vtx;
15829  }
15830 }
15831 
15832 
15833 /*************************************************************************
15834 * This function returns the vertex with the largest gain from a partition
15835 **************************************************************************/
15837 {
15838  int vtx;
15839 
15840  if (queue->nnodes == 0)
15841  return -1;
15842 
15843  if (queue->type == 1)
15844  vtx = queue->buckets[queue->maxgain]->id;
15845  else
15846  vtx = queue->heap[0].val;
15847 
15848  return vtx;
15849 }
15850 
15851 
15852 /*************************************************************************
15853 * This function returns the vertex with the largest gain from a partition
15854 **************************************************************************/
15856 {
15857  int key;
15858 
15859  if (queue->nnodes == 0)
15860  return -1;
15861 
15862  if (queue->type == 1)
15863  key = queue->maxgain;
15864  else
15865  key = queue->heap[0].key;
15866 
15867  return key;
15868 }
15869 
15870 
15871 
15872 
15873 /*************************************************************************
15874 * This functions checks the consistency of the heap
15875 **************************************************************************/
15877 {
15878  int i, j, nnodes;
15879  idxtype *locator;
15880  KeyValueType *heap;
15881 
15882  heap = queue->heap;
15883  locator = queue->locator;
15884  nnodes = queue->nnodes;
15885 
15886  if (nnodes == 0)
15887  return 1;
15888 
15889  ASSERT(locator[heap[0].val] == 0);
15890  for (i=1; i<nnodes; i++) {
15891  ASSERTP(locator[heap[i].val] == i, ("%d %d %d %d\n", nnodes, i, heap[i].val, locator[heap[i].val]));
15892  ASSERTP(heap[i].key <= heap[(i-1)/2].key, ("%d %d %d %d %d\n", i, (i-1)/2, nnodes, heap[i].key, heap[(i-1)/2].key));
15893  }
15894  for (i=1; i<nnodes; i++)
15895  ASSERT(heap[i].key <= heap[0].key);
15896 
15897  for (j=i=0; i<queue->maxnodes; i++) {
15898  if (locator[i] != -1)
15899  j++;
15900  }
15901  ASSERTP(j == nnodes, ("%d %d\n", j, nnodes));
15902 
15903  return 1;
15904 }
15905 /*
15906  * Copyright 1997, Regents of the University of Minnesota
15907  *
15908  * refine.c
15909  *
15910  * This file contains the driving routines for multilevel refinement
15911  *
15912  * Started 7/24/97
15913  * George
15914  *
15915  * $Id$
15916  */
15917 
15918 
15919 
15920 
15921 /*************************************************************************
15922 * This function is the entry point of refinement
15923 **************************************************************************/
15924 void Refine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int *tpwgts, float ubfactor)
15925 {
15926 
15927  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
15928 
15929  /* Compute the parameters of the coarsest graph */
15930  Compute2WayPartitionParams(ctrl, graph);
15931 
15932  for (;;) {
15933  ASSERT(CheckBnd(graph));
15934 
15935  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
15936  switch (ctrl->RType) {
15937  case 1:
15938  Balance2Way(ctrl, graph, tpwgts, ubfactor);
15939  FM_2WayEdgeRefine(ctrl, graph, tpwgts, 8);
15940  break;
15941  default:
15942  errexit("Unknown refinement type: %d\n", ctrl->RType);
15943  }
15944  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
15945 
15946  if (graph == orggraph)
15947  break;
15948 
15949  graph = graph->finer;
15950  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
15951  Project2WayPartition(ctrl, graph);
15952  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
15953  }
15954 
15955  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
15956 }
15957 
15958 
15959 /*************************************************************************
15960 * This function allocates memory for 2-way edge refinement
15961 **************************************************************************/
15963 {
15964  int nvtxs;
15965 
15966  nvtxs = graph->nvtxs;
15967 
15968  graph->rdata = idxmalloc(5*nvtxs+2, "Allocate2WayPartitionMemory: rdata");
15969  graph->pwgts = graph->rdata;
15970  graph->where = graph->rdata + 2;
15971  graph->id = graph->rdata + nvtxs + 2;
15972  graph->ed = graph->rdata + 2*nvtxs + 2;
15973  graph->bndptr = graph->rdata + 3*nvtxs + 2;
15974  graph->bndind = graph->rdata + 4*nvtxs + 2;
15975 }
15976 
15977 
15978 /*************************************************************************
15979 * This function computes the initial id/ed
15980 **************************************************************************/
15982 {
15983  int i, j, nvtxs, nbnd, mincut;
15984  idxtype *xadj, *vwgt, *adjncy, *adjwgt, *pwgts;
15985  idxtype *id, *ed, *where;
15986  idxtype *bndptr, *bndind;
15987  int me;
15988 
15989  nvtxs = graph->nvtxs;
15990  xadj = graph->xadj;
15991  vwgt = graph->vwgt;
15992  adjncy = graph->adjncy;
15993  adjwgt = graph->adjwgt;
15994 
15995  where = graph->where;
15996  pwgts = idxset(2, 0, graph->pwgts);
15997  id = idxset(nvtxs, 0, graph->id);
15998  ed = idxset(nvtxs, 0, graph->ed);
15999  bndptr = idxset(nvtxs, -1, graph->bndptr);
16000  bndind = graph->bndind;
16001 
16002 
16003  /*------------------------------------------------------------
16004  / Compute now the id/ed degrees
16005  /------------------------------------------------------------*/
16006  nbnd = mincut = 0;
16007  for (i=0; i<nvtxs; i++) {
16008  ASSERT(where[i] >= 0 && where[i] <= 1);
16009  me = where[i];
16010  pwgts[me] += vwgt[i];
16011 
16012  for (j=xadj[i]; j<xadj[i+1]; j++) {
16013  if (me == where[adjncy[j]])
16014  id[i] += adjwgt[j];
16015  else
16016  ed[i] += adjwgt[j];
16017  }
16018 
16019  if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
16020  mincut += ed[i];
16021  bndptr[i] = nbnd;
16022  bndind[nbnd++] = i;
16023  }
16024  }
16025 
16026  graph->mincut = mincut/2;
16027  graph->nbnd = nbnd;
16028 
16029  ASSERT(pwgts[0]+pwgts[1] == idxsum(nvtxs, vwgt));
16030 }
16031 
16032 
16033 
16034 /*************************************************************************
16035 * This function projects a partition, and at the same time computes the
16036 * parameters for refinement.
16037 **************************************************************************/
16039 {
16040  int i, j, k, nvtxs, nbnd, me;
16041  idxtype *xadj, *adjncy, *adjwgt, *adjwgtsum;
16042  idxtype *cmap, *where, *id, *ed, *bndptr, *bndind;
16043  idxtype *cwhere, *cid, *ced, *cbndptr;
16044  GraphType *cgraph;
16045 
16046  cgraph = graph->coarser;
16047  cwhere = cgraph->where;
16048  cid = cgraph->id;
16049  ced = cgraph->ed;
16050  cbndptr = cgraph->bndptr;
16051 
16052  nvtxs = graph->nvtxs;
16053  cmap = graph->cmap;
16054  xadj = graph->xadj;
16055  adjncy = graph->adjncy;
16056  adjwgt = graph->adjwgt;
16057  adjwgtsum = graph->adjwgtsum;
16058 
16059  Allocate2WayPartitionMemory(ctrl, graph);
16060 
16061  where = graph->where;
16062  id = idxset(nvtxs, 0, graph->id);
16063  ed = idxset(nvtxs, 0, graph->ed);
16064  bndptr = idxset(nvtxs, -1, graph->bndptr);
16065  bndind = graph->bndind;
16066 
16067 
16068  /* Go through and project partition and compute id/ed for the nodes */
16069  for (i=0; i<nvtxs; i++) {
16070  k = cmap[i];
16071  where[i] = cwhere[k];
16072  cmap[i] = cbndptr[k];
16073  }
16074 
16075  for (nbnd=0, i=0; i<nvtxs; i++) {
16076  me = where[i];
16077 
16078  id[i] = adjwgtsum[i];
16079 
16080  if (xadj[i] == xadj[i+1]) {
16081  bndptr[i] = nbnd;
16082  bndind[nbnd++] = i;
16083  }
16084  else {
16085  if (cmap[i] != -1) { /* If it is an interface node. Note that cmap[i] = cbndptr[cmap[i]] */
16086  for (j=xadj[i]; j<xadj[i+1]; j++) {
16087  if (me != where[adjncy[j]])
16088  ed[i] += adjwgt[j];
16089  }
16090  id[i] -= ed[i];
16091 
16092  if (ed[i] > 0 || xadj[i] == xadj[i+1]) {
16093  bndptr[i] = nbnd;
16094  bndind[nbnd++] = i;
16095  }
16096  }
16097  }
16098  }
16099 
16100  graph->mincut = cgraph->mincut;
16101  graph->nbnd = nbnd;
16102  idxcopy(2, cgraph->pwgts, graph->pwgts);
16103 
16104  FreeGraph(graph->coarser);
16105  graph->coarser = NULL;
16106 
16107 }
16108 
16109 /*
16110  * Copyright 1997, Regents of the University of Minnesota
16111  *
16112  * separator.c
16113  *
16114  * This file contains code for separator extraction
16115  *
16116  * Started 8/1/97
16117  * George
16118  *
16119  * $Id$
16120  *
16121  */
16122 
16123 
16124 
16125 /*************************************************************************
16126 * This function takes a bisection and constructs a minimum weight vertex
16127 * separator out of it. It uses the node-based separator refinement for it.
16128 **************************************************************************/
16129 void ConstructSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
16130 {
16131  int i, j, nvtxs, nbnd;
16132  idxtype *xadj, *where, *bndind;
16133 
16134  nvtxs = graph->nvtxs;
16135  xadj = graph->xadj;
16136  nbnd = graph->nbnd;
16137  bndind = graph->bndind;
16138 
16139  where = idxcopy(nvtxs, graph->where, idxwspacemalloc(ctrl, nvtxs));
16140 
16141  /* Put the nodes in the boundary into the separator */
16142  for (i=0; i<nbnd; i++) {
16143  j = bndind[i];
16144  if (xadj[j+1]-xadj[j] > 0) /* Ignore islands */
16145  where[j] = 2;
16146  }
16147 
16148  GKfree((void **) &graph->rdata, LTERM);
16149  Allocate2WayNodePartitionMemory(ctrl, graph);
16150  idxcopy(nvtxs, where, graph->where);
16151  idxwspacefree(ctrl, nvtxs);
16152 
16153  ASSERT(IsSeparable(graph));
16154 
16155  Compute2WayNodePartitionParams(ctrl, graph);
16156 
16158 
16159  FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
16160 
16161  ASSERT(IsSeparable(graph));
16162 }
16163 
16164 
16165 
16166 /*************************************************************************
16167 * This function takes a bisection and constructs a minimum weight vertex
16168 * separator out of it. It uses an unweighted minimum-cover algorithm
16169 * followed by node-based separator refinement.
16170 **************************************************************************/
16171 void ConstructMinCoverSeparator0(CtrlType *ctrl, GraphType *graph, float ubfactor)
16172 {
16173  int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize;
16174  idxtype *xadj, *adjncy, *bxadj, *badjncy;
16175  idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover;
16176 
16177 
16178  nvtxs = graph->nvtxs;
16179  xadj = graph->xadj;
16180  adjncy = graph->adjncy;
16181 
16182  nbnd = graph->nbnd;
16183  bndind = graph->bndind;
16184  bndptr = graph->bndptr;
16185  where = graph->where;
16186 
16187  vmap = idxwspacemalloc(ctrl, nvtxs);
16188  ivmap = idxwspacemalloc(ctrl, nbnd);
16189  cover = idxwspacemalloc(ctrl, nbnd);
16190 
16191  if (nbnd > 0) {
16192  /* Go through the boundary and determine the sizes of the bipartite graph */
16193  bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0;
16194  for (i=0; i<nbnd; i++) {
16195  j = bndind[i];
16196  k = where[j];
16197  if (xadj[j+1]-xadj[j] > 0) {
16198  bnvtxs[k]++;
16199  bnedges[k] += xadj[j+1]-xadj[j];
16200  }
16201  }
16202 
16203  bnvtxs[2] = bnvtxs[0]+bnvtxs[1];
16204  bnvtxs[1] = bnvtxs[0];
16205  bnvtxs[0] = 0;
16206 
16207  bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj");
16208  badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy");
16209 
16210  /* Construct the ivmap and vmap */
16211  ASSERT(idxset(nvtxs, -1, vmap) == vmap);
16212  for (i=0; i<nbnd; i++) {
16213  j = bndind[i];
16214  k = where[j];
16215  if (xadj[j+1]-xadj[j] > 0) {
16216  vmap[j] = bnvtxs[k];
16217  ivmap[bnvtxs[k]++] = j;
16218  }
16219  }
16220 
16221  /* OK, go through and put the vertices of each part starting from 0 */
16222  bnvtxs[1] = bnvtxs[0];
16223  bnvtxs[0] = 0;
16224  bxadj[0] = l = 0;
16225  for (k=0; k<2; k++) {
16226  for (ii=0; ii<nbnd; ii++) {
16227  i = bndind[ii];
16228  if (where[i] == k && xadj[i] < xadj[i+1]) {
16229  for (j=xadj[i]; j<xadj[i+1]; j++) {
16230  jj = adjncy[j];
16231  if (where[jj] != k) {
16232  ASSERT(bndptr[jj] != -1);
16233  ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj]));
16234  badjncy[l++] = vmap[jj];
16235  }
16236  }
16237  bxadj[++bnvtxs[k]] = l;
16238  }
16239  }
16240  }
16241 
16242  ASSERT(l <= bnedges[0]+bnedges[1]);
16243 
16244  MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize);
16245 
16246  IFSET(ctrl->dbglvl, DBG_SEPINFO,
16247  printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize));
16248 
16249  for (i=0; i<csize; i++) {
16250  j = ivmap[cover[i]];
16251  where[j] = 2;
16252  }
16253 
16254  GKfree((void **) &bxadj, (void **) &badjncy, LTERM);
16255 
16256  for (i=0; i<nbnd; i++)
16257  bndptr[bndind[i]] = -1;
16258  for (nbnd=i=0; i<nvtxs; i++) {
16259  if (where[i] == 2) {
16260  bndind[nbnd] = i;
16261  bndptr[i] = nbnd++;
16262  }
16263  }
16264  }
16265  else {
16266  IFSET(ctrl->dbglvl, DBG_SEPINFO,
16267  printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0));
16268  }
16269 
16270  idxwspacefree(ctrl, nvtxs);
16271  idxwspacefree(ctrl, graph->nbnd);
16272  idxwspacefree(ctrl, graph->nbnd);
16273  graph->nbnd = nbnd;
16274 
16275 
16276  ASSERT(IsSeparable(graph));
16277 }
16278 
16279 
16280 
16281 /*************************************************************************
16282 * This function takes a bisection and constructs a minimum weight vertex
16283 * separator out of it. It uses an unweighted minimum-cover algorithm
16284 * followed by node-based separator refinement.
16285 **************************************************************************/
16286 void ConstructMinCoverSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
16287 {
16288  int i, ii, j, jj, k, l, nvtxs, nbnd, bnvtxs[3], bnedges[2], csize;
16289  idxtype *xadj, *adjncy, *bxadj, *badjncy;
16290  idxtype *where, *bndind, *bndptr, *vmap, *ivmap, *cover;
16291 
16292 
16293  nvtxs = graph->nvtxs;
16294  xadj = graph->xadj;
16295  adjncy = graph->adjncy;
16296 
16297  nbnd = graph->nbnd;
16298  bndind = graph->bndind;
16299  bndptr = graph->bndptr;
16300  where = graph->where;
16301 
16302  vmap = idxwspacemalloc(ctrl, nvtxs);
16303  ivmap = idxwspacemalloc(ctrl, nbnd);
16304  cover = idxwspacemalloc(ctrl, nbnd);
16305 
16306  if (nbnd > 0) {
16307  /* Go through the boundary and determine the sizes of the bipartite graph */
16308  bnvtxs[0] = bnvtxs[1] = bnedges[0] = bnedges[1] = 0;
16309  for (i=0; i<nbnd; i++) {
16310  j = bndind[i];
16311  k = where[j];
16312  if (xadj[j+1]-xadj[j] > 0) {
16313  bnvtxs[k]++;
16314  bnedges[k] += xadj[j+1]-xadj[j];
16315  }
16316  }
16317 
16318  bnvtxs[2] = bnvtxs[0]+bnvtxs[1];
16319  bnvtxs[1] = bnvtxs[0];
16320  bnvtxs[0] = 0;
16321 
16322  bxadj = idxmalloc(bnvtxs[2]+1, "ConstructMinCoverSeparator: bxadj");
16323  badjncy = idxmalloc(bnedges[0]+bnedges[1]+1, "ConstructMinCoverSeparator: badjncy");
16324 
16325  /* Construct the ivmap and vmap */
16326  ASSERT(idxset(nvtxs, -1, vmap) == vmap);
16327  for (i=0; i<nbnd; i++) {
16328  j = bndind[i];
16329  k = where[j];
16330  if (xadj[j+1]-xadj[j] > 0) {
16331  vmap[j] = bnvtxs[k];
16332  ivmap[bnvtxs[k]++] = j;
16333  }
16334  }
16335 
16336  /* OK, go through and put the vertices of each part starting from 0 */
16337  bnvtxs[1] = bnvtxs[0];
16338  bnvtxs[0] = 0;
16339  bxadj[0] = l = 0;
16340  for (k=0; k<2; k++) {
16341  for (ii=0; ii<nbnd; ii++) {
16342  i = bndind[ii];
16343  if (where[i] == k && xadj[i] < xadj[i+1]) {
16344  for (j=xadj[i]; j<xadj[i+1]; j++) {
16345  jj = adjncy[j];
16346  if (where[jj] != k) {
16347  ASSERT(bndptr[jj] != -1);
16348  ASSERTP(vmap[jj] != -1, ("%d %d %d\n", jj, vmap[jj], graph->bndptr[jj]));
16349  badjncy[l++] = vmap[jj];
16350  }
16351  }
16352  bxadj[++bnvtxs[k]] = l;
16353  }
16354  }
16355  }
16356 
16357  ASSERT(l <= bnedges[0]+bnedges[1]);
16358 
16359  MinCover(bxadj, badjncy, bnvtxs[0], bnvtxs[1], cover, &csize);
16360 
16361  IFSET(ctrl->dbglvl, DBG_SEPINFO,
16362  printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, bnvtxs[0], bnvtxs[1]-bnvtxs[0], csize));
16363 
16364  for (i=0; i<csize; i++) {
16365  j = ivmap[cover[i]];
16366  where[j] = 2;
16367  }
16368 
16369  GKfree((void **) &bxadj, (void **) &badjncy, LTERM);
16370  }
16371  else {
16372  IFSET(ctrl->dbglvl, DBG_SEPINFO,
16373  printf("Nvtxs: %6d, [%5d %5d], Cut: %6d, SS: [%6d %6d], Cover: %6d\n", nvtxs, graph->pwgts[0], graph->pwgts[1], graph->mincut, 0, 0, 0));
16374  }
16375 
16376  /* Prepare to refine the vertex separator */
16377  idxcopy(nvtxs, graph->where, vmap);
16378  GKfree((void **) &graph->rdata, LTERM);
16379 
16380  Allocate2WayNodePartitionMemory(ctrl, graph);
16381  idxcopy(nvtxs, vmap, graph->where);
16382  idxwspacefree(ctrl, nvtxs+2*graph->nbnd);
16383 
16384  Compute2WayNodePartitionParams(ctrl, graph);
16385 
16387 
16388  FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 6);
16389 
16390  ASSERT(IsSeparable(graph));
16391 }
16392 
16393 /*
16394  * Copyright 1997, Regents of the University of Minnesota
16395  *
16396  * sfm.c
16397  *
16398  * This file contains code that implementes an FM-based separator refinement
16399  *
16400  * Started 8/1/97
16401  * George
16402  *
16403  * $Id$
16404  *
16405  */
16406 
16407 
16408 
16409 
16410 /*************************************************************************
16411 * This function performs a node-based FM refinement
16412 **************************************************************************/
16413 void FM_2WayNodeRefine(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
16414 {
16415  int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
16416  idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
16417  idxtype *mptr, *mind, *moved, *swaps, *perm;
16418  PQueueType parts[2];
16419  NRInfoType *rinfo;
16420  int higain, oldgain, mincut, initcut, mincutorder;
16421  int pass, to, other, limit;
16422  int badmaxpwgt, mindiff, newdiff;
16423  int u[2], g[2];
16424 
16425  nvtxs = graph->nvtxs;
16426  xadj = graph->xadj;
16427  adjncy = graph->adjncy;
16428  vwgt = graph->vwgt;
16429 
16430  bndind = graph->bndind;
16431  bndptr = graph->bndptr;
16432  where = graph->where;
16433  pwgts = graph->pwgts;
16434  rinfo = graph->nrinfo;
16435 
16436 
16437  i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt);
16438  PQueueInit(ctrl, &parts[0], nvtxs, i);
16439  PQueueInit(ctrl, &parts[1], nvtxs, i);
16440 
16441  moved = idxwspacemalloc(ctrl, nvtxs);
16442  swaps = idxwspacemalloc(ctrl, nvtxs);
16443  mptr = idxwspacemalloc(ctrl, nvtxs+1);
16444  mind = idxwspacemalloc(ctrl, nvtxs);
16445  perm = idxwspacemalloc(ctrl, nvtxs);
16446 
16447  IFSET(ctrl->dbglvl, DBG_REFINE,
16448  printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
16449 
16450  badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2);
16451 
16452  for (pass=0; pass<npasses; pass++) {
16453  idxset(nvtxs, -1, moved);
16454  PQueueReset(&parts[0]);
16455  PQueueReset(&parts[1]);
16456 
16457  mincutorder = -1;
16458  initcut = mincut = graph->mincut;
16459  nbnd = graph->nbnd;
16460 
16461  RandomPermute(nbnd, perm, 1);
16462  for (ii=0; ii<nbnd; ii++) {
16463  i = bndind[perm[ii]];
16464  ASSERT(where[i] == 2);
16465  PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]);
16466  PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]);
16467  }
16468 
16469  ASSERT(CheckNodeBnd(graph, nbnd));
16471 
16472  limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
16473 
16474  /******************************************************
16475  * Get into the FM loop
16476  *******************************************************/
16477  mptr[0] = nmind = 0;
16478  mindiff = abs(pwgts[0]-pwgts[1]);
16479  to = (pwgts[0] < pwgts[1] ? 0 : 1);
16480  for (nswaps=0; nswaps<nvtxs; nswaps++) {
16481  u[0] = PQueueSeeMax(&parts[0]);
16482  u[1] = PQueueSeeMax(&parts[1]);
16483  if (u[0] != -1 && u[1] != -1) {
16484  g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
16485  g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
16486 
16487  to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));
16488  /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */
16489 
16490  if (pwgts[to]+vwgt[u[to]] > badmaxpwgt)
16491  to = (to+1)%2;
16492  }
16493  else if (u[0] == -1 && u[1] == -1) {
16494  break;
16495  }
16496  else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) {
16497  to = 0;
16498  }
16499  else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) {
16500  to = 1;
16501  }
16502  else
16503  break;
16504 
16505  other = (to+1)%2;
16506 
16507  higain = PQueueGetMax(&parts[to]);
16508  if (moved[higain] == -1) /* Delete if it was in the separator originally */
16509  PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]);
16510 
16511  ASSERT(bndptr[higain] != -1);
16512 
16513  pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
16514 
16515  newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
16516  if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
16517  mincut = pwgts[2];
16518  mincutorder = nswaps;
16519  mindiff = newdiff;
16520  }
16521  else {
16522  if (nswaps - mincutorder > limit) {
16523  pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
16524  break; /* No further improvement, break out */
16525  }
16526  }
16527 
16528  BNDDelete(nbnd, bndind, bndptr, higain);
16529  pwgts[to] += vwgt[higain];
16530  where[higain] = to;
16531  moved[higain] = nswaps;
16532  swaps[nswaps] = higain;
16533 
16534 
16535  /**********************************************************
16536  * Update the degrees of the affected nodes
16537  ***********************************************************/
16538  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
16539  k = adjncy[j];
16540  if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
16541  oldgain = vwgt[k]-rinfo[k].edegrees[to];
16542  rinfo[k].edegrees[to] += vwgt[higain];
16543  if (moved[k] == -1 || moved[k] == -(2+other))
16544  PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]);
16545  }
16546  else if (where[k] == other) { /* This vertex is pulled into the separator */
16547  ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
16548  BNDInsert(nbnd, bndind, bndptr, k);
16549 
16550  mind[nmind++] = k; /* Keep track for rollback */
16551  where[k] = 2;
16552  pwgts[other] -= vwgt[k];
16553 
16554  edegrees = rinfo[k].edegrees;
16555  edegrees[0] = edegrees[1] = 0;
16556  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
16557  kk = adjncy[jj];
16558  if (where[kk] != 2)
16559  edegrees[where[kk]] += vwgt[kk];
16560  else {
16561  oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
16562  rinfo[kk].edegrees[other] -= vwgt[k];
16563  if (moved[kk] == -1 || moved[kk] == -(2+to))
16564  PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]);
16565  }
16566  }
16567 
16568  /* Insert the new vertex into the priority queue. Only one side! */
16569  if (moved[k] == -1) {
16570  PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]);
16571  moved[k] = -(2+to);
16572  }
16573  }
16574  }
16575  mptr[nswaps+1] = nmind;
16576 
16577  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
16578  printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
16579 
16580  }
16581 
16582 
16583  /****************************************************************
16584  * Roll back computation
16585  *****************************************************************/
16586  for (nswaps--; nswaps>mincutorder; nswaps--) {
16587  higain = swaps[nswaps];
16588 
16590 
16591  to = where[higain];
16592  other = (to+1)%2;
16593  INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
16594  where[higain] = 2;
16595  BNDInsert(nbnd, bndind, bndptr, higain);
16596 
16597  edegrees = rinfo[higain].edegrees;
16598  edegrees[0] = edegrees[1] = 0;
16599  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
16600  k = adjncy[j];
16601  if (where[k] == 2)
16602  rinfo[k].edegrees[to] -= vwgt[higain];
16603  else
16604  edegrees[where[k]] += vwgt[k];
16605  }
16606 
16607  /* Push nodes out of the separator */
16608  for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
16609  k = mind[j];
16610  ASSERT(where[k] == 2);
16611  where[k] = other;
16612  INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
16613  BNDDelete(nbnd, bndind, bndptr, k);
16614  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
16615  kk = adjncy[jj];
16616  if (where[kk] == 2)
16617  rinfo[kk].edegrees[other] += vwgt[k];
16618  }
16619  }
16620  }
16621 
16622  ASSERT(mincut == pwgts[2]);
16623 
16624  IFSET(ctrl->dbglvl, DBG_REFINE,
16625  printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
16626 
16627  graph->mincut = mincut;
16628  graph->nbnd = nbnd;
16629 
16630  if (mincutorder == -1 || mincut >= initcut)
16631  break;
16632  }
16633 
16634  PQueueFree(ctrl, &parts[0]);
16635  PQueueFree(ctrl, &parts[1]);
16636 
16637  idxwspacefree(ctrl, nvtxs+1);
16638  idxwspacefree(ctrl, nvtxs);
16639  idxwspacefree(ctrl, nvtxs);
16640  idxwspacefree(ctrl, nvtxs);
16641  idxwspacefree(ctrl, nvtxs);
16642 }
16643 
16644 
16645 /*************************************************************************
16646 * This function performs a node-based FM refinement
16647 **************************************************************************/
16648 void FM_2WayNodeRefine2(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
16649 {
16650  int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
16651  idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
16652  idxtype *mptr, *mind, *moved, *swaps, *perm;
16653  PQueueType parts[2];
16654  NRInfoType *rinfo;
16655  int higain, oldgain, mincut, initcut, mincutorder;
16656  int pass, to, other, limit;
16657  int badmaxpwgt, mindiff, newdiff;
16658  int u[2], g[2];
16659 
16660  nvtxs = graph->nvtxs;
16661  xadj = graph->xadj;
16662  adjncy = graph->adjncy;
16663  vwgt = graph->vwgt;
16664 
16665  bndind = graph->bndind;
16666  bndptr = graph->bndptr;
16667  where = graph->where;
16668  pwgts = graph->pwgts;
16669  rinfo = graph->nrinfo;
16670 
16671 
16672  i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt);
16673  PQueueInit(ctrl, &parts[0], nvtxs, i);
16674  PQueueInit(ctrl, &parts[1], nvtxs, i);
16675 
16676  moved = idxwspacemalloc(ctrl, nvtxs);
16677  swaps = idxwspacemalloc(ctrl, nvtxs);
16678  mptr = idxwspacemalloc(ctrl, nvtxs+1);
16679  mind = idxwspacemalloc(ctrl, nvtxs);
16680  perm = idxwspacemalloc(ctrl, nvtxs);
16681 
16682  IFSET(ctrl->dbglvl, DBG_REFINE,
16683  printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
16684 
16685  badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2);
16686 
16687  for (pass=0; pass<npasses; pass++) {
16688  idxset(nvtxs, -1, moved);
16689  PQueueReset(&parts[0]);
16690  PQueueReset(&parts[1]);
16691 
16692  mincutorder = -1;
16693  initcut = mincut = graph->mincut;
16694  nbnd = graph->nbnd;
16695 
16696  RandomPermute(nbnd, perm, 1);
16697  for (ii=0; ii<nbnd; ii++) {
16698  i = bndind[perm[ii]];
16699  ASSERT(where[i] == 2);
16700  PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]);
16701  PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]);
16702  }
16703 
16704  ASSERT(CheckNodeBnd(graph, nbnd));
16706 
16707  limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
16708 
16709  /******************************************************
16710  * Get into the FM loop
16711  *******************************************************/
16712  mptr[0] = nmind = 0;
16713  mindiff = abs(pwgts[0]-pwgts[1]);
16714  to = (pwgts[0] < pwgts[1] ? 0 : 1);
16715  for (nswaps=0; nswaps<nvtxs; nswaps++) {
16716  badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2]/2)/2);
16717 
16718  u[0] = PQueueSeeMax(&parts[0]);
16719  u[1] = PQueueSeeMax(&parts[1]);
16720  if (u[0] != -1 && u[1] != -1) {
16721  g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
16722  g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
16723 
16724  to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));
16725  /* to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : (pwgts[0] < pwgts[1] ? 0 : 1))); */
16726 
16727  if (pwgts[to]+vwgt[u[to]] > badmaxpwgt)
16728  to = (to+1)%2;
16729  }
16730  else if (u[0] == -1 && u[1] == -1) {
16731  break;
16732  }
16733  else if (u[0] != -1 && pwgts[0]+vwgt[u[0]] <= badmaxpwgt) {
16734  to = 0;
16735  }
16736  else if (u[1] != -1 && pwgts[1]+vwgt[u[1]] <= badmaxpwgt) {
16737  to = 1;
16738  }
16739  else
16740  break;
16741 
16742  other = (to+1)%2;
16743 
16744  higain = PQueueGetMax(&parts[to]);
16745  if (moved[higain] == -1) /* Delete if it was in the separator originally */
16746  PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]);
16747 
16748  ASSERT(bndptr[higain] != -1);
16749 
16750  pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
16751 
16752  newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
16753  if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
16754  mincut = pwgts[2];
16755  mincutorder = nswaps;
16756  mindiff = newdiff;
16757  }
16758  else {
16759  if (nswaps - mincutorder > limit) {
16760  pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
16761  break; /* No further improvement, break out */
16762  }
16763  }
16764 
16765  BNDDelete(nbnd, bndind, bndptr, higain);
16766  pwgts[to] += vwgt[higain];
16767  where[higain] = to;
16768  moved[higain] = nswaps;
16769  swaps[nswaps] = higain;
16770 
16771 
16772  /**********************************************************
16773  * Update the degrees of the affected nodes
16774  ***********************************************************/
16775  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
16776  k = adjncy[j];
16777  if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
16778  oldgain = vwgt[k]-rinfo[k].edegrees[to];
16779  rinfo[k].edegrees[to] += vwgt[higain];
16780  if (moved[k] == -1 || moved[k] == -(2+other))
16781  PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]);
16782  }
16783  else if (where[k] == other) { /* This vertex is pulled into the separator */
16784  ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
16785  BNDInsert(nbnd, bndind, bndptr, k);
16786 
16787  mind[nmind++] = k; /* Keep track for rollback */
16788  where[k] = 2;
16789  pwgts[other] -= vwgt[k];
16790 
16791  edegrees = rinfo[k].edegrees;
16792  edegrees[0] = edegrees[1] = 0;
16793  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
16794  kk = adjncy[jj];
16795  if (where[kk] != 2)
16796  edegrees[where[kk]] += vwgt[kk];
16797  else {
16798  oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
16799  rinfo[kk].edegrees[other] -= vwgt[k];
16800  if (moved[kk] == -1 || moved[kk] == -(2+to))
16801  PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]);
16802  }
16803  }
16804 
16805  /* Insert the new vertex into the priority queue. Only one side! */
16806  if (moved[k] == -1) {
16807  PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]);
16808  moved[k] = -(2+to);
16809  }
16810  }
16811  }
16812  mptr[nswaps+1] = nmind;
16813 
16814  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
16815  printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
16816 
16817  }
16818 
16819 
16820  /****************************************************************
16821  * Roll back computation
16822  *****************************************************************/
16823  for (nswaps--; nswaps>mincutorder; nswaps--) {
16824  higain = swaps[nswaps];
16825 
16827 
16828  to = where[higain];
16829  other = (to+1)%2;
16830  INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
16831  where[higain] = 2;
16832  BNDInsert(nbnd, bndind, bndptr, higain);
16833 
16834  edegrees = rinfo[higain].edegrees;
16835  edegrees[0] = edegrees[1] = 0;
16836  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
16837  k = adjncy[j];
16838  if (where[k] == 2)
16839  rinfo[k].edegrees[to] -= vwgt[higain];
16840  else
16841  edegrees[where[k]] += vwgt[k];
16842  }
16843 
16844  /* Push nodes out of the separator */
16845  for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
16846  k = mind[j];
16847  ASSERT(where[k] == 2);
16848  where[k] = other;
16849  INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
16850  BNDDelete(nbnd, bndind, bndptr, k);
16851  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
16852  kk = adjncy[jj];
16853  if (where[kk] == 2)
16854  rinfo[kk].edegrees[other] += vwgt[k];
16855  }
16856  }
16857  }
16858 
16859  ASSERT(mincut == pwgts[2]);
16860 
16861  IFSET(ctrl->dbglvl, DBG_REFINE,
16862  printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
16863 
16864  graph->mincut = mincut;
16865  graph->nbnd = nbnd;
16866 
16867  if (mincutorder == -1 || mincut >= initcut)
16868  break;
16869  }
16870 
16871  PQueueFree(ctrl, &parts[0]);
16872  PQueueFree(ctrl, &parts[1]);
16873 
16874  idxwspacefree(ctrl, nvtxs+1);
16875  idxwspacefree(ctrl, nvtxs);
16876  idxwspacefree(ctrl, nvtxs);
16877  idxwspacefree(ctrl, nvtxs);
16878  idxwspacefree(ctrl, nvtxs);
16879 }
16880 
16881 
16882 /*************************************************************************
16883 * This function performs a node-based FM refinement
16884 **************************************************************************/
16885 void FM_2WayNodeRefineEqWgt(CtrlType *ctrl, GraphType *graph, int npasses)
16886 {
16887  int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
16888  idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
16889  idxtype *mptr, *mind, *moved, *swaps, *perm;
16890  PQueueType parts[2];
16891  NRInfoType *rinfo;
16892  int higain, oldgain, mincut, initcut, mincutorder;
16893  int pass, to, other, limit;
16894  int mindiff, newdiff;
16895  int u[2], g[2];
16896 
16897  nvtxs = graph->nvtxs;
16898  xadj = graph->xadj;
16899  adjncy = graph->adjncy;
16900  vwgt = graph->vwgt;
16901 
16902  bndind = graph->bndind;
16903  bndptr = graph->bndptr;
16904  where = graph->where;
16905  pwgts = graph->pwgts;
16906  rinfo = graph->nrinfo;
16907 
16908 
16909  i = ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt);
16910  PQueueInit(ctrl, &parts[0], nvtxs, i);
16911  PQueueInit(ctrl, &parts[1], nvtxs, i);
16912 
16913  moved = idxwspacemalloc(ctrl, nvtxs);
16914  swaps = idxwspacemalloc(ctrl, nvtxs);
16915  mptr = idxwspacemalloc(ctrl, nvtxs+1);
16916  mind = idxwspacemalloc(ctrl, nvtxs);
16917  perm = idxwspacemalloc(ctrl, nvtxs);
16918 
16919  IFSET(ctrl->dbglvl, DBG_REFINE,
16920  printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
16921 
16922  for (pass=0; pass<npasses; pass++) {
16923  idxset(nvtxs, -1, moved);
16924  PQueueReset(&parts[0]);
16925  PQueueReset(&parts[1]);
16926 
16927  mincutorder = -1;
16928  initcut = mincut = graph->mincut;
16929  nbnd = graph->nbnd;
16930 
16931  RandomPermute(nbnd, perm, 1);
16932  for (ii=0; ii<nbnd; ii++) {
16933  i = bndind[perm[ii]];
16934  ASSERT(where[i] == 2);
16935  PQueueInsert(&parts[0], i, vwgt[i]-rinfo[i].edegrees[1]);
16936  PQueueInsert(&parts[1], i, vwgt[i]-rinfo[i].edegrees[0]);
16937  }
16938 
16939  ASSERT(CheckNodeBnd(graph, nbnd));
16941 
16942  limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
16943 
16944  /******************************************************
16945  * Get into the FM loop
16946  *******************************************************/
16947  mptr[0] = nmind = 0;
16948  mindiff = abs(pwgts[0]-pwgts[1]);
16949  to = (pwgts[0] < pwgts[1] ? 0 : 1);
16950  for (nswaps=0; nswaps<nvtxs; nswaps++) {
16951  to = (pwgts[0] < pwgts[1] ? 0 : 1);
16952 
16953  if (pwgts[0] == pwgts[1]) {
16954  u[0] = PQueueSeeMax(&parts[0]);
16955  u[1] = PQueueSeeMax(&parts[1]);
16956  if (u[0] != -1 && u[1] != -1) {
16957  g[0] = vwgt[u[0]]-rinfo[u[0]].edegrees[1];
16958  g[1] = vwgt[u[1]]-rinfo[u[1]].edegrees[0];
16959 
16960  to = (g[0] > g[1] ? 0 : (g[0] < g[1] ? 1 : pass%2));
16961  }
16962  }
16963  other = (to+1)%2;
16964 
16965  if ((higain = PQueueGetMax(&parts[to])) == -1)
16966  break;
16967 
16968  if (moved[higain] == -1) /* Delete if it was in the separator originally */
16969  PQueueDelete(&parts[other], higain, vwgt[higain]-rinfo[higain].edegrees[to]);
16970 
16971  ASSERT(bndptr[higain] != -1);
16972 
16973  pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
16974 
16975  newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
16976  if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
16977  mincut = pwgts[2];
16978  mincutorder = nswaps;
16979  mindiff = newdiff;
16980  }
16981  else {
16982  if (nswaps - mincutorder > limit) {
16983  pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
16984  break; /* No further improvement, break out */
16985  }
16986  }
16987 
16988  BNDDelete(nbnd, bndind, bndptr, higain);
16989  pwgts[to] += vwgt[higain];
16990  where[higain] = to;
16991  moved[higain] = nswaps;
16992  swaps[nswaps] = higain;
16993 
16994 
16995  /**********************************************************
16996  * Update the degrees of the affected nodes
16997  ***********************************************************/
16998  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
16999  k = adjncy[j];
17000  if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
17001  oldgain = vwgt[k]-rinfo[k].edegrees[to];
17002  rinfo[k].edegrees[to] += vwgt[higain];
17003  if (moved[k] == -1 || moved[k] == -(2+other))
17004  PQueueUpdate(&parts[other], k, oldgain, oldgain-vwgt[higain]);
17005  }
17006  else if (where[k] == other) { /* This vertex is pulled into the separator */
17007  ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
17008  BNDInsert(nbnd, bndind, bndptr, k);
17009 
17010  mind[nmind++] = k; /* Keep track for rollback */
17011  where[k] = 2;
17012  pwgts[other] -= vwgt[k];
17013 
17014  edegrees = rinfo[k].edegrees;
17015  edegrees[0] = edegrees[1] = 0;
17016  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
17017  kk = adjncy[jj];
17018  if (where[kk] != 2)
17019  edegrees[where[kk]] += vwgt[kk];
17020  else {
17021  oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
17022  rinfo[kk].edegrees[other] -= vwgt[k];
17023  if (moved[kk] == -1 || moved[kk] == -(2+to))
17024  PQueueUpdate(&parts[to], kk, oldgain, oldgain+vwgt[k]);
17025  }
17026  }
17027 
17028  /* Insert the new vertex into the priority queue. Only one side! */
17029  if (moved[k] == -1) {
17030  PQueueInsert(&parts[to], k, vwgt[k]-edegrees[other]);
17031  moved[k] = -(2+to);
17032  }
17033  }
17034  }
17035  mptr[nswaps+1] = nmind;
17036 
17037  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
17038  printf("Moved %6d to %3d, Gain: %5d [%5d] [%4d %4d] \t[%5d %5d %5d]\n", higain, to, g[to], g[other], vwgt[u[to]], vwgt[u[other]], pwgts[0], pwgts[1], pwgts[2]));
17039 
17040  }
17041 
17042 
17043  /****************************************************************
17044  * Roll back computation
17045  *****************************************************************/
17046  for (nswaps--; nswaps>mincutorder; nswaps--) {
17047  higain = swaps[nswaps];
17048 
17050 
17051  to = where[higain];
17052  other = (to+1)%2;
17053  INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
17054  where[higain] = 2;
17055  BNDInsert(nbnd, bndind, bndptr, higain);
17056 
17057  edegrees = rinfo[higain].edegrees;
17058  edegrees[0] = edegrees[1] = 0;
17059  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
17060  k = adjncy[j];
17061  if (where[k] == 2)
17062  rinfo[k].edegrees[to] -= vwgt[higain];
17063  else
17064  edegrees[where[k]] += vwgt[k];
17065  }
17066 
17067  /* Push nodes out of the separator */
17068  for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
17069  k = mind[j];
17070  ASSERT(where[k] == 2);
17071  where[k] = other;
17072  INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
17073  BNDDelete(nbnd, bndind, bndptr, k);
17074  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
17075  kk = adjncy[jj];
17076  if (where[kk] == 2)
17077  rinfo[kk].edegrees[other] += vwgt[k];
17078  }
17079  }
17080  }
17081 
17082  ASSERT(mincut == pwgts[2]);
17083 
17084  IFSET(ctrl->dbglvl, DBG_REFINE,
17085  printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
17086 
17087  graph->mincut = mincut;
17088  graph->nbnd = nbnd;
17089 
17090  if (mincutorder == -1 || mincut >= initcut)
17091  break;
17092  }
17093 
17094  PQueueFree(ctrl, &parts[0]);
17095  PQueueFree(ctrl, &parts[1]);
17096 
17097  idxwspacefree(ctrl, nvtxs+1);
17098  idxwspacefree(ctrl, nvtxs);
17099  idxwspacefree(ctrl, nvtxs);
17100  idxwspacefree(ctrl, nvtxs);
17101  idxwspacefree(ctrl, nvtxs);
17102 }
17103 
17104 
17105 /*************************************************************************
17106 * This function performs a node-based FM refinement. This is the
17107 * one-way version
17108 **************************************************************************/
17109 void FM_2WayNodeRefine_OneSided(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
17110 {
17111  int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps, nmind;
17112  idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
17113  idxtype *mptr, *mind, *swaps, *perm;
17114  PQueueType parts;
17115  NRInfoType *rinfo;
17116  int higain, oldgain, mincut, initcut, mincutorder;
17117  int pass, to, other, limit;
17118  int badmaxpwgt, mindiff, newdiff;
17119 
17120  nvtxs = graph->nvtxs;
17121  xadj = graph->xadj;
17122  adjncy = graph->adjncy;
17123  vwgt = graph->vwgt;
17124 
17125  bndind = graph->bndind;
17126  bndptr = graph->bndptr;
17127  where = graph->where;
17128  pwgts = graph->pwgts;
17129  rinfo = graph->nrinfo;
17130 
17131  PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt));
17132 
17133  perm = idxwspacemalloc(ctrl, nvtxs);
17134  swaps = idxwspacemalloc(ctrl, nvtxs);
17135  mptr = idxwspacemalloc(ctrl, nvtxs);
17136  mind = idxwspacemalloc(ctrl, nvtxs+1);
17137 
17138  IFSET(ctrl->dbglvl, DBG_REFINE,
17139  printf("Partitions-N1: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
17140 
17141  badmaxpwgt = (int)(ubfactor*(pwgts[0]+pwgts[1]+pwgts[2])/2);
17142 
17143  to = (pwgts[0] < pwgts[1] ? 1 : 0);
17144  for (pass=0; pass<npasses; pass++) {
17145  other = to;
17146  to = (to+1)%2;
17147 
17148  PQueueReset(&parts);
17149 
17150  mincutorder = -1;
17151  initcut = mincut = graph->mincut;
17152  nbnd = graph->nbnd;
17153 
17154  RandomPermute(nbnd, perm, 1);
17155  for (ii=0; ii<nbnd; ii++) {
17156  i = bndind[perm[ii]];
17157  ASSERT(where[i] == 2);
17158  PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]);
17159  }
17160 
17161  ASSERT(CheckNodeBnd(graph, nbnd));
17163 
17164  limit = (ctrl->oflags&OFLAG_COMPRESS ? amin(5*nbnd, 400) : amin(2*nbnd, 300));
17165 
17166  /******************************************************
17167  * Get into the FM loop
17168  *******************************************************/
17169  mptr[0] = nmind = 0;
17170  mindiff = abs(pwgts[0]-pwgts[1]);
17171  for (nswaps=0; nswaps<nvtxs; nswaps++) {
17172 
17173  if ((higain = PQueueGetMax(&parts)) == -1)
17174  break;
17175 
17176  ASSERT(bndptr[higain] != -1);
17177 
17178  if (pwgts[to]+vwgt[higain] > badmaxpwgt)
17179  break; /* No point going any further. Balance will be bad */
17180 
17181  pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
17182 
17183  newdiff = abs(pwgts[to]+vwgt[higain] - (pwgts[other]-rinfo[higain].edegrees[other]));
17184  if (pwgts[2] < mincut || (pwgts[2] == mincut && newdiff < mindiff)) {
17185  mincut = pwgts[2];
17186  mincutorder = nswaps;
17187  mindiff = newdiff;
17188  }
17189  else {
17190  if (nswaps - mincutorder > limit) {
17191  pwgts[2] += (vwgt[higain]-rinfo[higain].edegrees[other]);
17192  break; /* No further improvement, break out */
17193  }
17194  }
17195 
17196  BNDDelete(nbnd, bndind, bndptr, higain);
17197  pwgts[to] += vwgt[higain];
17198  where[higain] = to;
17199  swaps[nswaps] = higain;
17200 
17201 
17202  /**********************************************************
17203  * Update the degrees of the affected nodes
17204  ***********************************************************/
17205  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
17206  k = adjncy[j];
17207  if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
17208  rinfo[k].edegrees[to] += vwgt[higain];
17209  }
17210  else if (where[k] == other) { /* This vertex is pulled into the separator */
17211  ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
17212  BNDInsert(nbnd, bndind, bndptr, k);
17213 
17214  mind[nmind++] = k; /* Keep track for rollback */
17215  where[k] = 2;
17216  pwgts[other] -= vwgt[k];
17217 
17218  edegrees = rinfo[k].edegrees;
17219  edegrees[0] = edegrees[1] = 0;
17220  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
17221  kk = adjncy[jj];
17222  if (where[kk] != 2)
17223  edegrees[where[kk]] += vwgt[kk];
17224  else {
17225  oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
17226  rinfo[kk].edegrees[other] -= vwgt[k];
17227 
17228  /* Since the moves are one-sided this vertex has not been moved yet */
17229  PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]);
17230  }
17231  }
17232 
17233  /* Insert the new vertex into the priority queue. Safe due to one-sided moves */
17234  PQueueInsert(&parts, k, vwgt[k]-edegrees[other]);
17235  }
17236  }
17237  mptr[nswaps+1] = nmind;
17238 
17239 
17240  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
17241  printf("Moved %6d to %3d, Gain: %5d [%5d] \t[%5d %5d %5d] [%3d %2d]\n",
17242  higain, to, (vwgt[higain]-rinfo[higain].edegrees[other]), vwgt[higain], pwgts[0], pwgts[1], pwgts[2], nswaps, limit));
17243 
17244  }
17245 
17246 
17247  /****************************************************************
17248  * Roll back computation
17249  *****************************************************************/
17250  for (nswaps--; nswaps>mincutorder; nswaps--) {
17251  higain = swaps[nswaps];
17252 
17254  ASSERT(where[higain] == to);
17255 
17256  INC_DEC(pwgts[2], pwgts[to], vwgt[higain]);
17257  where[higain] = 2;
17258  BNDInsert(nbnd, bndind, bndptr, higain);
17259 
17260  edegrees = rinfo[higain].edegrees;
17261  edegrees[0] = edegrees[1] = 0;
17262  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
17263  k = adjncy[j];
17264  if (where[k] == 2)
17265  rinfo[k].edegrees[to] -= vwgt[higain];
17266  else
17267  edegrees[where[k]] += vwgt[k];
17268  }
17269 
17270  /* Push nodes out of the separator */
17271  for (j=mptr[nswaps]; j<mptr[nswaps+1]; j++) {
17272  k = mind[j];
17273  ASSERT(where[k] == 2);
17274  where[k] = other;
17275  INC_DEC(pwgts[other], pwgts[2], vwgt[k]);
17276  BNDDelete(nbnd, bndind, bndptr, k);
17277  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
17278  kk = adjncy[jj];
17279  if (where[kk] == 2)
17280  rinfo[kk].edegrees[other] += vwgt[k];
17281  }
17282  }
17283  }
17284 
17285  ASSERT(mincut == pwgts[2]);
17286 
17287  IFSET(ctrl->dbglvl, DBG_REFINE,
17288  printf("\tMinimum sep: %6d at %5d, PWGTS: [%6d %6d], NBND: %6d\n", mincut, mincutorder, pwgts[0], pwgts[1], nbnd));
17289 
17290  graph->mincut = mincut;
17291  graph->nbnd = nbnd;
17292 
17293  if (pass%2 == 1 && (mincutorder == -1 || mincut >= initcut))
17294  break;
17295  }
17296 
17297  PQueueFree(ctrl, &parts);
17298 
17299  idxwspacefree(ctrl, nvtxs+1);
17300  idxwspacefree(ctrl, nvtxs);
17301  idxwspacefree(ctrl, nvtxs);
17302  idxwspacefree(ctrl, nvtxs);
17303 }
17304 
17305 
17306 
17307 /*************************************************************************
17308 * This function performs a node-based FM refinement
17309 **************************************************************************/
17310 void FM_2WayNodeBalance(CtrlType *ctrl, GraphType *graph, float ubfactor)
17311 {
17312  int i, ii, j, k, jj, kk, nvtxs, nbnd, nswaps;
17313  idxtype *xadj, *vwgt, *adjncy, *where, *pwgts, *edegrees, *bndind, *bndptr;
17314  idxtype *perm, *moved;
17315  PQueueType parts;
17316  NRInfoType *rinfo;
17317  int higain, oldgain;
17318  int to, other;
17319 
17320  nvtxs = graph->nvtxs;
17321  xadj = graph->xadj;
17322  adjncy = graph->adjncy;
17323  vwgt = graph->vwgt;
17324 
17325  bndind = graph->bndind;
17326  bndptr = graph->bndptr;
17327  where = graph->where;
17328  pwgts = graph->pwgts;
17329  rinfo = graph->nrinfo;
17330 
17331  if (abs(pwgts[0]-pwgts[1]) < (int)((ubfactor-1.0)*(pwgts[0]+pwgts[1])))
17332  return;
17333  if (abs(pwgts[0]-pwgts[1]) < 3*idxsum(nvtxs, vwgt)/nvtxs)
17334  return;
17335 
17336  to = (pwgts[0] < pwgts[1] ? 0 : 1);
17337  other = (to+1)%2;
17338 
17339  PQueueInit(ctrl, &parts, nvtxs, ComputeMaxNodeGain(nvtxs, xadj, adjncy, vwgt));
17340 
17341  perm = idxwspacemalloc(ctrl, nvtxs);
17342  moved = idxset(nvtxs, -1, idxwspacemalloc(ctrl, nvtxs));
17343 
17344  IFSET(ctrl->dbglvl, DBG_REFINE,
17345  printf("Partitions: [%6d %6d] Nv-Nb[%6d %6d]. ISep: %6d [B]\n", pwgts[0], pwgts[1], graph->nvtxs, graph->nbnd, graph->mincut));
17346 
17347  nbnd = graph->nbnd;
17348  RandomPermute(nbnd, perm, 1);
17349  for (ii=0; ii<nbnd; ii++) {
17350  i = bndind[perm[ii]];
17351  ASSERT(where[i] == 2);
17352  PQueueInsert(&parts, i, vwgt[i]-rinfo[i].edegrees[other]);
17353  }
17354 
17355  ASSERT(CheckNodeBnd(graph, nbnd));
17357 
17358  /******************************************************
17359  * Get into the FM loop
17360  *******************************************************/
17361  for (nswaps=0; nswaps<nvtxs; nswaps++) {
17362  if ((higain = PQueueGetMax(&parts)) == -1)
17363  break;
17364 
17365  moved[higain] = 1;
17366 
17367  if (pwgts[other] - rinfo[higain].edegrees[other] < (pwgts[0]+pwgts[1])/2)
17368  continue;
17369 #ifdef XXX
17370  if (pwgts[other] - rinfo[higain].edegrees[other] < pwgts[to]+vwgt[higain])
17371  break;
17372 #endif
17373 
17374  ASSERT(bndptr[higain] != -1);
17375 
17376  pwgts[2] -= (vwgt[higain]-rinfo[higain].edegrees[other]);
17377 
17378  BNDDelete(nbnd, bndind, bndptr, higain);
17379  pwgts[to] += vwgt[higain];
17380  where[higain] = to;
17381 
17382  IFSET(ctrl->dbglvl, DBG_MOVEINFO,
17383  printf("Moved %6d to %3d, Gain: %3d, \t[%5d %5d %5d]\n", higain, to, vwgt[higain]-rinfo[higain].edegrees[other], pwgts[0], pwgts[1], pwgts[2]));
17384 
17385 
17386  /**********************************************************
17387  * Update the degrees of the affected nodes
17388  ***********************************************************/
17389  for (j=xadj[higain]; j<xadj[higain+1]; j++) {
17390  k = adjncy[j];
17391  if (where[k] == 2) { /* For the in-separator vertices modify their edegree[to] */
17392  rinfo[k].edegrees[to] += vwgt[higain];
17393  }
17394  else if (where[k] == other) { /* This vertex is pulled into the separator */
17395  ASSERTP(bndptr[k] == -1, ("%d %d %d\n", k, bndptr[k], where[k]));
17396  BNDInsert(nbnd, bndind, bndptr, k);
17397 
17398  where[k] = 2;
17399  pwgts[other] -= vwgt[k];
17400 
17401  edegrees = rinfo[k].edegrees;
17402  edegrees[0] = edegrees[1] = 0;
17403  for (jj=xadj[k]; jj<xadj[k+1]; jj++) {
17404  kk = adjncy[jj];
17405  if (where[kk] != 2)
17406  edegrees[where[kk]] += vwgt[kk];
17407  else {
17408  ASSERT(bndptr[kk] != -1);
17409  oldgain = vwgt[kk]-rinfo[kk].edegrees[other];
17410  rinfo[kk].edegrees[other] -= vwgt[k];
17411 
17412  if (moved[kk] == -1)
17413  PQueueUpdateUp(&parts, kk, oldgain, oldgain+vwgt[k]);
17414  }
17415  }
17416 
17417  /* Insert the new vertex into the priority queue */
17418  PQueueInsert(&parts, k, vwgt[k]-edegrees[other]);
17419  }
17420  }
17421 
17422  if (pwgts[to] > pwgts[other])
17423  break;
17424  }
17425 
17426  IFSET(ctrl->dbglvl, DBG_REFINE,
17427  printf("\tBalanced sep: %6d at %4d, PWGTS: [%6d %6d], NBND: %6d\n", pwgts[2], nswaps, pwgts[0], pwgts[1], nbnd));
17428 
17429  graph->mincut = pwgts[2];
17430  graph->nbnd = nbnd;
17431 
17432 
17433  PQueueFree(ctrl, &parts);
17434 
17435  idxwspacefree(ctrl, nvtxs);
17436  idxwspacefree(ctrl, nvtxs);
17437 }
17438 
17439 
17440 /*************************************************************************
17441 * This function computes the maximum possible gain for a vertex
17442 **************************************************************************/
17443 int ComputeMaxNodeGain(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt)
17444 {
17445  int i, j, k, max;
17446 
17447  max = 0;
17448  for (j=xadj[0]; j<xadj[1]; j++)
17449  max += vwgt[adjncy[j]];
17450 
17451  for (i=1; i<nvtxs; i++) {
17452  for (k=0, j=xadj[i]; j<xadj[i+1]; j++)
17453  k += vwgt[adjncy[j]];
17454  if (max < k)
17455  max = k;
17456  }
17457 
17458  return max;
17459 }
17460 
17461 
17462 /*
17463  * Copyright 1997, Regents of the University of Minnesota
17464  *
17465  * srefine.c
17466  *
17467  * This file contains code for the separator refinement algortihms
17468  *
17469  * Started 8/1/97
17470  * George
17471  *
17472  * $Id$
17473  *
17474  */
17475 
17476 
17477 
17478 
17479 /*************************************************************************
17480 * This function is the entry point of the separator refinement
17481 **************************************************************************/
17482 void Refine2WayNode(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float ubfactor)
17483 {
17484 
17485  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->UncoarsenTmr));
17486 
17487  for (;;) {
17488  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->RefTmr));
17489  if (ctrl->RType != 15)
17490  FM_2WayNodeBalance(ctrl, graph, ubfactor);
17491 
17492  switch (ctrl->RType) {
17493  case 1:
17494  FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
17495  break;
17496  case 2:
17497  FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8);
17498  break;
17499  case 3:
17500  FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
17501  FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8);
17502  break;
17503  case 4:
17504  FM_2WayNodeRefine_OneSided(ctrl, graph, ubfactor, 8);
17505  FM_2WayNodeRefine(ctrl, graph, ubfactor, 8);
17506  break;
17507  case 5:
17508  FM_2WayNodeRefineEqWgt(ctrl, graph, 8);
17509  break;
17510  }
17511  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->RefTmr));
17512 
17513  if (graph == orggraph)
17514  break;
17515 
17516  graph = graph->finer;
17517  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->ProjectTmr));
17518  Project2WayNodePartition(ctrl, graph);
17519  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->ProjectTmr));
17520  }
17521 
17522  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->UncoarsenTmr));
17523 }
17524 
17525 
17526 /*************************************************************************
17527 * This function allocates memory for 2-way edge refinement
17528 **************************************************************************/
17530 {
17531  int nvtxs, pad64;
17532 
17533  nvtxs = graph->nvtxs;
17534 
17535  pad64 = (3*nvtxs+3)%2;
17536 
17537  graph->rdata = idxmalloc(3*nvtxs+3+(sizeof(NRInfoType)/sizeof(idxtype))*nvtxs+pad64, "Allocate2WayPartitionMemory: rdata");
17538  graph->pwgts = graph->rdata;
17539  graph->where = graph->rdata + 3;
17540  graph->bndptr = graph->rdata + nvtxs + 3;
17541  graph->bndind = graph->rdata + 2*nvtxs + 3;
17542  graph->nrinfo = (NRInfoType *)(graph->rdata + 3*nvtxs + 3 + pad64);
17543 }
17544 
17545 
17546 
17547 /*************************************************************************
17548 * This function computes the initial id/ed
17549 **************************************************************************/
17551 {
17552  int i, j, nvtxs, nbnd;
17553  idxtype *xadj, *adjncy, *adjwgt, *vwgt;
17554  idxtype *where, *pwgts, *bndind, *bndptr, *edegrees;
17555  NRInfoType *rinfo;
17556  int me, other;
17557 
17558  nvtxs = graph->nvtxs;
17559  xadj = graph->xadj;
17560  vwgt = graph->vwgt;
17561  adjncy = graph->adjncy;
17562  adjwgt = graph->adjwgt;
17563 
17564  where = graph->where;
17565  rinfo = graph->nrinfo;
17566  pwgts = idxset(3, 0, graph->pwgts);
17567  bndind = graph->bndind;
17568  bndptr = idxset(nvtxs, -1, graph->bndptr);
17569 
17570 
17571  /*------------------------------------------------------------
17572  / Compute now the separator external degrees
17573  /------------------------------------------------------------*/
17574  nbnd = 0;
17575  for (i=0; i<nvtxs; i++) {
17576  me = where[i];
17577  pwgts[me] += vwgt[i];
17578 
17579  ASSERT(me >=0 && me <= 2);
17580 
17581  if (me == 2) { /* If it is on the separator do some computations */
17582  BNDInsert(nbnd, bndind, bndptr, i);
17583 
17584  edegrees = rinfo[i].edegrees;
17585  edegrees[0] = edegrees[1] = 0;
17586 
17587  for (j=xadj[i]; j<xadj[i+1]; j++) {
17588  other = where[adjncy[j]];
17589  if (other != 2)
17590  edegrees[other] += vwgt[adjncy[j]];
17591  }
17592  }
17593  }
17594 
17595  ASSERT(CheckNodeBnd(graph, nbnd));
17596 
17597  graph->mincut = pwgts[2];
17598  graph->nbnd = nbnd;
17599 }
17600 
17601 
17602 /*************************************************************************
17603 * This function computes the initial id/ed
17604 **************************************************************************/
17606 {
17607  int i, nvtxs;
17608  idxtype *cmap, *where, *cwhere;
17609  GraphType *cgraph;
17610 
17611  cgraph = graph->coarser;
17612  cwhere = cgraph->where;
17613 
17614  nvtxs = graph->nvtxs;
17615  cmap = graph->cmap;
17616 
17617  Allocate2WayNodePartitionMemory(ctrl, graph);
17618  where = graph->where;
17619 
17620  /* Project the partition */
17621  for (i=0; i<nvtxs; i++) {
17622  where[i] = cwhere[cmap[i]];
17623  ASSERTP(where[i] >= 0 && where[i] <= 2, ("%d %d %d %d\n", i, cmap[i], where[i], cwhere[cmap[i]]));
17624  }
17625 
17626  FreeGraph(graph->coarser);
17627  graph->coarser = NULL;
17628 
17629  Compute2WayNodePartitionParams(ctrl, graph);
17630 }
17631 /*
17632  * Copyright 1997, Regents of the University of Minnesota
17633  *
17634  * stat.c
17635  *
17636  * This file computes various statistics
17637  *
17638  * Started 7/25/97
17639  * George
17640  *
17641  * $Id$
17642  *
17643  */
17644 
17645 
17646 
17647 
17648 /*************************************************************************
17649 * This function computes cuts and balance information
17650 **************************************************************************/
17651 void ComputePartitionInfo(GraphType *graph, int nparts, idxtype *where)
17652 {
17653  int i, j, nvtxs, ncon, mustfree=0;
17654  idxtype *xadj, *adjncy, *vwgt, *adjwgt, *kpwgts, *tmpptr;
17655  idxtype *padjncy, *padjwgt, *padjcut;
17656 
17657  nvtxs = graph->nvtxs;
17658  ncon = graph->ncon;
17659  xadj = graph->xadj;
17660  adjncy = graph->adjncy;
17661  vwgt = graph->vwgt;
17662  adjwgt = graph->adjwgt;
17663 
17664  if (vwgt == NULL) {
17665  vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt");
17666  mustfree = 1;
17667  }
17668  if (adjwgt == NULL) {
17669  adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt");
17670  mustfree += 2;
17671  }
17672 
17673  printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where));
17674 
17675  /* Compute balance information */
17676  kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts");
17677 
17678  for (i=0; i<nvtxs; i++) {
17679  for (j=0; j<ncon; j++)
17680  kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j];
17681  }
17682 
17683  if (ncon == 1) {
17684  printf("\tBalance: %5.3f out of %5.3f\n",
17685  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)),
17686  1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts)));
17687  }
17688  else {
17689  printf("\tBalance:");
17690  for (j=0; j<ncon; j++)
17691  printf(" (%5.3f out of %5.3f)",
17692  1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)),
17693  1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)));
17694  printf("\n");
17695  }
17696 
17697 
17698  /* Compute p-adjncy information */
17699  padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy");
17700  padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
17701  padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
17702 
17703  idxset(nparts, 0, kpwgts);
17704  for (i=0; i<nvtxs; i++) {
17705  for (j=xadj[i]; j<xadj[i+1]; j++) {
17706  if (where[i] != where[adjncy[j]]) {
17707  padjncy[where[i]*nparts+where[adjncy[j]]] = 1;
17708  padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j];
17709  if (kpwgts[where[adjncy[j]]] == 0) {
17710  padjwgt[where[i]*nparts+where[adjncy[j]]]++;
17711  kpwgts[where[adjncy[j]]] = 1;
17712  }
17713  }
17714  }
17715  for (j=xadj[i]; j<xadj[i+1]; j++)
17716  kpwgts[where[adjncy[j]]] = 0;
17717  }
17718 
17719  for (i=0; i<nparts; i++)
17720  kpwgts[i] = idxsum(nparts, padjncy+i*nparts);
17721  printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5.2f %7.3f\n",
17722  kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)],
17723  1.0*idxsum(nparts, kpwgts)/(1.0*nparts),
17724  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
17725 
17726  for (i=0; i<nparts; i++)
17727  kpwgts[i] = idxsum(nparts, padjcut+i*nparts);
17728  printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n",
17729  kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
17730  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
17731 
17732  for (i=0; i<nparts; i++)
17733  kpwgts[i] = idxsum(nparts, padjwgt+i*nparts);
17734  printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n",
17735  kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
17736  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs));
17737 
17738  tmpptr = graph->where;
17739  graph->where = where;
17740  for (i=0; i<nparts; i++)
17741  IsConnectedSubdomain(NULL, graph, i, 1);
17742  graph->where = tmpptr;
17743 
17744  if (mustfree == 1 || mustfree == 3) {
17745  free(vwgt);
17746  graph->vwgt = NULL;
17747  }
17748  if (mustfree == 2 || mustfree == 3) {
17749  free(adjwgt);
17750  graph->adjwgt = NULL;
17751  }
17752 
17753  GKfree((void **) &kpwgts, (void **) &padjncy,
17754  (void **) &padjwgt, (void **) &padjcut, LTERM);
17755 }
17756 
17757 
17758 /*************************************************************************
17759 * This function computes cuts and balance information
17760 **************************************************************************/
17761 void ComputePartitionInfoBipartite(GraphType *graph, int nparts, idxtype *where)
17762 {
17763  int i, j, nvtxs, ncon, mustfree=0;
17764  idxtype *xadj, *adjncy, *vwgt, *vsize, *adjwgt, *kpwgts;
17765  idxtype *padjncy, *padjwgt, *padjcut;
17766 
17767  nvtxs = graph->nvtxs;
17768  ncon = graph->ncon;
17769  xadj = graph->xadj;
17770  adjncy = graph->adjncy;
17771  vwgt = graph->vwgt;
17772  vsize = graph->vsize;
17773  adjwgt = graph->adjwgt;
17774 
17775  if (vwgt == NULL) {
17776  vwgt = graph->vwgt = idxsmalloc(nvtxs, 1, "vwgt");
17777  mustfree = 1;
17778  }
17779  if (adjwgt == NULL) {
17780  adjwgt = graph->adjwgt = idxsmalloc(xadj[nvtxs], 1, "adjwgt");
17781  mustfree += 2;
17782  }
17783 
17784  printf("%d-way Cut: %5d, Vol: %5d, ", nparts, ComputeCut(graph, where), ComputeVolume(graph, where));
17785 
17786  /* Compute balance information */
17787  kpwgts = idxsmalloc(ncon*nparts, 0, "ComputePartitionInfo: kpwgts");
17788 
17789  for (i=0; i<nvtxs; i++) {
17790  for (j=0; j<ncon; j++)
17791  kpwgts[where[i]*ncon+j] += vwgt[i*ncon+j];
17792  }
17793 
17794  if (ncon == 1) {
17795  printf("\tBalance: %5.3f out of %5.3f\n",
17796  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)),
17797  1.0*nparts*vwgt[idxamax(nvtxs, vwgt)]/(1.0*idxsum(nparts, kpwgts)));
17798  }
17799  else {
17800  printf("\tBalance:");
17801  for (j=0; j<ncon; j++)
17802  printf(" (%5.3f out of %5.3f)",
17803  1.0*nparts*kpwgts[ncon*idxamax_strd(nparts, kpwgts+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)),
17804  1.0*nparts*vwgt[ncon*idxamax_strd(nvtxs, vwgt+j, ncon)+j]/(1.0*idxsum_strd(nparts, kpwgts+j, ncon)));
17805  printf("\n");
17806  }
17807 
17808 
17809  /* Compute p-adjncy information */
17810  padjncy = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjncy");
17811  padjwgt = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
17812  padjcut = idxsmalloc(nparts*nparts, 0, "ComputePartitionInfo: padjwgt");
17813 
17814  idxset(nparts, 0, kpwgts);
17815  for (i=0; i<nvtxs; i++) {
17816  for (j=xadj[i]; j<xadj[i+1]; j++) {
17817  if (where[i] != where[adjncy[j]]) {
17818  padjncy[where[i]*nparts+where[adjncy[j]]] = 1;
17819  padjcut[where[i]*nparts+where[adjncy[j]]] += adjwgt[j];
17820  if (kpwgts[where[adjncy[j]]] == 0) {
17821  padjwgt[where[i]*nparts+where[adjncy[j]]] += vsize[i];
17822  kpwgts[where[adjncy[j]]] = 1;
17823  }
17824  }
17825  }
17826  for (j=xadj[i]; j<xadj[i+1]; j++)
17827  kpwgts[where[adjncy[j]]] = 0;
17828  }
17829 
17830  for (i=0; i<nparts; i++)
17831  kpwgts[i] = idxsum(nparts, padjncy+i*nparts);
17832  printf("Min/Max/Avg/Bal # of adjacent subdomains: %5d %5d %5d %7.3f\n",
17833  kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
17834  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
17835 
17836  for (i=0; i<nparts; i++)
17837  kpwgts[i] = idxsum(nparts, padjcut+i*nparts);
17838  printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5d %5d %5d %7.3f\n",
17839  kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
17840  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)));
17841 
17842  for (i=0; i<nparts; i++)
17843  kpwgts[i] = idxsum(nparts, padjwgt+i*nparts);
17844  printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5d %5d %5d %7.3f %7.3f\n",
17845  kpwgts[idxamin(nparts, kpwgts)], kpwgts[idxamax(nparts, kpwgts)], idxsum(nparts, kpwgts)/nparts,
17846  1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts)), 1.0*idxsum(nparts, kpwgts)/(1.0*nvtxs));
17847 
17848 
17849  if (mustfree == 1 || mustfree == 3) {
17850  free(vwgt);
17851  graph->vwgt = NULL;
17852  }
17853  if (mustfree == 2 || mustfree == 3) {
17854  free(adjwgt);
17855  graph->adjwgt = NULL;
17856  }
17857 
17858  GKfree((void **) &kpwgts, (void **) &padjncy,
17859  (void **) &padjwgt, (void **) &padjcut, LTERM);
17860 }
17861 
17862 
17863 
17864 /*************************************************************************
17865 * This function computes the balance of the partitioning
17866 **************************************************************************/
17867 void ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec)
17868 {
17869  int i, j, nvtxs, ncon;
17870  idxtype *kpwgts, *vwgt;
17871 
17872  nvtxs = graph->nvtxs;
17873  ncon = graph->ncon;
17874  vwgt = graph->vwgt;
17875 
17876  kpwgts = idxsmalloc(nparts, 0, "ComputePartitionInfo: kpwgts");
17877 
17878  if (vwgt == NULL) {
17879  for (i=0; i<nvtxs; i++)
17880  kpwgts[where[i]]++;
17881  ubvec[0] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*nvtxs);
17882  }
17883  else {
17884  for (j=0; j<ncon; j++) {
17885  idxset(nparts, 0, kpwgts);
17886  for (i=0; i<graph->nvtxs; i++)
17887  kpwgts[where[i]] += vwgt[i*ncon+j];
17888 
17889  ubvec[j] = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts));
17890  }
17891  }
17892 
17893  free(kpwgts);
17894 
17895 }
17896 
17897 
17898 /*************************************************************************
17899 * This function computes the balance of the element partitioning
17900 **************************************************************************/
17901 float ComputeElementBalance(int ne, int nparts, idxtype *where)
17902 {
17903  int i;
17904  idxtype *kpwgts;
17905  float balance;
17906 
17907  kpwgts = idxsmalloc(nparts, 0, "ComputeElementBalance: kpwgts");
17908 
17909  for (i=0; i<ne; i++)
17910  kpwgts[where[i]]++;
17911 
17912  balance = 1.0*nparts*kpwgts[idxamax(nparts, kpwgts)]/(1.0*idxsum(nparts, kpwgts));
17913 
17914  free(kpwgts);
17915 
17916  return balance;
17917 
17918 }
17919 /*
17920  * Copyright 1997, Regents of the University of Minnesota
17921  *
17922  * subdomains.c
17923  *
17924  * This file contains functions that deal with prunning the number of
17925  * adjacent subdomains in KMETIS
17926  *
17927  * Started 7/15/98
17928  * George
17929  *
17930  * $Id$
17931  *
17932  */
17933 
17934 
17935 
17936 
17937 /*************************************************************************
17938 * This function performs k-way refinement
17939 **************************************************************************/
17940 void Random_KWayEdgeRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
17941 {
17942  int i, ii, iii, j, k, l, pass, nvtxs, nmoves, nbnd, tvwgt, myndegrees;
17943  int from, me, to, oldcut, vwgt, gain;
17944  int maxndoms, nadd;
17945  idxtype *xadj, *adjncy, *adjwgt;
17946  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts;
17947  idxtype *phtable, *pmat, *pmatptr, *ndoms;
17948  EDegreeType *myedegrees;
17949  RInfoType *myrinfo;
17950 
17951  nvtxs = graph->nvtxs;
17952  xadj = graph->xadj;
17953  adjncy = graph->adjncy;
17954  adjwgt = graph->adjwgt;
17955 
17956  bndptr = graph->bndptr;
17957  bndind = graph->bndind;
17958 
17959  where = graph->where;
17960  pwgts = graph->pwgts;
17961 
17962  pmat = ctrl->wspace.pmat;
17963  phtable = idxwspacemalloc(ctrl, nparts);
17964  ndoms = idxwspacemalloc(ctrl, nparts);
17965 
17966  ComputeSubDomainGraph(graph, nparts, pmat, ndoms);
17967 
17968  /* Setup the weight intervals of the various subdomains */
17969  minwgt = idxwspacemalloc(ctrl, nparts);
17970  maxwgt = idxwspacemalloc(ctrl, nparts);
17971  itpwgts = idxwspacemalloc(ctrl, nparts);
17972  tvwgt = idxsum(nparts, pwgts);
17973  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
17974 
17975  for (i=0; i<nparts; i++) {
17976  itpwgts[i] = tpwgts[i]*tvwgt;
17977  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
17978  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
17979  }
17980 
17981  perm = idxwspacemalloc(ctrl, nvtxs);
17982 
17983  IFSET(ctrl->dbglvl, DBG_REFINE,
17984  printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d\n",
17985  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
17986  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
17987  graph->mincut));
17988 
17989  for (pass=0; pass<npasses; pass++) {
17990  ASSERT(ComputeCut(graph, where) == graph->mincut);
17991 
17992  maxndoms = ndoms[idxamax(nparts, ndoms)];
17993 
17994  oldcut = graph->mincut;
17995  nbnd = graph->nbnd;
17996 
17997  RandomPermute(nbnd, perm, 1);
17998  for (nmoves=iii=0; iii<graph->nbnd; iii++) {
17999  ii = perm[iii];
18000  if (ii >= nbnd)
18001  continue;
18002  i = bndind[ii];
18003 
18004  myrinfo = graph->rinfo+i;
18005 
18006  if (myrinfo->ed >= myrinfo->id) { /* Total ED is too high */
18007  from = where[i];
18008  vwgt = graph->vwgt[i];
18009 
18010  if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from])
18011  continue; /* This cannot be moved! */
18012 
18013  myedegrees = myrinfo->edegrees;
18014  myndegrees = myrinfo->ndegrees;
18015 
18016  /* Determine the valid domains */
18017  for (j=0; j<myndegrees; j++) {
18018  to = myedegrees[j].pid;
18019  phtable[to] = 1;
18020  pmatptr = pmat + to*nparts;
18021  for (nadd=0, k=0; k<myndegrees; k++) {
18022  if (k == j)
18023  continue;
18024 
18025  l = myedegrees[k].pid;
18026  if (pmatptr[l] == 0) {
18027  if (ndoms[l] > maxndoms-1) {
18028  phtable[to] = 0;
18029  nadd = maxndoms;
18030  break;
18031  }
18032  nadd++;
18033  }
18034  }
18035  if (ndoms[to]+nadd > maxndoms)
18036  phtable[to] = 0;
18037  if (nadd == 0)
18038  phtable[to] = 2;
18039  }
18040 
18041  /* Find the first valid move */
18042  j = myrinfo->id;
18043  for (k=0; k<myndegrees; k++) {
18044  to = myedegrees[k].pid;
18045  if (!phtable[to])
18046  continue;
18047  gain = myedegrees[k].ed-j; /* j = myrinfo->id. Allow good nodes to move */
18048  if (pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain && gain >= 0)
18049  break;
18050  }
18051  if (k == myndegrees)
18052  continue; /* break out if you did not find a candidate */
18053 
18054  for (j=k+1; j<myndegrees; j++) {
18055  to = myedegrees[j].pid;
18056  if (!phtable[to])
18057  continue;
18058  if ((myedegrees[j].ed > myedegrees[k].ed && pwgts[to]+vwgt <= maxwgt[to]) ||
18059  (myedegrees[j].ed == myedegrees[k].ed &&
18060  itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid]))
18061  k = j;
18062  }
18063 
18064  to = myedegrees[k].pid;
18065 
18066  j = 0;
18067  if (myedegrees[k].ed-myrinfo->id > 0)
18068  j = 1;
18069  else if (myedegrees[k].ed-myrinfo->id == 0) {
18070  if (/*(iii&7) == 0 ||*/ phtable[myedegrees[k].pid] == 2 || pwgts[from] >= maxwgt[from] || itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from])
18071  j = 1;
18072  }
18073  if (j == 0)
18074  continue;
18075 
18076  /*=====================================================================
18077  * If we got here, we can now move the vertex from 'from' to 'to'
18078  *======================================================================*/
18079  graph->mincut -= myedegrees[k].ed-myrinfo->id;
18080 
18081  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
18082 
18083  /* Update pmat to reflect the move of 'i' */
18084  pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
18085  pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
18086  if (pmat[from*nparts+to] == 0) {
18087  ndoms[from]--;
18088  if (ndoms[from]+1 == maxndoms)
18089  maxndoms = ndoms[idxamax(nparts, ndoms)];
18090  }
18091  if (pmat[to*nparts+from] == 0) {
18092  ndoms[to]--;
18093  if (ndoms[to]+1 == maxndoms)
18094  maxndoms = ndoms[idxamax(nparts, ndoms)];
18095  }
18096 
18097  /* Update where, weight, and ID/ED information of the vertex you moved */
18098  where[i] = to;
18099  INC_DEC(pwgts[to], pwgts[from], vwgt);
18100  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
18101  SWAP(myrinfo->id, myedegrees[k].ed, j);
18102  if (myedegrees[k].ed == 0)
18103  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
18104  else
18105  myedegrees[k].pid = from;
18106 
18107  if (myrinfo->ed-myrinfo->id < 0)
18108  BNDDelete(nbnd, bndind, bndptr, i);
18109 
18110  /* Update the degrees of adjacent vertices */
18111  for (j=xadj[i]; j<xadj[i+1]; j++) {
18112  ii = adjncy[j];
18113  me = where[ii];
18114 
18115  myrinfo = graph->rinfo+ii;
18116  if (myrinfo->edegrees == NULL) {
18117  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
18118  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
18119  }
18120  myedegrees = myrinfo->edegrees;
18121 
18122  ASSERT(CheckRInfo(myrinfo));
18123 
18124  if (me == from) {
18125  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
18126 
18127  if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
18128  BNDInsert(nbnd, bndind, bndptr, ii);
18129  }
18130  else if (me == to) {
18131  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
18132 
18133  if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
18134  BNDDelete(nbnd, bndind, bndptr, ii);
18135  }
18136 
18137  /* Remove contribution from the .ed of 'from' */
18138  if (me != from) {
18139  for (k=0; k<myrinfo->ndegrees; k++) {
18140  if (myedegrees[k].pid == from) {
18141  if (myedegrees[k].ed == adjwgt[j])
18142  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
18143  else
18144  myedegrees[k].ed -= adjwgt[j];
18145  break;
18146  }
18147  }
18148  }
18149 
18150  /* Add contribution to the .ed of 'to' */
18151  if (me != to) {
18152  for (k=0; k<myrinfo->ndegrees; k++) {
18153  if (myedegrees[k].pid == to) {
18154  myedegrees[k].ed += adjwgt[j];
18155  break;
18156  }
18157  }
18158  if (k == myrinfo->ndegrees) {
18159  myedegrees[myrinfo->ndegrees].pid = to;
18160  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
18161  }
18162  }
18163 
18164  /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
18165  if (me != from && me != to) {
18166  pmat[me*nparts+from] -= adjwgt[j];
18167  pmat[from*nparts+me] -= adjwgt[j];
18168  if (pmat[me*nparts+from] == 0) {
18169  ndoms[me]--;
18170  if (ndoms[me]+1 == maxndoms)
18171  maxndoms = ndoms[idxamax(nparts, ndoms)];
18172  }
18173  if (pmat[from*nparts+me] == 0) {
18174  ndoms[from]--;
18175  if (ndoms[from]+1 == maxndoms)
18176  maxndoms = ndoms[idxamax(nparts, ndoms)];
18177  }
18178 
18179  if (pmat[me*nparts+to] == 0) {
18180  ndoms[me]++;
18181  if (ndoms[me] > maxndoms) {
18182  printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms);
18183  maxndoms = ndoms[me];
18184  }
18185  }
18186  if (pmat[to*nparts+me] == 0) {
18187  ndoms[to]++;
18188  if (ndoms[to] > maxndoms) {
18189  printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms);
18190  maxndoms = ndoms[to];
18191  }
18192  }
18193  pmat[me*nparts+to] += adjwgt[j];
18194  pmat[to*nparts+me] += adjwgt[j];
18195  }
18196 
18197  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
18198  ASSERT(CheckRInfo(myrinfo));
18199 
18200  }
18201  nmoves++;
18202  }
18203  }
18204 
18205  graph->nbnd = nbnd;
18206 
18207  IFSET(ctrl->dbglvl, DBG_REFINE,
18208  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %5d, Vol: %5d, %d\n",
18209  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
18210  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves,
18211  graph->mincut, ComputeVolume(graph, where), idxsum(nparts, ndoms)));
18212 
18213  if (graph->mincut == oldcut)
18214  break;
18215  }
18216 
18217  idxwspacefree(ctrl, nparts);
18218  idxwspacefree(ctrl, nparts);
18219  idxwspacefree(ctrl, nparts);
18220  idxwspacefree(ctrl, nparts);
18221  idxwspacefree(ctrl, nparts);
18222  idxwspacefree(ctrl, nvtxs);
18223 }
18224 
18225 
18226 
18227 /*************************************************************************
18228 * This function performs k-way refinement
18229 **************************************************************************/
18230 void Greedy_KWayEdgeBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
18231 {
18232  int i, ii, j, k, l, pass, nvtxs, nbnd, tvwgt, myndegrees, oldgain, gain, nmoves;
18233  int from, me, to, oldcut, vwgt, maxndoms, nadd;
18234  idxtype *xadj, *adjncy, *adjwgt;
18235  idxtype *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *moved, *itpwgts;
18236  idxtype *phtable, *pmat, *pmatptr, *ndoms;
18237  EDegreeType *myedegrees;
18238  RInfoType *myrinfo;
18239  PQueueType queue;
18240 
18241  nvtxs = graph->nvtxs;
18242  xadj = graph->xadj;
18243  adjncy = graph->adjncy;
18244  adjwgt = graph->adjwgt;
18245 
18246  bndind = graph->bndind;
18247  bndptr = graph->bndptr;
18248 
18249  where = graph->where;
18250  pwgts = graph->pwgts;
18251 
18252  pmat = ctrl->wspace.pmat;
18253  phtable = idxwspacemalloc(ctrl, nparts);
18254  ndoms = idxwspacemalloc(ctrl, nparts);
18255 
18256  ComputeSubDomainGraph(graph, nparts, pmat, ndoms);
18257 
18258 
18259  /* Setup the weight intervals of the various subdomains */
18260  minwgt = idxwspacemalloc(ctrl, nparts);
18261  maxwgt = idxwspacemalloc(ctrl, nparts);
18262  itpwgts = idxwspacemalloc(ctrl, nparts);
18263  tvwgt = idxsum(nparts, pwgts);
18264  ASSERT(tvwgt == idxsum(nvtxs, graph->vwgt));
18265 
18266  for (i=0; i<nparts; i++) {
18267  itpwgts[i] = tpwgts[i]*tvwgt;
18268  maxwgt[i] = tpwgts[i]*tvwgt*ubfactor;
18269  minwgt[i] = tpwgts[i]*tvwgt*(1.0/ubfactor);
18270  }
18271 
18272  perm = idxwspacemalloc(ctrl, nvtxs);
18273  moved = idxwspacemalloc(ctrl, nvtxs);
18274 
18275  PQueueInit(ctrl, &queue, nvtxs, graph->adjwgtsum[idxamax(nvtxs, graph->adjwgtsum)]);
18276 
18277  IFSET(ctrl->dbglvl, DBG_REFINE,
18278  printf("Partitions: [%6d %6d]-[%6d %6d], Balance: %5.3f, Nv-Nb[%6d %6d]. Cut: %6d [B]\n",
18279  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)], minwgt[0], maxwgt[0],
18280  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nvtxs, graph->nbnd,
18281  graph->mincut));
18282 
18283  for (pass=0; pass<npasses; pass++) {
18284  ASSERT(ComputeCut(graph, where) == graph->mincut);
18285 
18286  /* Check to see if things are out of balance, given the tolerance */
18287  for (i=0; i<nparts; i++) {
18288  if (pwgts[i] > maxwgt[i])
18289  break;
18290  }
18291  if (i == nparts) /* Things are balanced. Return right away */
18292  break;
18293 
18294  PQueueReset(&queue);
18295  idxset(nvtxs, -1, moved);
18296 
18297  oldcut = graph->mincut;
18298  nbnd = graph->nbnd;
18299 
18300  RandomPermute(nbnd, perm, 1);
18301  for (ii=0; ii<nbnd; ii++) {
18302  i = bndind[perm[ii]];
18303  PQueueInsert(&queue, i, graph->rinfo[i].ed - graph->rinfo[i].id);
18304  moved[i] = 2;
18305  }
18306 
18307  maxndoms = ndoms[idxamax(nparts, ndoms)];
18308 
18309  for (nmoves=0;;) {
18310  if ((i = PQueueGetMax(&queue)) == -1)
18311  break;
18312  moved[i] = 1;
18313 
18314  myrinfo = graph->rinfo+i;
18315  from = where[i];
18316  vwgt = graph->vwgt[i];
18317 
18318  if (pwgts[from]-vwgt < minwgt[from])
18319  continue; /* This cannot be moved! */
18320 
18321  myedegrees = myrinfo->edegrees;
18322  myndegrees = myrinfo->ndegrees;
18323 
18324  /* Determine the valid domains */
18325  for (j=0; j<myndegrees; j++) {
18326  to = myedegrees[j].pid;
18327  phtable[to] = 1;
18328  pmatptr = pmat + to*nparts;
18329  for (nadd=0, k=0; k<myndegrees; k++) {
18330  if (k == j)
18331  continue;
18332 
18333  l = myedegrees[k].pid;
18334  if (pmatptr[l] == 0) {
18335  if (ndoms[l] > maxndoms-1) {
18336  phtable[to] = 0;
18337  nadd = maxndoms;
18338  break;
18339  }
18340  nadd++;
18341  }
18342  }
18343  if (ndoms[to]+nadd > maxndoms)
18344  phtable[to] = 0;
18345  }
18346 
18347  for (k=0; k<myndegrees; k++) {
18348  to = myedegrees[k].pid;
18349  if (!phtable[to])
18350  continue;
18351  if (pwgts[to]+vwgt <= maxwgt[to] || itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from])
18352  break;
18353  }
18354  if (k == myndegrees)
18355  continue; /* break out if you did not find a candidate */
18356 
18357  for (j=k+1; j<myndegrees; j++) {
18358  to = myedegrees[j].pid;
18359  if (!phtable[to])
18360  continue;
18361  if (itpwgts[myedegrees[k].pid]*pwgts[to] < itpwgts[to]*pwgts[myedegrees[k].pid])
18362  k = j;
18363  }
18364 
18365  to = myedegrees[k].pid;
18366 
18367  if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && myedegrees[k].ed-myrinfo->id < 0)
18368  continue;
18369 
18370  /*=====================================================================
18371  * If we got here, we can now move the vertex from 'from' to 'to'
18372  *======================================================================*/
18373  graph->mincut -= myedegrees[k].ed-myrinfo->id;
18374 
18375  IFSET(ctrl->dbglvl, DBG_MOVEINFO, printf("\t\tMoving %6d to %3d. Gain: %4d. Cut: %6d\n", i, to, myedegrees[k].ed-myrinfo->id, graph->mincut));
18376 
18377  /* Update pmat to reflect the move of 'i' */
18378  pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
18379  pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
18380  if (pmat[from*nparts+to] == 0) {
18381  ndoms[from]--;
18382  if (ndoms[from]+1 == maxndoms)
18383  maxndoms = ndoms[idxamax(nparts, ndoms)];
18384  }
18385  if (pmat[to*nparts+from] == 0) {
18386  ndoms[to]--;
18387  if (ndoms[to]+1 == maxndoms)
18388  maxndoms = ndoms[idxamax(nparts, ndoms)];
18389  }
18390 
18391 
18392  /* Update where, weight, and ID/ED information of the vertex you moved */
18393  where[i] = to;
18394  INC_DEC(pwgts[to], pwgts[from], vwgt);
18395  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
18396  SWAP(myrinfo->id, myedegrees[k].ed, j);
18397  if (myedegrees[k].ed == 0)
18398  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
18399  else
18400  myedegrees[k].pid = from;
18401 
18402  if (myrinfo->ed == 0)
18403  BNDDelete(nbnd, bndind, bndptr, i);
18404 
18405  /* Update the degrees of adjacent vertices */
18406  for (j=xadj[i]; j<xadj[i+1]; j++) {
18407  ii = adjncy[j];
18408  me = where[ii];
18409 
18410  myrinfo = graph->rinfo+ii;
18411  if (myrinfo->edegrees == NULL) {
18412  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
18413  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
18414  }
18415  myedegrees = myrinfo->edegrees;
18416 
18417  ASSERT(CheckRInfo(myrinfo));
18418 
18419  oldgain = (myrinfo->ed-myrinfo->id);
18420 
18421  if (me == from) {
18422  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
18423 
18424  if (myrinfo->ed > 0 && bndptr[ii] == -1)
18425  BNDInsert(nbnd, bndind, bndptr, ii);
18426  }
18427  else if (me == to) {
18428  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
18429 
18430  if (myrinfo->ed == 0 && bndptr[ii] != -1)
18431  BNDDelete(nbnd, bndind, bndptr, ii);
18432  }
18433 
18434  /* Remove contribution from the .ed of 'from' */
18435  if (me != from) {
18436  for (k=0; k<myrinfo->ndegrees; k++) {
18437  if (myedegrees[k].pid == from) {
18438  if (myedegrees[k].ed == adjwgt[j])
18439  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
18440  else
18441  myedegrees[k].ed -= adjwgt[j];
18442  break;
18443  }
18444  }
18445  }
18446 
18447  /* Add contribution to the .ed of 'to' */
18448  if (me != to) {
18449  for (k=0; k<myrinfo->ndegrees; k++) {
18450  if (myedegrees[k].pid == to) {
18451  myedegrees[k].ed += adjwgt[j];
18452  break;
18453  }
18454  }
18455  if (k == myrinfo->ndegrees) {
18456  myedegrees[myrinfo->ndegrees].pid = to;
18457  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
18458  }
18459  }
18460 
18461  /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
18462  if (me != from && me != to) {
18463  pmat[me*nparts+from] -= adjwgt[j];
18464  pmat[from*nparts+me] -= adjwgt[j];
18465  if (pmat[me*nparts+from] == 0) {
18466  ndoms[me]--;
18467  if (ndoms[me]+1 == maxndoms)
18468  maxndoms = ndoms[idxamax(nparts, ndoms)];
18469  }
18470  if (pmat[from*nparts+me] == 0) {
18471  ndoms[from]--;
18472  if (ndoms[from]+1 == maxndoms)
18473  maxndoms = ndoms[idxamax(nparts, ndoms)];
18474  }
18475 
18476  if (pmat[me*nparts+to] == 0) {
18477  ndoms[me]++;
18478  if (ndoms[me] > maxndoms) {
18479  printf("You just increased the maxndoms: %d %d\n", ndoms[me], maxndoms);
18480  maxndoms = ndoms[me];
18481  }
18482  }
18483  if (pmat[to*nparts+me] == 0) {
18484  ndoms[to]++;
18485  if (ndoms[to] > maxndoms) {
18486  printf("You just increased the maxndoms: %d %d\n", ndoms[to], maxndoms);
18487  maxndoms = ndoms[to];
18488  }
18489  }
18490  pmat[me*nparts+to] += adjwgt[j];
18491  pmat[to*nparts+me] += adjwgt[j];
18492  }
18493 
18494  /* Update the queue */
18495  if (me == to || me == from) {
18496  gain = myrinfo->ed-myrinfo->id;
18497  if (moved[ii] == 2) {
18498  if (myrinfo->ed > 0)
18499  PQueueUpdate(&queue, ii, oldgain, gain);
18500  else {
18501  PQueueDelete(&queue, ii, oldgain);
18502  moved[ii] = -1;
18503  }
18504  }
18505  else if (moved[ii] == -1 && myrinfo->ed > 0) {
18506  PQueueInsert(&queue, ii, gain);
18507  moved[ii] = 2;
18508  }
18509  }
18510 
18511  ASSERT(myrinfo->ndegrees <= xadj[ii+1]-xadj[ii]);
18512  ASSERT(CheckRInfo(myrinfo));
18513  }
18514  nmoves++;
18515  }
18516 
18517  graph->nbnd = nbnd;
18518 
18519  IFSET(ctrl->dbglvl, DBG_REFINE,
18520  printf("\t[%6d %6d], Balance: %5.3f, Nb: %6d. Nmoves: %5d, Cut: %6d, %d\n",
18521  pwgts[idxamin(nparts, pwgts)], pwgts[idxamax(nparts, pwgts)],
18522  1.0*nparts*pwgts[idxamax(nparts, pwgts)]/tvwgt, graph->nbnd, nmoves, graph->mincut,idxsum(nparts, ndoms)));
18523  }
18524 
18525  PQueueFree(ctrl, &queue);
18526 
18527  idxwspacefree(ctrl, nparts);
18528  idxwspacefree(ctrl, nparts);
18529  idxwspacefree(ctrl, nparts);
18530  idxwspacefree(ctrl, nparts);
18531  idxwspacefree(ctrl, nparts);
18532  idxwspacefree(ctrl, nvtxs);
18533  idxwspacefree(ctrl, nvtxs);
18534 
18535 }
18536 
18537 
18538 
18539 
18540 /*************************************************************************
18541 * This function computes the subdomain graph
18542 **************************************************************************/
18543 void PrintSubDomainGraph(GraphType *graph, int nparts, idxtype *where)
18544 {
18545  int i, j, k, me, nvtxs, total, max;
18546  idxtype *xadj, *adjncy, *adjwgt, *pmat;
18547 
18548  nvtxs = graph->nvtxs;
18549  xadj = graph->xadj;
18550  adjncy = graph->adjncy;
18551  adjwgt = graph->adjwgt;
18552 
18553  pmat = idxsmalloc(nparts*nparts, 0, "ComputeSubDomainGraph: pmat");
18554 
18555  for (i=0; i<nvtxs; i++) {
18556  me = where[i];
18557  for (j=xadj[i]; j<xadj[i+1]; j++) {
18558  k = adjncy[j];
18559  if (where[k] != me)
18560  pmat[me*nparts+where[k]] += adjwgt[j];
18561  }
18562  }
18563 
18564  /* printf("Subdomain Info\n"); */
18565  total = max = 0;
18566  for (i=0; i<nparts; i++) {
18567  for (k=0, j=0; j<nparts; j++) {
18568  if (pmat[i*nparts+j] > 0)
18569  k++;
18570  }
18571  total += k;
18572 
18573  if (k > max)
18574  max = k;
18575 /*
18576  printf("%2d -> %2d ", i, k);
18577  for (j=0; j<nparts; j++) {
18578  if (pmat[i*nparts+j] > 0)
18579  printf("[%2d %4d] ", j, pmat[i*nparts+j]);
18580  }
18581  printf("\n");
18582 */
18583  }
18584  printf("Total adjacent subdomains: %d, Max: %d\n", total, max);
18585 
18586  free(pmat);
18587 }
18588 
18589 
18590 
18591 /*************************************************************************
18592 * This function computes the subdomain graph
18593 **************************************************************************/
18594 void ComputeSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms)
18595 {
18596  int i, j, k, me, nvtxs, ndegrees;
18597  idxtype *xadj, *adjncy, *adjwgt, *where;
18598  RInfoType *rinfo;
18599  EDegreeType *edegrees;
18600 
18601  nvtxs = graph->nvtxs;
18602  xadj = graph->xadj;
18603  adjncy = graph->adjncy;
18604  adjwgt = graph->adjwgt;
18605  where = graph->where;
18606  rinfo = graph->rinfo;
18607 
18608  idxset(nparts*nparts, 0, pmat);
18609 
18610  for (i=0; i<nvtxs; i++) {
18611  if (rinfo[i].ed > 0) {
18612  me = where[i];
18613  ndegrees = rinfo[i].ndegrees;
18614  edegrees = rinfo[i].edegrees;
18615 
18616  k = me*nparts;
18617  for (j=0; j<ndegrees; j++)
18618  pmat[k+edegrees[j].pid] += edegrees[j].ed;
18619  }
18620  }
18621 
18622  for (i=0; i<nparts; i++) {
18623  ndoms[i] = 0;
18624  for (j=0; j<nparts; j++) {
18625  if (pmat[i*nparts+j] > 0)
18626  ndoms[i]++;
18627  }
18628  }
18629 
18630 }
18631 
18632 
18633 
18634 
18635 
18636 /*************************************************************************
18637 * This function computes the subdomain graph
18638 **************************************************************************/
18639 void EliminateSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts)
18640 {
18641  int i, ii, j, k, me, other, nvtxs, total, max, avg, totalout, nind, ncand, ncand2, target, target2, nadd;
18642  int min, move, cpwgt, tvwgt;
18643  idxtype *xadj, *adjncy, *vwgt, *adjwgt, *pwgts, *where, *maxpwgt, *pmat, *ndoms, *mypmat, *otherpmat, *ind;
18644  KeyValueType *cand, *cand2;
18645 
18646  nvtxs = graph->nvtxs;
18647  xadj = graph->xadj;
18648  adjncy = graph->adjncy;
18649  vwgt = graph->vwgt;
18650  adjwgt = graph->adjwgt;
18651 
18652  where = graph->where;
18653  pwgts = graph->pwgts; /* We assume that this is properly initialized */
18654 
18655  maxpwgt = idxwspacemalloc(ctrl, nparts);
18656  ndoms = idxwspacemalloc(ctrl, nparts);
18657  otherpmat = idxwspacemalloc(ctrl, nparts);
18658  ind = idxwspacemalloc(ctrl, nvtxs);
18659  pmat = ctrl->wspace.pmat;
18660 
18661  cand = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
18662  cand2 = (KeyValueType *)GKmalloc(nparts*sizeof(KeyValueType), "EliminateSubDomainEdges: cand");
18663 
18664  /* Compute the pmat matrix and ndoms */
18665  ComputeSubDomainGraph(graph, nparts, pmat, ndoms);
18666 
18667 
18668  /* Compute the maximum allowed weight for each domain */
18669  tvwgt = idxsum(nparts, pwgts);
18670  for (i=0; i<nparts; i++)
18671  maxpwgt[i] = 1.25*tpwgts[i]*tvwgt;
18672 
18673 
18674  /* Get into the loop eliminating subdomain connections */
18675  for (;;) {
18676  total = idxsum(nparts, ndoms);
18677  avg = total/nparts;
18678  max = ndoms[idxamax(nparts, ndoms)];
18679 
18680  /* printf("Adjacent Subdomain Stats: Total: %3d, Max: %3d, Avg: %3d [%5d]\n", total, max, avg, idxsum(nparts*nparts, pmat)); */
18681 
18682  if (max < 1.4*avg)
18683  break;
18684 
18685  me = idxamax(nparts, ndoms);
18686  mypmat = pmat + me*nparts;
18687  totalout = idxsum(nparts, mypmat);
18688 
18689  /*printf("Me: %d, TotalOut: %d,\n", me, totalout);*/
18690 
18691  /* Sort the connections according to their cut */
18692  for (ncand2=0, i=0; i<nparts; i++) {
18693  if (mypmat[i] > 0) {
18694  cand2[ncand2].key = mypmat[i];
18695  cand2[ncand2++].val = i;
18696  }
18697  }
18698  ikeysort(ncand2, cand2);
18699 
18700  move = 0;
18701  for (min=0; min<ncand2; min++) {
18702  if (cand2[min].key > totalout/(2*ndoms[me]))
18703  break;
18704 
18705  other = cand2[min].val;
18706 
18707  /*printf("\tMinOut: %d to %d\n", mypmat[other], other);*/
18708 
18709  idxset(nparts, 0, otherpmat);
18710 
18711  /* Go and find the vertices in 'other' that are connected in 'me' */
18712  for (nind=0, i=0; i<nvtxs; i++) {
18713  if (where[i] == other) {
18714  for (j=xadj[i]; j<xadj[i+1]; j++) {
18715  if (where[adjncy[j]] == me) {
18716  ind[nind++] = i;
18717  break;
18718  }
18719  }
18720  }
18721  }
18722 
18723  /* Go and construct the otherpmat to see where these nind vertices are connected to */
18724  for (cpwgt=0, ii=0; ii<nind; ii++) {
18725  i = ind[ii];
18726  cpwgt += vwgt[i];
18727 
18728  for (j=xadj[i]; j<xadj[i+1]; j++)
18729  otherpmat[where[adjncy[j]]] += adjwgt[j];
18730  }
18731  otherpmat[other] = 0;
18732 
18733  for (ncand=0, i=0; i<nparts; i++) {
18734  if (otherpmat[i] > 0) {
18735  cand[ncand].key = -otherpmat[i];
18736  cand[ncand++].val = i;
18737  }
18738  }
18739  ikeysort(ncand, cand);
18740 
18741  /*
18742  * Go through and the select the first domain that is common with 'me', and
18743  * does not increase the ndoms[target] higher than my ndoms, subject to the
18744  * maxpwgt constraint. Traversal is done from the mostly connected to the least.
18745  */
18746  target = target2 = -1;
18747  for (i=0; i<ncand; i++) {
18748  k = cand[i].val;
18749 
18750  if (mypmat[k] > 0) {
18751  if (pwgts[k] + cpwgt > maxpwgt[k]) /* Check if balance will go off */
18752  continue;
18753 
18754  for (j=0; j<nparts; j++) {
18755  if (otherpmat[j] > 0 && ndoms[j] >= ndoms[me]-1 && pmat[nparts*j+k] == 0)
18756  break;
18757  }
18758  if (j == nparts) { /* No bad second level effects */
18759  for (nadd=0, j=0; j<nparts; j++) {
18760  if (otherpmat[j] > 0 && pmat[nparts*k+j] == 0)
18761  nadd++;
18762  }
18763 
18764  /*printf("\t\tto=%d, nadd=%d, %d\n", k, nadd, ndoms[k]);*/
18765  if (target2 == -1 && ndoms[k]+nadd < ndoms[me]) {
18766  target2 = k;
18767  }
18768  if (nadd == 0) {
18769  target = k;
18770  break;
18771  }
18772  }
18773  }
18774  }
18775  if (target == -1 && target2 != -1)
18776  target = target2;
18777 
18778  if (target == -1) {
18779  /* printf("\t\tCould not make the move\n");*/
18780  continue;
18781  }
18782 
18783  /*printf("\t\tMoving to %d\n", target);*/
18784 
18785  /* Update the partition weights */
18786  INC_DEC(pwgts[target], pwgts[other], cpwgt);
18787 
18788  MoveGroupMConn(ctrl, graph, ndoms, pmat, nparts, target, nind, ind);
18789 
18790  move = 1;
18791  break;
18792  }
18793 
18794  if (move == 0)
18795  break;
18796  }
18797 
18798  idxwspacefree(ctrl, nparts);
18799  idxwspacefree(ctrl, nparts);
18800  idxwspacefree(ctrl, nparts);
18801  idxwspacefree(ctrl, nvtxs);
18802 
18803  GKfree((void **) &cand, (void **) &cand2, LTERM);
18804 }
18805 
18806 
18807 /*************************************************************************
18808 * This function moves a collection of vertices and updates their rinfo
18809 **************************************************************************/
18810 void MoveGroupMConn(CtrlType *ctrl, GraphType *graph, idxtype *ndoms, idxtype *pmat,
18811  int nparts, int to, int nind, idxtype *ind)
18812 {
18813  int i, ii, iii, j, k, nvtxs, nbnd;
18814  int from, me;
18815  idxtype *xadj, *adjncy, *adjwgt;
18816  idxtype *where, *bndptr, *bndind;
18817  EDegreeType *myedegrees;
18818  RInfoType *myrinfo;
18819 
18820  nvtxs = graph->nvtxs;
18821  xadj = graph->xadj;
18822  adjncy = graph->adjncy;
18823  adjwgt = graph->adjwgt;
18824 
18825  where = graph->where;
18826  bndptr = graph->bndptr;
18827  bndind = graph->bndind;
18828 
18829  nbnd = graph->nbnd;
18830 
18831  for (iii=0; iii<nind; iii++) {
18832  i = ind[iii];
18833  from = where[i];
18834 
18835  myrinfo = graph->rinfo+i;
18836  if (myrinfo->edegrees == NULL) {
18837  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
18838  ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
18839  myrinfo->ndegrees = 0;
18840  }
18841  myedegrees = myrinfo->edegrees;
18842 
18843  /* find the location of 'to' in myrinfo or create it if it is not there */
18844  for (k=0; k<myrinfo->ndegrees; k++) {
18845  if (myedegrees[k].pid == to)
18846  break;
18847  }
18848  if (k == myrinfo->ndegrees) {
18849  myedegrees[k].pid = to;
18850  myedegrees[k].ed = 0;
18851  myrinfo->ndegrees++;
18852  }
18853 
18854  graph->mincut -= myedegrees[k].ed-myrinfo->id;
18855 
18856  /* Update pmat to reflect the move of 'i' */
18857  pmat[from*nparts+to] += (myrinfo->id-myedegrees[k].ed);
18858  pmat[to*nparts+from] += (myrinfo->id-myedegrees[k].ed);
18859  if (pmat[from*nparts+to] == 0)
18860  ndoms[from]--;
18861  if (pmat[to*nparts+from] == 0)
18862  ndoms[to]--;
18863 
18864  /* Update where, weight, and ID/ED information of the vertex you moved */
18865  where[i] = to;
18866  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
18867  SWAP(myrinfo->id, myedegrees[k].ed, j);
18868  if (myedegrees[k].ed == 0)
18869  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
18870  else
18871  myedegrees[k].pid = from;
18872 
18873  if (myrinfo->ed-myrinfo->id < 0 && bndptr[i] != -1)
18874  BNDDelete(nbnd, bndind, bndptr, i);
18875 
18876  /* Update the degrees of adjacent vertices */
18877  for (j=xadj[i]; j<xadj[i+1]; j++) {
18878  ii = adjncy[j];
18879  me = where[ii];
18880 
18881  myrinfo = graph->rinfo+ii;
18882  if (myrinfo->edegrees == NULL) {
18883  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
18884  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
18885  }
18886  myedegrees = myrinfo->edegrees;
18887 
18888  ASSERT(CheckRInfo(myrinfo));
18889 
18890  if (me == from) {
18891  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
18892 
18893  if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
18894  BNDInsert(nbnd, bndind, bndptr, ii);
18895  }
18896  else if (me == to) {
18897  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
18898 
18899  if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
18900  BNDDelete(nbnd, bndind, bndptr, ii);
18901  }
18902 
18903  /* Remove contribution from the .ed of 'from' */
18904  if (me != from) {
18905  for (k=0; k<myrinfo->ndegrees; k++) {
18906  if (myedegrees[k].pid == from) {
18907  if (myedegrees[k].ed == adjwgt[j])
18908  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
18909  else
18910  myedegrees[k].ed -= adjwgt[j];
18911  break;
18912  }
18913  }
18914  }
18915 
18916  /* Add contribution to the .ed of 'to' */
18917  if (me != to) {
18918  for (k=0; k<myrinfo->ndegrees; k++) {
18919  if (myedegrees[k].pid == to) {
18920  myedegrees[k].ed += adjwgt[j];
18921  break;
18922  }
18923  }
18924  if (k == myrinfo->ndegrees) {
18925  myedegrees[myrinfo->ndegrees].pid = to;
18926  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
18927  }
18928  }
18929 
18930  /* Update pmat to reflect the move of 'i' for domains other than 'from' and 'to' */
18931  if (me != from && me != to) {
18932  pmat[me*nparts+from] -= adjwgt[j];
18933  pmat[from*nparts+me] -= adjwgt[j];
18934  if (pmat[me*nparts+from] == 0)
18935  ndoms[me]--;
18936  if (pmat[from*nparts+me] == 0)
18937  ndoms[from]--;
18938 
18939  if (pmat[me*nparts+to] == 0)
18940  ndoms[me]++;
18941  if (pmat[to*nparts+me] == 0)
18942  ndoms[to]++;
18943 
18944  pmat[me*nparts+to] += adjwgt[j];
18945  pmat[to*nparts+me] += adjwgt[j];
18946  }
18947 
18948  ASSERT(CheckRInfo(myrinfo));
18949  }
18950 
18951  ASSERT(CheckRInfo(graph->rinfo+i));
18952  }
18953 
18954  graph->nbnd = nbnd;
18955 
18956 }
18957 
18958 
18959 
18960 
18961 /*************************************************************************
18962 * This function finds all the connected components induced by the
18963 * partitioning vector in wgraph->where and tries to push them around to
18964 * remove some of them
18965 **************************************************************************/
18966 void EliminateComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
18967 {
18968  int i, ii, j, jj, k, me, nvtxs, tvwgt, first, last, nleft, ncmps, cwgt, target, deltawgt;
18969  idxtype *xadj, *adjncy, *vwgt, *adjwgt, *where, *pwgts, *maxpwgt;
18970  idxtype *cpvec, *touched, *perm, *todo, *cind, *cptr, *npcmps;
18971 
18972  nvtxs = graph->nvtxs;
18973  xadj = graph->xadj;
18974  adjncy = graph->adjncy;
18975  vwgt = graph->vwgt;
18976  adjwgt = graph->adjwgt;
18977 
18978  where = graph->where;
18979  pwgts = graph->pwgts;
18980 
18981  touched = idxset(nvtxs, 0, idxwspacemalloc(ctrl, nvtxs));
18982  cptr = idxwspacemalloc(ctrl, nvtxs);
18983  cind = idxwspacemalloc(ctrl, nvtxs);
18984  perm = idxwspacemalloc(ctrl, nvtxs);
18985  todo = idxwspacemalloc(ctrl, nvtxs);
18986  maxpwgt = idxwspacemalloc(ctrl, nparts);
18987  cpvec = idxwspacemalloc(ctrl, nparts);
18988  npcmps = idxset(nparts, 0, idxwspacemalloc(ctrl, nparts));
18989 
18990  for (i=0; i<nvtxs; i++)
18991  perm[i] = todo[i] = i;
18992 
18993  /* Find the connected componends induced by the partition */
18994  ncmps = -1;
18995  first = last = 0;
18996  nleft = nvtxs;
18997  while (nleft > 0) {
18998  if (first == last) { /* Find another starting vertex */
18999  cptr[++ncmps] = first;
19000  ASSERT(touched[todo[0]] == 0);
19001  i = todo[0];
19002  cind[last++] = i;
19003  touched[i] = 1;
19004  me = where[i];
19005  npcmps[me]++;
19006  }
19007 
19008  i = cind[first++];
19009  k = perm[i];
19010  j = todo[k] = todo[--nleft];
19011  perm[j] = k;
19012 
19013  for (j=xadj[i]; j<xadj[i+1]; j++) {
19014  k = adjncy[j];
19015  if (where[k] == me && !touched[k]) {
19016  cind[last++] = k;
19017  touched[k] = 1;
19018  }
19019  }
19020  }
19021  cptr[++ncmps] = first;
19022 
19023  /* printf("I found %d components, for this %d-way partition\n", ncmps, nparts); */
19024 
19025  if (ncmps > nparts) { /* There are more components than processors */
19026  /* First determine the max allowed load imbalance */
19027  tvwgt = idxsum(nparts, pwgts);
19028  for (i=0; i<nparts; i++)
19029  maxpwgt[i] = ubfactor*tpwgts[i]*tvwgt;
19030 
19031  deltawgt = 5;
19032 
19033  for (i=0; i<ncmps; i++) {
19034  me = where[cind[cptr[i]]]; /* Get the domain of this component */
19035  if (npcmps[me] == 1)
19036  continue; /* Skip it because it is contigous */
19037 
19038  /*printf("Trying to move %d from %d\n", i, me); */
19039 
19040  /* Determine the weight of the block to be moved and abort if too high */
19041  for (cwgt=0, j=cptr[i]; j<cptr[i+1]; j++)
19042  cwgt += vwgt[cind[j]];
19043 
19044  if (cwgt > .30*pwgts[me])
19045  continue; /* Skip the component if it is over 30% of the weight */
19046 
19047  /* Determine the connectivity */
19048  idxset(nparts, 0, cpvec);
19049  for (j=cptr[i]; j<cptr[i+1]; j++) {
19050  ii = cind[j];
19051  for (jj=xadj[ii]; jj<xadj[ii+1]; jj++)
19052  cpvec[where[adjncy[jj]]] += adjwgt[jj];
19053  }
19054  cpvec[me] = 0;
19055 
19056  target = -1;
19057  for (j=0; j<nparts; j++) {
19058  if (cpvec[j] > 0 && (cwgt < deltawgt || pwgts[j] + cwgt < maxpwgt[j])) {
19059  if (target == -1 || cpvec[target] < cpvec[j])
19060  target = j;
19061  }
19062  }
19063 
19064  /* printf("\tMoving it to %d [%d]\n", target, cpvec[target]);*/
19065 
19066  if (target != -1) {
19067  /* Assign all the vertices of 'me' to 'target' and update data structures */
19068  INC_DEC(pwgts[target], pwgts[me], cwgt);
19069  npcmps[me]--;
19070 
19071  MoveGroup(ctrl, graph, nparts, target, i, cptr, cind);
19072  }
19073  }
19074 
19075  }
19076 
19077  idxwspacefree(ctrl, nparts);
19078  idxwspacefree(ctrl, nparts);
19079  idxwspacefree(ctrl, nparts);
19080  idxwspacefree(ctrl, nvtxs);
19081  idxwspacefree(ctrl, nvtxs);
19082  idxwspacefree(ctrl, nvtxs);
19083  idxwspacefree(ctrl, nvtxs);
19084  idxwspacefree(ctrl, nvtxs);
19085 
19086 }
19087 
19088 
19089 /*************************************************************************
19090 * This function moves a collection of vertices and updates their rinfo
19091 **************************************************************************/
19092 void MoveGroup(CtrlType *ctrl, GraphType *graph, int nparts, int to, int gid, idxtype *ptr, idxtype *ind)
19093 {
19094  int i, ii, iii, j, k, nvtxs, nbnd;
19095  int from, me;
19096  idxtype *xadj, *adjncy, *adjwgt;
19097  idxtype *where, *bndptr, *bndind;
19098  EDegreeType *myedegrees;
19099  RInfoType *myrinfo;
19100 
19101  nvtxs = graph->nvtxs;
19102  xadj = graph->xadj;
19103  adjncy = graph->adjncy;
19104  adjwgt = graph->adjwgt;
19105 
19106  where = graph->where;
19107  bndptr = graph->bndptr;
19108  bndind = graph->bndind;
19109 
19110  nbnd = graph->nbnd;
19111 
19112  for (iii=ptr[gid]; iii<ptr[gid+1]; iii++) {
19113  i = ind[iii];
19114  from = where[i];
19115 
19116  myrinfo = graph->rinfo+i;
19117  if (myrinfo->edegrees == NULL) {
19118  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
19119  ctrl->wspace.cdegree += xadj[i+1]-xadj[i];
19120  myrinfo->ndegrees = 0;
19121  }
19122  myedegrees = myrinfo->edegrees;
19123 
19124  /* find the location of 'to' in myrinfo or create it if it is not there */
19125  for (k=0; k<myrinfo->ndegrees; k++) {
19126  if (myedegrees[k].pid == to)
19127  break;
19128  }
19129  if (k == myrinfo->ndegrees) {
19130  myedegrees[k].pid = to;
19131  myedegrees[k].ed = 0;
19132  myrinfo->ndegrees++;
19133  }
19134 
19135  graph->mincut -= myedegrees[k].ed-myrinfo->id;
19136 
19137 
19138  /* Update where, weight, and ID/ED information of the vertex you moved */
19139  where[i] = to;
19140  myrinfo->ed += myrinfo->id-myedegrees[k].ed;
19141  SWAP(myrinfo->id, myedegrees[k].ed, j);
19142  if (myedegrees[k].ed == 0)
19143  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
19144  else
19145  myedegrees[k].pid = from;
19146 
19147  if (myrinfo->ed-myrinfo->id < 0 && bndptr[i] != -1)
19148  BNDDelete(nbnd, bndind, bndptr, i);
19149 
19150  /* Update the degrees of adjacent vertices */
19151  for (j=xadj[i]; j<xadj[i+1]; j++) {
19152  ii = adjncy[j];
19153  me = where[ii];
19154 
19155  myrinfo = graph->rinfo+ii;
19156  if (myrinfo->edegrees == NULL) {
19157  myrinfo->edegrees = ctrl->wspace.edegrees+ctrl->wspace.cdegree;
19158  ctrl->wspace.cdegree += xadj[ii+1]-xadj[ii];
19159  }
19160  myedegrees = myrinfo->edegrees;
19161 
19162  ASSERT(CheckRInfo(myrinfo));
19163 
19164  if (me == from) {
19165  INC_DEC(myrinfo->ed, myrinfo->id, adjwgt[j]);
19166 
19167  if (myrinfo->ed-myrinfo->id >= 0 && bndptr[ii] == -1)
19168  BNDInsert(nbnd, bndind, bndptr, ii);
19169  }
19170  else if (me == to) {
19171  INC_DEC(myrinfo->id, myrinfo->ed, adjwgt[j]);
19172 
19173  if (myrinfo->ed-myrinfo->id < 0 && bndptr[ii] != -1)
19174  BNDDelete(nbnd, bndind, bndptr, ii);
19175  }
19176 
19177  /* Remove contribution from the .ed of 'from' */
19178  if (me != from) {
19179  for (k=0; k<myrinfo->ndegrees; k++) {
19180  if (myedegrees[k].pid == from) {
19181  if (myedegrees[k].ed == adjwgt[j])
19182  myedegrees[k] = myedegrees[--myrinfo->ndegrees];
19183  else
19184  myedegrees[k].ed -= adjwgt[j];
19185  break;
19186  }
19187  }
19188  }
19189 
19190  /* Add contribution to the .ed of 'to' */
19191  if (me != to) {
19192  for (k=0; k<myrinfo->ndegrees; k++) {
19193  if (myedegrees[k].pid == to) {
19194  myedegrees[k].ed += adjwgt[j];
19195  break;
19196  }
19197  }
19198  if (k == myrinfo->ndegrees) {
19199  myedegrees[myrinfo->ndegrees].pid = to;
19200  myedegrees[myrinfo->ndegrees++].ed = adjwgt[j];
19201  }
19202  }
19203 
19204  ASSERT(CheckRInfo(myrinfo));
19205  }
19206 
19207  ASSERT(CheckRInfo(graph->rinfo+i));
19208  }
19209 
19210  graph->nbnd = nbnd;
19211 
19212 }
19213 
19214 /*
19215  * Copyright 1997, Regents of the University of Minnesota
19216  *
19217  * timing.c
19218  *
19219  * This file contains routines that deal with timing Metis
19220  *
19221  * Started 7/24/97
19222  * George
19223  *
19224  * $Id$
19225  *
19226  */
19227 
19228 
19229 
19230 
19231 /*************************************************************************
19232 * This function clears the timers
19233 **************************************************************************/
19235 {
19236  cleartimer(ctrl->TotalTmr);
19237  cleartimer(ctrl->InitPartTmr);
19238  cleartimer(ctrl->MatchTmr);
19239  cleartimer(ctrl->ContractTmr);
19240  cleartimer(ctrl->CoarsenTmr);
19241  cleartimer(ctrl->UncoarsenTmr);
19242  cleartimer(ctrl->RefTmr);
19243  cleartimer(ctrl->ProjectTmr);
19244  cleartimer(ctrl->SplitTmr);
19245  cleartimer(ctrl->SepTmr);
19246  cleartimer(ctrl->AuxTmr1);
19247  cleartimer(ctrl->AuxTmr2);
19248  cleartimer(ctrl->AuxTmr3);
19249  cleartimer(ctrl->AuxTmr4);
19250  cleartimer(ctrl->AuxTmr5);
19251  cleartimer(ctrl->AuxTmr6);
19252 }
19253 
19254 
19255 
19256 /*************************************************************************
19257 * This function prints the various timers
19258 **************************************************************************/
19260 {
19261  printf("\nTiming Information -------------------------------------------------");
19262  printf("\n Multilevel: \t\t %7.3f", gettimer(ctrl->TotalTmr));
19263  printf("\n Coarsening: \t\t %7.3f", gettimer(ctrl->CoarsenTmr));
19264  printf("\n Matching: \t\t\t %7.3f", gettimer(ctrl->MatchTmr));
19265  printf("\n Contract: \t\t\t %7.3f", gettimer(ctrl->ContractTmr));
19266  printf("\n Initial Partition: \t %7.3f", gettimer(ctrl->InitPartTmr));
19267  printf("\n Construct Separator: \t %7.3f", gettimer(ctrl->SepTmr));
19268  printf("\n Uncoarsening: \t\t %7.3f", gettimer(ctrl->UncoarsenTmr));
19269  printf("\n Refinement: \t\t\t %7.3f", gettimer(ctrl->RefTmr));
19270  printf("\n Projection: \t\t\t %7.3f", gettimer(ctrl->ProjectTmr));
19271  printf("\n Splitting: \t\t %7.3f", gettimer(ctrl->SplitTmr));
19272  printf("\n AUX1: \t\t %7.3f", gettimer(ctrl->AuxTmr1));
19273  printf("\n AUX2: \t\t %7.3f", gettimer(ctrl->AuxTmr2));
19274  printf("\n AUX3: \t\t %7.3f", gettimer(ctrl->AuxTmr3));
19275  printf("\n********************************************************************\n");
19276 }
19277 
19278 
19279 /*************************************************************************
19280 * This function returns the seconds
19281 **************************************************************************/
19282 double seconds(void)
19283 {
19284  return((double) clock()/CLOCKS_PER_SEC);
19285 }
19286 
19287 
19288 /*
19289  * Copyright 1997, Regents of the University of Minnesota
19290  *
19291  * util.c
19292  *
19293  * This function contains various utility routines
19294  *
19295  * Started 9/28/95
19296  * George
19297  *
19298  * $Id$
19299  */
19300 
19301 
19302 
19303 
19304 /*************************************************************************
19305 * This function prints an error message and exits
19306 **************************************************************************/
19307 void errexit(char *f_str,...)
19308 {
19309  va_list argp;
19310  char out1[256], out2[256];
19311 
19312  va_start(argp, f_str);
19313  vsprintf(out1, f_str, argp);
19314  va_end(argp);
19315 
19316  sprintf(out2, "Error! %s", out1);
19317 
19318  fprintf(stdout, "%s", out2);
19319  fflush(stdout);
19320 
19321  abort();
19322 }
19323 
19324 
19325 
19326 #ifndef DMALLOC
19327 /*************************************************************************
19328 * The following function allocates an array of integers
19329 **************************************************************************/
19330 int *imalloc(int n, char *msg)
19331 {
19332  if (n == 0)
19333  return NULL;
19334 
19335  return (int *)GKmalloc(sizeof(int)*n, msg);
19336 }
19337 
19338 
19339 /*************************************************************************
19340 * The following function allocates an array of integers
19341 **************************************************************************/
19342 idxtype *idxmalloc(int n, char *msg)
19343 {
19344  if (n == 0)
19345  return NULL;
19346 
19347  return (idxtype *)GKmalloc(sizeof(idxtype)*n, msg);
19348 }
19349 
19350 
19351 /*************************************************************************
19352 * The following function allocates an array of float
19353 **************************************************************************/
19354 float *fmalloc(int n, char *msg)
19355 {
19356  if (n == 0)
19357  return NULL;
19358 
19359  return (float *)GKmalloc(sizeof(float)*n, msg);
19360 }
19361 
19362 
19363 /*************************************************************************
19364 * The follwoing function allocates an array of integers
19365 **************************************************************************/
19366 int *ismalloc(int n, int ival, char *msg)
19367 {
19368  if (n == 0)
19369  return NULL;
19370 
19371  return iset(n, ival, (int *)GKmalloc(sizeof(int)*n, msg));
19372 }
19373 
19374 
19375 
19376 /*************************************************************************
19377 * The follwoing function allocates an array of integers
19378 **************************************************************************/
19379 idxtype *idxsmalloc(int n, idxtype ival, char *msg)
19380 {
19381  if (n == 0)
19382  return NULL;
19383 
19384  return idxset(n, ival, (idxtype *)GKmalloc(sizeof(idxtype)*n, msg));
19385 }
19386 
19387 
19388 /*************************************************************************
19389 * This function is my wrapper around malloc
19390 **************************************************************************/
19391 void *GKmalloc(int nbytes, char *msg)
19392 {
19393  void *ptr;
19394 
19395  if (nbytes == 0)
19396  return NULL;
19397 
19398  ptr = (void *)malloc(nbytes);
19399  if (ptr == NULL)
19400  errexit("***Memory allocation failed for %s. Requested size: %d bytes", msg, nbytes);
19401 
19402  return ptr;
19403 }
19404 #endif
19405 
19406 /*************************************************************************
19407 * This function is my wrapper around free, allows multiple pointers
19408 **************************************************************************/
19409 void GKfree(void **ptr1,...)
19410 {
19411  va_list plist;
19412  void **ptr;
19413 
19414  if (*ptr1 != NULL)
19415  free(*ptr1);
19416  *ptr1 = NULL;
19417 
19418  va_start(plist, ptr1);
19419 
19420  /* while ((int)(ptr = va_arg(plist, void **)) != -1) { */
19421  while ((ptr = va_arg(plist, void **)) != LTERM) {
19422  if (*ptr != NULL)
19423  free(*ptr);
19424  *ptr = NULL;
19425  }
19426 
19427  va_end(plist);
19428 }
19429 
19430 
19431 /*************************************************************************
19432 * These functions set the values of a vector
19433 **************************************************************************/
19434 int *iset(int n, int val, int *x)
19435 {
19436  int i;
19437 
19438  for (i=0; i<n; i++)
19439  x[i] = val;
19440 
19441  return x;
19442 }
19443 
19444 
19445 /*************************************************************************
19446 * These functions set the values of a vector
19447 **************************************************************************/
19449 {
19450  int i;
19451 
19452  for (i=0; i<n; i++)
19453  x[i] = val;
19454 
19455  return x;
19456 }
19457 
19458 
19459 /*************************************************************************
19460 * These functions set the values of a vector
19461 **************************************************************************/
19462 float *sset(int n, float val, float *x)
19463 {
19464  int i;
19465 
19466  for (i=0; i<n; i++)
19467  x[i] = val;
19468 
19469  return x;
19470 }
19471 
19472 
19473 
19474 /*************************************************************************
19475 * These functions return the index of the maximum element in a vector
19476 **************************************************************************/
19477 int iamax(int n, int *x)
19478 {
19479  int i, max=0;
19480 
19481  for (i=1; i<n; i++)
19482  max = (x[i] > x[max] ? i : max);
19483 
19484  return max;
19485 }
19486 
19487 
19488 /*************************************************************************
19489 * These functions return the index of the maximum element in a vector
19490 **************************************************************************/
19491 int idxamax(int n, idxtype *x)
19492 {
19493  int i, max=0;
19494 
19495  for (i=1; i<n; i++)
19496  max = (x[i] > x[max] ? i : max);
19497 
19498  return max;
19499 }
19500 
19501 /*************************************************************************
19502 * These functions return the index of the maximum element in a vector
19503 **************************************************************************/
19504 int idxamax_strd(int n, idxtype *x, int incx)
19505 {
19506  int i, max=0;
19507 
19508  n *= incx;
19509  for (i=incx; i<n; i+=incx)
19510  max = (x[i] > x[max] ? i : max);
19511 
19512  return max/incx;
19513 }
19514 
19515 
19516 
19517 /*************************************************************************
19518 * These functions return the index of the maximum element in a vector
19519 **************************************************************************/
19520 int samax(int n, float *x)
19521 {
19522  int i, max=0;
19523 
19524  for (i=1; i<n; i++)
19525  max = (x[i] > x[max] ? i : max);
19526 
19527  return max;
19528 }
19529 
19530 /*************************************************************************
19531 * These functions return the index of the almost maximum element in a vector
19532 **************************************************************************/
19533 int samax2(int n, float *x)
19534 {
19535  int i, max1, max2;
19536 
19537  if (x[0] > x[1]) {
19538  max1 = 0;
19539  max2 = 1;
19540  }
19541  else {
19542  max1 = 1;
19543  max2 = 0;
19544  }
19545 
19546  for (i=2; i<n; i++) {
19547  if (x[i] > x[max1]) {
19548  max2 = max1;
19549  max1 = i;
19550  }
19551  else if (x[i] > x[max2])
19552  max2 = i;
19553  }
19554 
19555  return max2;
19556 }
19557 
19558 
19559 /*************************************************************************
19560 * These functions return the index of the minimum element in a vector
19561 **************************************************************************/
19562 int idxamin(int n, idxtype *x)
19563 {
19564  int i, min=0;
19565 
19566  for (i=1; i<n; i++)
19567  min = (x[i] < x[min] ? i : min);
19568 
19569  return min;
19570 }
19571 
19572 
19573 /*************************************************************************
19574 * These functions return the index of the minimum element in a vector
19575 **************************************************************************/
19576 int samin(int n, float *x)
19577 {
19578  int i, min=0;
19579 
19580  for (i=1; i<n; i++)
19581  min = (x[i] < x[min] ? i : min);
19582 
19583  return min;
19584 }
19585 
19586 
19587 /*************************************************************************
19588 * This function sums the entries in an array
19589 **************************************************************************/
19590 int idxsum(int n, idxtype *x)
19591 {
19592  int i, sum = 0;
19593 
19594  for (i=0; i<n; i++)
19595  sum += x[i];
19596 
19597  return sum;
19598 }
19599 
19600 
19601 /*************************************************************************
19602 * This function sums the entries in an array
19603 **************************************************************************/
19604 int idxsum_strd(int n, idxtype *x, int incx)
19605 {
19606  int i, sum = 0;
19607 
19608  for (i=0; i<n; i++, x+=incx) {
19609  sum += *x;
19610  }
19611 
19612  return sum;
19613 }
19614 
19615 
19616 /*************************************************************************
19617 * This function sums the entries in an array
19618 **************************************************************************/
19619 void idxadd(int n, idxtype *x, idxtype *y)
19620 {
19621  for (n--; n>=0; n--)
19622  y[n] += x[n];
19623 }
19624 
19625 
19626 /*************************************************************************
19627 * This function sums the entries in an array
19628 **************************************************************************/
19629 int charsum(int n, char *x)
19630 {
19631  int i, sum = 0;
19632 
19633  for (i=0; i<n; i++)
19634  sum += x[i];
19635 
19636  return sum;
19637 }
19638 
19639 /*************************************************************************
19640 * This function sums the entries in an array
19641 **************************************************************************/
19642 int isum(int n, int *x)
19643 {
19644  int i, sum = 0;
19645 
19646  for (i=0; i<n; i++)
19647  sum += x[i];
19648 
19649  return sum;
19650 }
19651 
19652 /*************************************************************************
19653 * This function sums the entries in an array
19654 **************************************************************************/
19655 float ssum(int n, float *x)
19656 {
19657  int i;
19658  float sum = 0.0;
19659 
19660  for (i=0; i<n; i++)
19661  sum += x[i];
19662 
19663  return sum;
19664 }
19665 
19666 /*************************************************************************
19667 * This function sums the entries in an array
19668 **************************************************************************/
19669 float ssum_strd(int n, float *x, int incx)
19670 {
19671  int i;
19672  float sum = 0.0;
19673 
19674  for (i=0; i<n; i++, x+=incx)
19675  sum += *x;
19676 
19677  return sum;
19678 }
19679 
19680 /*************************************************************************
19681 * This function sums the entries in an array
19682 **************************************************************************/
19683 void sscale(int n, float alpha, float *x)
19684 {
19685  int i;
19686 
19687  for (i=0; i<n; i++)
19688  x[i] *= alpha;
19689 }
19690 
19691 
19692 /*************************************************************************
19693 * This function computes a 2-norm
19694 **************************************************************************/
19695 float snorm2(int n, float *v)
19696 {
19697  int i;
19698  float partial = 0;
19699 
19700  for (i = 0; i<n; i++)
19701  partial += v[i] * v[i];
19702 
19703  return sqrt(partial);
19704 }
19705 
19706 
19707 
19708 /*************************************************************************
19709 * This function computes a 2-norm
19710 **************************************************************************/
19711 float sdot(int n, float *x, float *y)
19712 {
19713  int i;
19714  float partial = 0;
19715 
19716  for (i = 0; i<n; i++)
19717  partial += x[i] * y[i];
19718 
19719  return partial;
19720 }
19721 
19722 
19723 /*************************************************************************
19724 * This function computes a 2-norm
19725 **************************************************************************/
19726 void saxpy(int n, float alpha, float *x, int incx, float *y, int incy)
19727 {
19728  int i;
19729 
19730  for (i=0; i<n; i++, x+=incx, y+=incy)
19731  *y += alpha*(*x);
19732 }
19733 
19734 
19735 
19736 
19737 /*************************************************************************
19738 * This file randomly permutes the contents of an array.
19739 * flag == 0, don't initialize perm
19740 * flag == 1, set p[i] = i
19741 **************************************************************************/
19742 void RandomPermute(int n, idxtype *p, int flag)
19743 {
19744  int i, u, v;
19745  idxtype tmp;
19746 
19747  if (flag == 1) {
19748  for (i=0; i<n; i++)
19749  p[i] = i;
19750  }
19751 
19752  if (n <= 4)
19753  return;
19754 
19755  for (i=0; i<n; i+=16) {
19756  u = RandomInRangeFast(n-4);
19757  v = RandomInRangeFast(n-4);
19758  SWAP(p[v], p[u], tmp);
19759  SWAP(p[v+1], p[u+1], tmp);
19760  SWAP(p[v+2], p[u+2], tmp);
19761  SWAP(p[v+3], p[u+3], tmp);
19762  }
19763 }
19764 
19765 
19766 
19767 /*************************************************************************
19768 * This function returns true if the a is a power of 2
19769 **************************************************************************/
19770 int ispow2(int a)
19771 {
19772  for (; a%2 != 1; a = a>>1);
19773  return (a > 1 ? 0 : 1);
19774 }
19775 
19776 
19777 /*************************************************************************
19778 * This function initializes the random number generator
19779 **************************************************************************/
19780 void InitRandom(int seed)
19781 {
19782  if (seed == -1) {
19783 #ifndef __VC__
19784  srand48(7654321L);
19785 #endif
19786  srand(4321);
19787  }
19788  else {
19789 #ifndef __VC__
19790  srand48(seed);
19791 #endif
19792  srand(seed);
19793  }
19794 }
19795 
19796 /*************************************************************************
19797 * This function returns the log2(x)
19798 **************************************************************************/
19799 int log2(int a)
19800 {
19801  int i;
19802 
19803  for (i=1; a > 1; i++, a = a>>1);
19804  return i-1;
19805 }
#define OPTION_ITYPE
Definition: defs.h:31
#define MAXNCON
Definition: defs.h:20
#define KMETIS_DBGLVL
Definition: defs.h:52
#define OP_PMETIS
Definition: defs.h:89
#define OEMETIS_DBGLVL
Definition: defs.h:58
#define OP_OEMETIS
Definition: defs.h:91
#define IPART_GGPKL
Definition: defs.h:108
#define OPTION_OFLAGS
Definition: defs.h:34
#define DBG_MOVEINFO
Definition: defs.h:159
#define OPTION_PFACTOR
Definition: defs.h:35
#define KVMETIS_CTYPE
Definition: defs.h:82
#define DBG_COARSEN
Definition: defs.h:156
#define KMETIS_CTYPE
Definition: defs.h:49
#define OPTION_CTYPE
Definition: defs.h:30
#define MMDSWITCH
Definition: defs.h:149
#define ONMETIS_ITYPE
Definition: defs.h:62
#define RTYPE_KWAYRANDOM_MCONN
Definition: defs.h:121
#define UNMATCHED
Definition: defs.h:131
#define PMETIS_CTYPE
Definition: defs.h:43
#define MATCH_HEM
Definition: defs.h:99
#define DBG_SEPINFO
Definition: defs.h:161
#define OEMETIS_CTYPE
Definition: defs.h:55
#define KVMETIS_DBGLVL
Definition: defs.h:85
#define MATCH_SBHEM_INFNORM
Definition: defs.h:105
#define OFLAG_COMPRESS
Definition: defs.h:38
#define HTLENGTH
Definition: defs.h:26
#define PMETIS_RTYPE
Definition: defs.h:45
#define SMALLNIPARTS
Definition: defs.h:139
#define RTYPE_KWAYGREEDY
Definition: defs.h:120
#define MATCH_SHEBM_ONENORM
Definition: defs.h:102
#define McKMETIS_ITYPE
Definition: defs.h:77
#define PLUS_GAINSPAN
Definition: defs.h:23
#define RTYPE_KWAYRANDOM
Definition: defs.h:119
#define MATCH_SHEM
Definition: defs.h:100
#define OP_KVMETIS
Definition: defs.h:94
#define ONMETIS_RTYPE
Definition: defs.h:63
#define PMETIS_ITYPE
Definition: defs.h:44
#define ORDER_UNBALANCE_FRACTION
Definition: defs.h:147
#define MATCH_RM
Definition: defs.h:98
#define PMETIS_DBGLVL
Definition: defs.h:46
#define IPART_RANDOM
Definition: defs.h:110
#define McKMETIS_RTYPE
Definition: defs.h:78
#define COARSEN_FRACTION2
Definition: defs.h:142
#define OPTION_NSEPS
Definition: defs.h:36
#define McPMETIS_RTYPE
Definition: defs.h:72
#define KMETIS_ITYPE
Definition: defs.h:50
#define OEMETIS_ITYPE
Definition: defs.h:56
#define OP_ONMETIS
Definition: defs.h:92
#define IPART_GGPKLNODE
Definition: defs.h:109
#define MATCH_SHEMKWAY
Definition: defs.h:101
#define McPMETIS_CTYPE
Definition: defs.h:70
#define McKMETIS_DBGLVL
Definition: defs.h:79
#define ONMETIS_OFLAGS
Definition: defs.h:65
#define DBG_IPART
Definition: defs.h:158
#define KVMETIS_ITYPE
Definition: defs.h:83
#define DBG_REFINE
Definition: defs.h:157
#define KMETIS_RTYPE
Definition: defs.h:51
#define LARGENIPARTS
Definition: defs.h:138
#define OPTION_RTYPE
Definition: defs.h:32
#define MATCH_SHEBM_INFNORM
Definition: defs.h:103
#define ONMETIS_CTYPE
Definition: defs.h:61
#define LTERM
Definition: defs.h:18
#define ONMETIS_PFACTOR
Definition: defs.h:66
#define ONMETIS_DBGLVL
Definition: defs.h:64
#define OP_KMETIS
Definition: defs.h:90
#define ONMETIS_NSEPS
Definition: defs.h:67
#define DBG_KWAYPINFO
Definition: defs.h:160
#define McPMETIS_DBGLVL
Definition: defs.h:73
#define DBG_TIME
Definition: defs.h:154
#define KVMETIS_RTYPE
Definition: defs.h:84
#define OEMETIS_RTYPE
Definition: defs.h:57
#define McPMETIS_ITYPE
Definition: defs.h:71
#define MATCH_SBHEM_ONENORM
Definition: defs.h:104
#define McKMETIS_CTYPE
Definition: defs.h:76
#define OPTION_DBGLVL
Definition: defs.h:33
#define OFLAG_CCMP
Definition: defs.h:39
#define NEG_GAINSPAN
Definition: defs.h:24
#define RTYPE_FM
Definition: defs.h:113
#define COMPRESSION_FRACTION
Definition: defs.h:145
#define scopy(n, a, b)
Definition: macros.h:43
#define MALLOC_CHECK(ptr)
Definition: macros.h:83
#define INC_DEC(a, b, val)
Definition: macros.h:39
#define ASSERT(expr)
Definition: macros.h:130
#define SWAP(a, b, tmp)
Definition: macros.h:36
#define BNDInsert(nbnd, bndind, bndptr, vtx)
Definition: macros.h:102
#define MAKECSR(i, n, a)
Definition: macros.h:91
#define ASSERTP(expr, msg)
Definition: macros.h:142
#define BNDDelete(nbnd, bndind, bndptr, vtx)
Definition: macros.h:109
#define gettimer(tmr)
Definition: macros.h:55
#define stoptimer(tmr)
Definition: macros.h:54
#define cleartimer(tmr)
Definition: macros.h:52
#define RandomInRangeFast(u)
Definition: macros.h:24
#define IFSET(a, flag, cmd)
Definition: macros.h:61
#define amin(a, b)
Definition: macros.h:30
#define idxcopy(n, a, b)
Definition: macros.h:44
#define amax(a, b)
Definition: macros.h:29
#define starttimer(tmr)
Definition: macros.h:53
#define RandomInRange(u)
Definition: macros.h:23
void METIS_PartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:3361
void MlevelNestedDissection(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx)
Definition: metis.c:14103
void Balance2Way(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:21
void SetUpSplitGraph(GraphType *graph, GraphType *sgraph, int snvtxs, int snedges)
Definition: metis.c:15294
void iintsort(int n, int *base)
Definition: metis.c:13455
int MocIsHBalanced(int ncon, int nparts, float *npwgts, float *ubvec)
Definition: metis.c:11018
void METIS_WPartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:14652
#define INROW
Definition: metis.c:9367
void SelectQueue2(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2], float *maxwgt)
Definition: metis.c:8917
int idxamax(int n, idxtype *x)
Definition: metis.c:19491
void Change2CNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy)
Definition: metis.c:1869
void METIS_PARTMESHDUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2157
void METIS_PARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2044
#define THRESH
Definition: metis.c:13312
int MCMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float ubfactor, int fpart)
Definition: metis.c:12760
int mmdint(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker)
Definition: metis.c:12238
GraphType * Coarsen2Way(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:938
void MocInit2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts)
Definition: metis.c:10153
int PQueueInsert(PQueueType *queue, int node, int gain)
Definition: metis.c:15464
void InitTimers(CtrlType *ctrl)
Definition: metis.c:19234
void SplitGraphPart(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph)
Definition: metis.c:15175
void metis_meshtodual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2201
int PQueueGetMax(PQueueType *queue)
Definition: metis.c:15765
void genmmd(int neqns, idxtype *xadj, idxtype *adjncy, idxtype *invp, idxtype *perm, int delta, idxtype *head, idxtype *qsize, idxtype *list, idxtype *marker, int maxint, int *ncsub)
Definition: metis.c:11986
int AreAllHVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit)
Definition: metis.c:10982
void InitGraph(GraphType *graph)
Definition: metis.c:8012
int CheckNodePartitionParams(GraphType *graph)
Definition: metis.c:1428
void PQueueReset(PQueueType *queue)
Definition: metis.c:15406
void METIS_NodeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *options, int *sepsize, idxtype *part)
Definition: metis.c:14873
void metis_nodewnd_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2128
void AllocateWorkSpace(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:7862
void metis_meshtodual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2205
void metis_wpartgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2037
void CreateCoarseGraphNoMask(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
Definition: metis.c:515
void MinCover(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *cover, int *csize)
Definition: metis.c:9389
void metis_partgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2048
void GrowBisectionNode(CtrlType *ctrl, GraphType *graph, float ubfactor)
Definition: metis.c:3127
int AreAnyVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
Definition: metis.c:13231
void MlevelNestedDissectionCC(CtrlType *ctrl, GraphType *graph, idxtype *order, float ubfactor, int lastvtx)
Definition: metis.c:14166
void SetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int wgtflag)
Definition: metis.c:2322
void EliminateVolComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
Definition: metis.c:6272
int WspaceAvail(CtrlType *ctrl)
Definition: metis.c:7937
void MocRefineKWayHorizontal(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *ubvec)
Definition: metis.c:11150
void metis_wpartgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2033
void RandomPermute(int n, idxtype *p, int flag)
Definition: metis.c:19742
void MocInit2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:9763
int AreAllHVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float *limit)
Definition: metis.c:10965
void METIS_NODEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2101
void metis_edgend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2090
int AreAllVwgtsAbove(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
Definition: metis.c:13248
void METIS_PARTMESHNODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2139
void Allocate2WayNodePartitionMemory(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:17529
void MocComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:11408
void METIS_NodeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:13919
void metis_meshtodual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2197
int idxamin(int n, idxtype *x)
Definition: metis.c:19562
void METIS_mCPartGraphKway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:10353
#define HC
Definition: metis.c:9370
void MlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:15153
void METIS_WPARTGRAPHKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2063
void HEXNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8318
void metis_estimatememory_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
Definition: metis.c:2219
void iidxsort(int n, idxtype *base)
Definition: metis.c:13327
void MocCompute2WayPartitionParams(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:13065
int * ismalloc(int n, int ival, char *msg)
Definition: metis.c:19366
GraphType * CreateGraph(void)
Definition: metis.c:7996
void ChangeMesh2FNumbering(int n, idxtype *mesh, int nvtxs, idxtype *xadj, idxtype *adjncy)
Definition: metis.c:1955
void ikeyvalsort(int n, KeyValueType *base)
Definition: metis.c:13720
void FM_2WayNodeRefine_OneSided(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
Definition: metis.c:17109
void METIS_EDGEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2082
int IsHBalanceBetterTT(int ncon, int nparts, float *pt1, float *pt2, float *vwgt, float *ubvec)
Definition: metis.c:11094
int IsHBalanceBetterFT(int ncon, int nparts, float *pfrom, float *pto, float *vwgt, float *ubvec)
Definition: metis.c:11046
void mmdelm(int mdeg_node, idxtype *xadj, idxtype *adjncy, idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker, int maxint, int tag)
Definition: metis.c:12104
int BetterBalance(int ncon, float *npwgts, float *tpwgts, float *diff)
Definition: metis.c:9306
int CheckBnd2(GraphType *graph)
Definition: metis.c:1340
void ComputeKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:4612
void Random_KWayVolRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
Definition: metis.c:4821
void AllocateVolKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:6543
void MCHMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:12907
void metis_partgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
Definition: metis.c:2274
void metis_partgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2052
void mmdnum(int neqns, idxtype *perm, idxtype *invp, idxtype *qsize)
Definition: metis.c:12281
void MocRefine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float ubfactor)
Definition: metis.c:12994
void metis_edgend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2086
void CreateCoarseGraph(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
Definition: metis.c:342
void Change2FNumbering(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vector)
Definition: metis.c:1884
void MocInit2WayPartition(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
Definition: metis.c:9996
void fwspacefree(CtrlType *ctrl, int n)
Definition: metis.c:7982
GraphType * SetUpCoarseGraph(GraphType *graph, int cnvtxs, int dovsize)
Definition: metis.c:799
void Greedy_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
Definition: metis.c:3816
void sscale(int n, float alpha, float *x)
Definition: metis.c:19683
void FreeWorkSpace(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:7928
void MCMatch_RM(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:11449
void metis_nodend(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2105
void MlevelNodeBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:14312
void metis_nodend_(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2109
void MinCover_Decompose(idxtype *xadj, idxtype *adjncy, int asize, int bsize, idxtype *mate, idxtype *cover, int *csize)
Definition: metis.c:9511
void TRINODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8220
void metis_estimatememory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
Definition: metis.c:2215
void MoveGroupMConn(CtrlType *ctrl, GraphType *graph, idxtype *ndoms, idxtype *pmat, int nparts, int to, int nind, idxtype *ind)
Definition: metis.c:18810
int MCHMlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *ubvec, int fpart)
Definition: metis.c:12813
void Match_RM(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:6918
void Random_KWayVolRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
Definition: metis.c:4677
void EliminateVolSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts)
Definition: metis.c:6045
void MCRandom_KWayEdgeRefineHorizontal(CtrlType *ctrl, GraphType *graph, int nparts, float *orgubvec, int npasses)
Definition: metis.c:10473
void MocProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:11302
void MCMatch_HEM(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:11506
void TETNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8269
int IsConnected2(GraphType *graph, int report)
Definition: metis.c:2792
void Greedy_KWayVolBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
Definition: metis.c:5060
int SelectQueueOneWay2(int ncon, float *pto, PQueueType queues[MAXNCON][2], float *ubvec)
Definition: metis.c:9937
int ComputeCoarseGraphSize(int nvtxs, idxtype *xadj, idxtype *adjncy, int cnvtxs, idxtype *cmap, idxtype *match, idxtype *perm)
Definition: metis.c:1608
void MocBalance2Way(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor)
Definition: metis.c:7512
void METIS_MESHTONODAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2175
void metis_nodewnd__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2132
int PQueueSeeMax(PQueueType *queue)
Definition: metis.c:15836
void metis_partmeshdual_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2165
int ComputeCut(GraphType *graph, idxtype *where)
Definition: metis.c:1278
void SetUpGraph2(GraphType *graph, int nvtxs, int ncon, idxtype *xadj, idxtype *adjncy, float *nvwgt, idxtype *adjwgt)
Definition: metis.c:2472
void METIS_PartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:15006
void metis_wpartgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
Definition: metis.c:2295
void MCMatch_SHEM(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:11565
void metis_mcpartgraphrecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2234
void idxadd(int n, idxtype *x, idxtype *y)
Definition: metis.c:19619
void METIS_MESHTODUAL(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2193
void METIS_PARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2007
void errexit(char *f_str,...)
Definition: metis.c:19307
int PQueueUpdate(PQueueType *queue, int node, int oldgain, int newgain)
Definition: metis.c:15619
void PQueueUpdateUp(PQueueType *queue, int node, int oldgain, int newgain)
Definition: metis.c:15692
void METIS_MCPARTGRAPHRECURSIVE(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2230
int iamax(int n, int *x)
Definition: metis.c:19477
void RandomBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:3263
int samax(int n, float *x)
Definition: metis.c:19520
void Greedy_KWayEdgeBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
Definition: metis.c:18230
void ConstructSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
Definition: metis.c:16129
void CheckVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:5877
void METIS_mCHPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *ubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:12603
int ComputeMaxNodeGain(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt)
Definition: metis.c:17443
void METIS_PartMeshNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:8471
void AllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:4381
void METIS_PARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
Definition: metis.c:2266
void METIS_mCPartGraphRecursive(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:12550
void PQueueFree(CtrlType *ctrl, PQueueType *queue)
Definition: metis.c:15430
void MocInit2WayPartition2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:9628
void Match_SHEM(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:7079
void PrintSubDomainGraph(GraphType *graph, int nparts, idxtype *where)
Definition: metis.c:18543
void METIS_NodeNDP(int nvtxs, idxtype *xadj, idxtype *adjncy, int npes, int *options, idxtype *perm, idxtype *iperm, idxtype *sizes)
Definition: metis.c:14702
#define SC
Definition: metis.c:9369
void Allocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:15962
int SelectQueueOneWay(int ncon, float *npwgts, float *tpwgts, int from, PQueueType queues[MAXNCON][2])
Definition: metis.c:10314
int FindComponents(CtrlType *ctrl, GraphType *graph, idxtype *cptr, idxtype *cind)
Definition: metis.c:2855
void MinCover_RowDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag)
Definition: metis.c:9585
void Greedy_KWayVolBalanceMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
Definition: metis.c:5214
void PQueueInit(CtrlType *ctrl, PQueueType *queue, int maxnodes, int maxgain)
Definition: metis.c:15349
void METIS_WPARTGRAPHRECURSIVE(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2025
float sdot(int n, float *x, float *y)
Definition: metis.c:19711
void FM_2WayNodeRefine(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
Definition: metis.c:16413
int MlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor)
Definition: metis.c:3432
void metis_wpartgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2029
void MocProject2WayPartition(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:13124
void MlevelNodeBisectionMultiple(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:14230
void METIS_MeshToDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8074
void ComputeVolKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:6565
void metis_nodend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2113
void metis_partgraphrecursive__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2019
idxtype * idxmalloc(int n, char *msg)
Definition: metis.c:19342
void CreateCoarseGraph_NVW(CtrlType *ctrl, GraphType *graph, int cnvtxs, idxtype *match, idxtype *perm)
Definition: metis.c:650
void metis_meshtonodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2187
void QUADNODALMETIS(int nelmnts, int nvtxs, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8391
void ComputeSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms)
Definition: metis.c:18594
void GENDUALMETIS(int nelmnts, int nvtxs, int etype, idxtype *elmnts, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8125
void metis_partgraphvkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
Definition: metis.c:2278
int CheckBnd(GraphType *graph)
Definition: metis.c:1304
void metis_partgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2056
void ComputeVolKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:6875
void METIS_ESTIMATEMEMORY(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
Definition: metis.c:2211
void metis_mcpartgraphkway(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2252
void metis_partmeshnodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2143
void Greedy_KWayEdgeBalance(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses)
Definition: metis.c:4046
int IsSeparable(GraphType *graph)
Definition: metis.c:1475
int idxsum_strd(int n, idxtype *x, int incx)
Definition: metis.c:19604
void VolSetUpGraph(GraphType *graph, int OpType, int nvtxs, int ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int wgtflag)
Definition: metis.c:2512
void metis_nodewnd(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2124
void metis_mcpartgraphkway__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2260
int idxamax_strd(int n, idxtype *x, int incx)
Definition: metis.c:19504
void SelectQueue3(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2], float *maxwgt)
Definition: metis.c:7428
int PQueueGetSize(PQueueType *queue)
Definition: metis.c:15455
void METIS_WPartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
Definition: metis.c:3509
void METIS_PartGraphVKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
Definition: metis.c:3488
int idxsum(int n, idxtype *x)
Definition: metis.c:19590
void EliminateComponents(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
Definition: metis.c:18966
int * iset(int n, int val, int *x)
Definition: metis.c:19434
void MocGeneral2WayBalance(CtrlType *ctrl, GraphType *graph, float *tpwgts, float lbfactor)
Definition: metis.c:7526
void GKfree(void **ptr1,...)
Definition: metis.c:19409
void METIS_NodeWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:14044
float ComputeElementBalance(int ne, int nparts, idxtype *where)
Definition: metis.c:17901
idxtype * idxset(int n, idxtype val, idxtype *x)
Definition: metis.c:19448
void MCMatch_SHEBM(CtrlType *ctrl, GraphType *graph, int norm)
Definition: metis.c:11659
void MocGrowBisectionNew2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:9715
void MinCover_ColDFS(idxtype *xadj, idxtype *adjncy, int root, idxtype *mate, idxtype *where, int flag)
Definition: metis.c:9560
GraphType * MCCoarsen2Way(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:7769
int charsum(int n, char *x)
Definition: metis.c:19629
void Random_KWayEdgeRefine(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
Definition: metis.c:3613
void Init2WayPartition(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:2938
void MlevelNestedDissectionP(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx, int npes, int cpos, idxtype *sizes)
Definition: metis.c:14800
void FM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, int *tpwgts, int npasses)
Definition: metis.c:1674
void ChangeMesh2CNumbering(int n, idxtype *mesh)
Definition: metis.c:1942
int CheckRInfo(RInfoType *rinfo)
Definition: metis.c:1411
void RandomizeGraph(GraphType *graph)
Definition: metis.c:2653
void Change2FNumbering2(int nvtxs, idxtype *xadj, idxtype *adjncy)
Definition: metis.c:1902
void SelectQueue(int ncon, float *npwgts, float *tpwgts, int *from, int *cnum, PQueueType queues[MAXNCON][2])
Definition: metis.c:9241
void metis_wpartgraphkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2067
#define HR
Definition: metis.c:9373
void METIS_PartGraphKway2(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:14630
int samax2(int n, float *x)
Definition: metis.c:19533
float ComputeLoadImbalance(int ncon, int nparts, float *npwgts, float *tpwgts)
Definition: metis.c:13264
void METIS_MeshToNodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:8093
void metis_wpartgraphkway__(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2075
float BetterVBalance(int ncon, int norm, float *vwgt, float *u1wgt, float *u2wgt)
Definition: metis.c:11862
#define VC
Definition: metis.c:9368
void METIS_EdgeComputeSeparator(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *options, int *sepsize, idxtype *part)
Definition: metis.c:14932
int PQueueDelete(PQueueType *queue, int node, int gain)
Definition: metis.c:15523
void ComputePartitionInfo(GraphType *graph, int nparts, idxtype *where)
Definition: metis.c:17651
void ComputeVolKWayBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:6850
void METIS_mCHPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, float *nvwgt, idxtype *adjwgt, int *nparts, float *ubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:12707
void MCGreedy_KWayEdgeBalanceHorizontal(CtrlType *ctrl, GraphType *graph, int nparts, float *ubvec, int npasses)
Definition: metis.c:10710
int SplitGraphOrderCC(CtrlType *ctrl, GraphType *graph, GraphType *sgraphs, int ncmps, idxtype *cptr, idxtype *cind)
Definition: metis.c:14507
float Compute2WayHLoadImbalance(int ncon, float *npwgts, float *tpwgts)
Definition: metis.c:9322
void ComputeHKWayLoadImbalance(int ncon, int nparts, float *npwgts, float *lbvec)
Definition: metis.c:10998
void MocBalance2Way2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:7185
int IsConnectedSubdomain(CtrlType *ctrl, GraphType *graph, int pid, int report)
Definition: metis.c:2677
void ComputeKWayVolGains(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:6645
void FM_2WayNodeRefine2(CtrlType *ctrl, GraphType *graph, float ubfactor, int npasses)
Definition: metis.c:16648
void ConstructMinCoverSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
Definition: metis.c:16286
float * sset(int n, float val, float *x)
Definition: metis.c:19462
idxtype * idxwspacemalloc(CtrlType *ctrl, int n)
Definition: metis.c:7946
int MinCover_Augment(idxtype *xadj, idxtype *adjncy, int col, idxtype *mate, idxtype *flag, idxtype *level, int maxlevel)
Definition: metis.c:9474
void metis_partmeshnodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2147
void RefineVolKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
Definition: metis.c:6456
void CompressGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *cptr, idxtype *cind)
Definition: metis.c:1023
void METIS_WPartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:3382
void Project2WayPartition(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:16038
int samin(int n, float *x)
Definition: metis.c:19576
#define SR
Definition: metis.c:9372
void metis_mcpartgraphkway_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2256
int isum(int n, int *x)
Definition: metis.c:19642
void METIS_NODEWND(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2120
void KWayVolUpdate(CtrlType *ctrl, GraphType *graph, int v, int from, int to, idxtype *marker, idxtype *phtable, idxtype *updind)
Definition: metis.c:5463
void * GKmalloc(int nbytes, char *msg)
Definition: metis.c:19391
void Match_RM_NVW(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:6971
void metis_partmeshnodal__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2151
void General2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts)
Definition: metis.c:173
void SetUpGraphKway(GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy)
Definition: metis.c:2443
int MlevelVolKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor)
Definition: metis.c:3559
void PrintTimers(CtrlType *ctrl)
Definition: metis.c:19259
int AreAllVwgtsBelow(int ncon, float alpha, float *vwgt1, float beta, float *vwgt2, float limit)
Definition: metis.c:13215
int ispow2(int a)
Definition: metis.c:19770
float ssum_strd(int n, float *x, int incx)
Definition: metis.c:19669
void InitRandom(int seed)
Definition: metis.c:19780
void METIS_EstimateMemory(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
Definition: metis.c:1519
float * fwspacemalloc(CtrlType *ctrl, int n)
Definition: metis.c:7970
void METIS_MCPARTGRAPHKWAY(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *rubvec, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2248
int IsBetter2wayBalance(int ncon, float *newbal, float *oldbal, float *ubvec)
Definition: metis.c:8980
void Compute2WayPartitionParams(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:15981
int CheckHeap(PQueueType *queue)
Definition: metis.c:15876
void METIS_EdgeND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:13862
void MocFM_2WayEdgeRefine2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *orgubvec, int npasses)
Definition: metis.c:8674
void metis_mcpartgraphrecursive_(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2238
void METIS_WPARTGRAPHVKWAY(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
Definition: metis.c:2283
void FM_2WayNodeBalance(CtrlType *ctrl, GraphType *graph, float ubfactor)
Definition: metis.c:17310
void MocGeneral2WayBalance2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:7199
void metis_meshtonodal_(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2183
void MCMlevelEdgeBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
Definition: metis.c:12890
void Compute2WayHLoadImbalanceVec(int ncon, float *npwgts, float *tpwgts, float *lbvec)
Definition: metis.c:9340
void ComputeKWayVolume(GraphType *graph, int nupd, idxtype *updind, idxtype *marker, idxtype *phtable)
Definition: metis.c:5747
void metis_estimatememory__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *optype, int *nbytes)
Definition: metis.c:2223
void METIS_WPartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:15029
void PruneGraph(CtrlType *ctrl, GraphType *graph, int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *iperm, float factor)
Definition: metis.c:1162
idxtype * idxsmalloc(int n, idxtype ival, char *msg)
Definition: metis.c:19379
int MCMlevelKWayPartitioning(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *rubvec)
Definition: metis.c:10405
void ikeysort(int n, KeyValueType *base)
Definition: metis.c:13584
float * fmalloc(int n, char *msg)
Definition: metis.c:19354
int ComputeVolume(GraphType *graph, idxtype *where)
Definition: metis.c:5838
void ComputePartitionBalance(GraphType *graph, int nparts, idxtype *where, float *ubvec)
Definition: metis.c:17867
void Compute2WayNodePartitionParams(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:17550
void SplitGraphOrder(CtrlType *ctrl, GraphType *graph, GraphType *lgraph, GraphType *rgraph)
Definition: metis.c:14352
void idxwspacefree(CtrlType *ctrl, int n)
Definition: metis.c:7958
int IsConnected(CtrlType *ctrl, GraphType *graph, int report)
Definition: metis.c:2755
void MCMatch_SBHEM(CtrlType *ctrl, GraphType *graph, int norm)
Definition: metis.c:11760
float snorm2(int n, float *v)
Definition: metis.c:19695
int log2(int a)
Definition: metis.c:19799
int MlevelRecursiveBisection(CtrlType *ctrl, GraphType *graph, int nparts, idxtype *part, float *tpwgts, float ubfactor, int fpart)
Definition: metis.c:15087
void FreeGraph(GraphType *graph)
Definition: metis.c:8044
void EliminateSubDomainEdges(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts)
Definition: metis.c:18639
void MMDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int lastvtx)
Definition: metis.c:14461
void Project2WayNodePartition(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:17605
void MocAllocate2WayPartitionMemory(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:13044
void RefineKWay(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int nparts, float *tpwgts, float ubfactor)
Definition: metis.c:4286
void metis_partgraphrecursive_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2015
void BucketSortKeysInc(int n, int max, idxtype *keys, idxtype *tperm, idxtype *perm)
Definition: metis.c:302
void Random_KWayEdgeRefineMConn(CtrlType *ctrl, GraphType *graph, int nparts, float *tpwgts, float ubfactor, int npasses, int ffactor)
Definition: metis.c:17940
void metis_edgend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
Definition: metis.c:2094
void Bnd2WayBalance(CtrlType *ctrl, GraphType *graph, int *tpwgts)
Definition: metis.c:47
void MocRefine2Way2(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:12939
void METIS_mCPartGraphRecursiveInternal(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, float *nvwgt, idxtype *adjwgt, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:12661
double seconds(void)
Definition: metis.c:19282
void ProjectVolKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:6745
void MoveGroup(CtrlType *ctrl, GraphType *graph, int nparts, int to, int gid, idxtype *ptr, idxtype *ind)
Definition: metis.c:19092
void ComputeVolSubDomainGraph(GraphType *graph, int nparts, idxtype *pmat, idxtype *ndoms)
Definition: metis.c:6003
void MocAllocateKWayPartitionMemory(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:11197
void metis_partmeshdual__(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2169
float ssum(int n, float *x)
Definition: metis.c:19655
void metis_wpartgraphvkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
Definition: metis.c:2291
#define INCOL
Definition: metis.c:9366
#define VR
Definition: metis.c:9371
#define MTHRESH
Definition: metis.c:13313
int * imalloc(int n, char *msg)
Definition: metis.c:19330
void metis_partmeshdual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:2161
void ProjectKWayPartition(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:4488
void MocFM_2WayEdgeRefine(CtrlType *ctrl, GraphType *graph, float *tpwgts, int npasses)
Definition: metis.c:9023
void Refine2Way(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:15924
void mmdupd(int ehead, int neqns, idxtype *xadj, idxtype *adjncy, int delta, int *mdeg, idxtype *head, idxtype *forward, idxtype *backward, idxtype *qsize, idxtype *list, idxtype *marker, int maxint, int *tag)
Definition: metis.c:12345
void MocComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:11219
void InitSeparator(CtrlType *ctrl, GraphType *graph, float ubfactor)
Definition: metis.c:2972
void MocGrowBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
Definition: metis.c:10032
void GrowBisection(CtrlType *ctrl, GraphType *graph, int *tpwgts, float ubfactor)
Definition: metis.c:2999
void ChangeMesh2FNumbering2(int n, idxtype *mesh, int ne, int nn, idxtype *epart, idxtype *npart)
Definition: metis.c:1975
void Refine2WayNode(CtrlType *ctrl, GraphType *orggraph, GraphType *graph, float ubfactor)
Definition: metis.c:17482
int PQueueGetKey(PQueueType *queue)
Definition: metis.c:15855
void Match_HEM(CtrlType *ctrl, GraphType *graph)
Definition: metis.c:7023
void metis_wpartgraphkway_(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2071
void metis_mcpartgraphrecursive__(int *nvtxs, int *ncon, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2242
void METIS_PartMeshDual(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, int *nparts, int *edgecut, idxtype *epart, idxtype *npart)
Definition: metis.c:8559
void ConstructMinCoverSeparator0(CtrlType *ctrl, GraphType *graph, float ubfactor)
Definition: metis.c:16171
void ComputePartitionInfoBipartite(GraphType *graph, int nparts, idxtype *where)
Definition: metis.c:17761
void ReAdjustMemory(GraphType *graph, GraphType *cgraph, int dovsize)
Definition: metis.c:863
int AreAllVwgtsBelowFast(int ncon, float *vwgt1, float *vwgt2, float limit)
Definition: metis.c:11923
void MocRandomBisection(CtrlType *ctrl, GraphType *graph, float *tpwgts, float ubfactor)
Definition: metis.c:10080
void FM_2WayNodeRefineEqWgt(CtrlType *ctrl, GraphType *graph, int npasses)
Definition: metis.c:16885
void MocGrowBisection2(CtrlType *ctrl, GraphType *graph, float *tpwgts, float *ubvec)
Definition: metis.c:9664
int AreAllBelow(int ncon, float *v1, float *v2)
Definition: metis.c:13286
void Change2FNumberingOrder(int nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *v1, idxtype *v2)
Definition: metis.c:1919
int IsBalanced(idxtype *pwgts, int nparts, float *tpwgts, float ubfactor)
Definition: metis.c:4595
void metis_wpartgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, float *tpwgts, int *options, int *volume, idxtype *part)
Definition: metis.c:2287
void saxpy(int n, float alpha, float *x, int incx, float *y, int incy)
Definition: metis.c:19726
void EstimateCFraction(int nvtxs, idxtype *xadj, idxtype *adjncy, float *vfraction, float *efraction)
Definition: metis.c:1563
int CheckNodeBnd(GraphType *graph, int onbnd)
Definition: metis.c:1375
void metis_partgraphvkway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *vsize, int *wgtflag, int *numflag, int *nparts, int *options, int *volume, idxtype *part)
Definition: metis.c:2270
void metis_partgraphrecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt, idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts, int *options, int *edgecut, idxtype *part)
Definition: metis.c:2011
void ComputeKWayBalanceBoundary(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:4637
void ComputeKWayPartitionParams(CtrlType *ctrl, GraphType *graph, int nparts)
Definition: metis.c:4407
void metis_meshtonodal(int *ne, int *nn, idxtype *elmnts, int *etype, int *numflag, idxtype *dxadj, idxtype *dadjncy)
Definition: metis.c:2179
integer(kind=inttype) istart
Definition: BCPointers.F90:20
integer(kind=inttype) iend
Definition: BCPointers.F90:20
integer(kind=inttype) jstart
Definition: BCPointers.F90:21
integer(kind=inttype) jj
Definition: blockette.F90:21
integer(kind=inttype) ii
Definition: blockette.F90:21
integer(kind=inttype) kk
Definition: blockette.F90:21
real(kind=realtype), dimension(:, :, :), pointer p
integer(kind=inttype), dimension(:, :, :), pointer status
real(kind=realtype), dimension(:, :, :, :), pointer x
integer(kind=inttype), parameter imax
Definition: constants.F90:293
integer(kind=inttype), parameter imin
Definition: constants.F90:292
real(kind=realtype) beta
Definition: inputParam.F90:591
real(kind=realtype) alpha
Definition: inputParam.F90:591
integer(kind=inttype), dimension(:), allocatable part
real, dimension(2) ubvec
integer(kind=inttype) function delta(val1, val2)
Definition: utils.F90:2534
void srand48(long)
int CheckGraph(GraphType *)
ADflow_intT idxtype
Definition: struct.h:19
#define MAXIDX
Definition: struct.h:21
struct ListNodeType ListNodeType
Definition: struct.h:43
idxtype key
Definition: struct.h:28
idxtype val
Definition: struct.h:29
int id
Definition: struct.h:39
struct ListNodeType * next
Definition: struct.h:40
struct ListNodeType * prev
Definition: struct.h:40
int mustfree
Definition: struct.h:55
idxtype * locator
Definition: struct.h:65
int type
Definition: struct.h:52
int pgainspan
Definition: struct.h:58
ListNodeType * nodes
Definition: struct.h:60
ListNodeType ** buckets
Definition: struct.h:61
int maxnodes
Definition: struct.h:54
int maxgain
Definition: struct.h:59
KeyValueType * heap
Definition: struct.h:64
int ngainspan
Definition: struct.h:58
int nnodes
Definition: struct.h:53
timer AuxTmr3
Definition: struct.h:228
int dbglvl
Definition: struct.h:213
timer ContractTmr
Definition: struct.h:227
WorkSpaceType wspace
Definition: struct.h:224
timer ProjectTmr
Definition: struct.h:228
timer AuxTmr2
Definition: struct.h:228
int pfactor
Definition: struct.h:220
timer RefTmr
Definition: struct.h:228
timer CoarsenTmr
Definition: struct.h:227
timer AuxTmr6
Definition: struct.h:228
int CType
Definition: struct.h:214
timer UncoarsenTmr
Definition: struct.h:227
timer InitPartTmr
Definition: struct.h:227
int optype
Definition: struct.h:219
int IType
Definition: struct.h:215
int nseps
Definition: struct.h:221
int maxvwgt
Definition: struct.h:217
int CoarsenTo
Definition: struct.h:212
int RType
Definition: struct.h:216
timer SepTmr
Definition: struct.h:228
timer MatchTmr
Definition: struct.h:227
timer AuxTmr1
Definition: struct.h:228
float nmaxvwgt
Definition: struct.h:218
int oflags
Definition: struct.h:222
timer AuxTmr4
Definition: struct.h:228
timer AuxTmr5
Definition: struct.h:228
timer TotalTmr
Definition: struct.h:227
timer SplitTmr
Definition: struct.h:228
idxtype pid
Definition: struct.h:75
idxtype ed
Definition: struct.h:76
int nbnd
Definition: struct.h:174
idxtype * adjncy
Definition: struct.h:162
VRInfoType * vrinfo
Definition: struct.h:184
idxtype * bndind
Definition: struct.h:175
idxtype * where
Definition: struct.h:173
idxtype * rdata
Definition: struct.h:154
int nvtxs
Definition: struct.h:158
idxtype * gdata
Definition: struct.h:154
idxtype * ed
Definition: struct.h:178
idxtype * vwgt
Definition: struct.h:160
float * nvwgt
Definition: struct.h:192
int minvol
Definition: struct.h:172
NRInfoType * nrinfo
Definition: struct.h:187
idxtype * adjwgtsum
Definition: struct.h:165
struct graphdef * finer
Definition: struct.h:195
RInfoType * rinfo
Definition: struct.h:181
idxtype * pwgts
Definition: struct.h:173
idxtype * label
Definition: struct.h:167
int ncon
Definition: struct.h:191
idxtype * id
Definition: struct.h:178
float * npwgts
Definition: struct.h:193
int nedges
Definition: struct.h:158
int mincut
Definition: struct.h:172
idxtype * adjwgt
Definition: struct.h:163
idxtype * bndptr
Definition: struct.h:175
idxtype * vsize
Definition: struct.h:161
struct graphdef * coarser
Definition: struct.h:195
idxtype * xadj
Definition: struct.h:159
idxtype * cmap
Definition: struct.h:169
idxtype edegrees[2]
Definition: struct.h:144
int id
Definition: struct.h:117
int ndegrees
Definition: struct.h:118
EDegreeType * edegrees
Definition: struct.h:119
int ed
Definition: struct.h:117
idxtype ed
Definition: struct.h:86
idxtype ned
Definition: struct.h:86
idxtype pid
Definition: struct.h:85
idxtype gv
Definition: struct.h:87
int gv
Definition: struct.h:131
int id
Definition: struct.h:130
int ndegrees
Definition: struct.h:132
VEDegreeType * edegrees
Definition: struct.h:133
int nid
Definition: struct.h:130
int ed
Definition: struct.h:130
idxtype * core
Definition: struct.h:96
int ccore
Definition: struct.h:97
EDegreeType * edegrees
Definition: struct.h:99
int maxcore
Definition: struct.h:97
idxtype * auxcore
Definition: struct.h:103
int cdegree
Definition: struct.h:101
VEDegreeType * vedegrees
Definition: struct.h:100
idxtype * pmat
Definition: struct.h:105