Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/metis-5.1.0/libmetis/ometis.c
3206 views
1
/*
2
* Copyright 1997, Regents of the University of Minnesota
3
*
4
* ometis.c
5
*
6
* This file contains the top level routines for the multilevel recursive
7
* bisection algorithm PMETIS.
8
*
9
* Started 7/24/97
10
* George
11
*
12
* $Id: ometis.c 10513 2011-07-07 22:06:03Z karypis $
13
*
14
*/
15
16
#include "metislib.h"
17
18
19
/*************************************************************************/
20
/*! This function is the entry point for the multilevel nested dissection
21
ordering code. At each bisection, a node-separator is computed using
22
a node-based refinement approach.
23
24
\param nvtxs is the number of vertices in the graph.
25
\param xadj is of length nvtxs+1 marking the start of the adjancy
26
list of each vertex in adjncy.
27
\param adjncy stores the adjacency lists of the vertices. The adjnacy
28
list of a vertex should not contain the vertex itself.
29
\param vwgt is an array of size nvtxs storing the weight of each
30
vertex. If vwgt is NULL, then the vertices are considered
31
to have unit weight.
32
\param numflag is either 0 or 1 indicating that the numbering of
33
the vertices starts from 0 or 1, respectively.
34
\param options is an array of size METIS_NOPTIONS used to pass
35
various options impacting the of the algorithm. A NULL
36
value indicates use of default options.
37
\param perm is an array of size nvtxs such that if A and A' are
38
the original and permuted matrices, then A'[i] = A[perm[i]].
39
\param iperm is an array of size nvtxs such that if A and A' are
40
the original and permuted matrices, then A[i] = A'[iperm[i]].
41
*/
42
/*************************************************************************/
43
int METIS_NodeND(idx_t *nvtxs, idx_t *xadj, idx_t *adjncy, idx_t *vwgt,
44
idx_t *options, idx_t *perm, idx_t *iperm)
45
{
46
int sigrval=0, renumber=0;
47
idx_t i, ii, j, l, nnvtxs=0;
48
graph_t *graph=NULL;
49
ctrl_t *ctrl;
50
idx_t *cptr, *cind, *piperm;
51
int numflag = 0;
52
53
/* set up malloc cleaning code and signal catchers */
54
if (!gk_malloc_init())
55
return METIS_ERROR_MEMORY;
56
57
gk_sigtrap();
58
59
if ((sigrval = gk_sigcatch()) != 0)
60
goto SIGTHROW;
61
62
63
/* set up the run time parameters */
64
ctrl = SetupCtrl(METIS_OP_OMETIS, options, 1, 3, NULL, NULL);
65
if (!ctrl) {
66
gk_siguntrap();
67
return METIS_ERROR_INPUT;
68
}
69
70
/* if required, change the numbering to 0 */
71
if (ctrl->numflag == 1) {
72
Change2CNumbering(*nvtxs, xadj, adjncy);
73
renumber = 1;
74
}
75
76
IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl));
77
IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr));
78
79
/* prune the dense columns */
80
if (ctrl->pfactor > 0.0) {
81
piperm = imalloc(*nvtxs, "OMETIS: piperm");
82
83
graph = PruneGraph(ctrl, *nvtxs, xadj, adjncy, vwgt, piperm, ctrl->pfactor);
84
if (graph == NULL) {
85
/* if there was no prunning, cleanup the pfactor */
86
gk_free((void **)&piperm, LTERM);
87
ctrl->pfactor = 0.0;
88
}
89
else {
90
nnvtxs = graph->nvtxs;
91
ctrl->compress = 0; /* disable compression if prunning took place */
92
}
93
}
94
95
/* compress the graph; note that compression only happens if not prunning
96
has taken place. */
97
if (ctrl->compress) {
98
cptr = imalloc(*nvtxs+1, "OMETIS: cptr");
99
cind = imalloc(*nvtxs, "OMETIS: cind");
100
101
graph = CompressGraph(ctrl, *nvtxs, xadj, adjncy, vwgt, cptr, cind);
102
if (graph == NULL) {
103
/* if there was no compression, cleanup the compress flag */
104
gk_free((void **)&cptr, &cind, LTERM);
105
ctrl->compress = 0;
106
}
107
else {
108
nnvtxs = graph->nvtxs;
109
ctrl->cfactor = 1.0*(*nvtxs)/nnvtxs;
110
if (ctrl->cfactor > 1.5 && ctrl->nseps == 1)
111
ctrl->nseps = 2;
112
//ctrl->nseps = (idx_t)(ctrl->cfactor*ctrl->nseps);
113
}
114
}
115
116
/* if no prunning and no compression, setup the graph in the normal way. */
117
if (ctrl->pfactor == 0.0 && ctrl->compress == 0)
118
graph = SetupGraph(ctrl, *nvtxs, 1, xadj, adjncy, vwgt, NULL, NULL);
119
120
ASSERT(CheckGraph(graph, ctrl->numflag, 1));
121
122
/* allocate workspace memory */
123
AllocateWorkSpace(ctrl, graph);
124
125
/* do the nested dissection ordering */
126
if (ctrl->ccorder)
127
MlevelNestedDissectionCC(ctrl, graph, iperm, graph->nvtxs);
128
else
129
MlevelNestedDissection(ctrl, graph, iperm, graph->nvtxs);
130
131
132
if (ctrl->pfactor > 0.0) { /* Order any prunned vertices */
133
icopy(nnvtxs, iperm, perm); /* Use perm as an auxiliary array */
134
for (i=0; i<nnvtxs; i++)
135
iperm[piperm[i]] = perm[i];
136
for (i=nnvtxs; i<*nvtxs; i++)
137
iperm[piperm[i]] = i;
138
139
gk_free((void **)&piperm, LTERM);
140
}
141
else if (ctrl->compress) { /* Uncompress the ordering */
142
/* construct perm from iperm */
143
for (i=0; i<nnvtxs; i++)
144
perm[iperm[i]] = i;
145
for (l=ii=0; ii<nnvtxs; ii++) {
146
i = perm[ii];
147
for (j=cptr[i]; j<cptr[i+1]; j++)
148
iperm[cind[j]] = l++;
149
}
150
151
gk_free((void **)&cptr, &cind, LTERM);
152
}
153
154
for (i=0; i<*nvtxs; i++)
155
perm[iperm[i]] = i;
156
157
IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr));
158
IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl));
159
160
/* clean up */
161
FreeCtrl(&ctrl);
162
163
SIGTHROW:
164
/* if required, change the numbering back to 1 */
165
if (renumber)
166
Change2FNumberingOrder(*nvtxs, xadj, adjncy, perm, iperm);
167
168
gk_siguntrap();
169
gk_malloc_cleanup(0);
170
171
return metis_rcode(sigrval);
172
}
173
174
175
/*************************************************************************/
176
/*! This is the driver for the recursive tri-section of a graph into the
177
left, separator, and right partitions. The graphs correspond to the
178
left and right parts are further tri-sected in a recursive fashion.
179
The nodes in the separator are ordered at the end of the left & right
180
nodes.
181
*/
182
/*************************************************************************/
183
void MlevelNestedDissection(ctrl_t *ctrl, graph_t *graph, idx_t *order,
184
idx_t lastvtx)
185
{
186
idx_t i, j, nvtxs, nbnd;
187
idx_t *label, *bndind;
188
graph_t *lgraph, *rgraph;
189
190
nvtxs = graph->nvtxs;
191
192
MlevelNodeBisectionMultiple(ctrl, graph);
193
194
IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO,
195
printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n",
196
graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
197
198
199
/* Order the nodes in the separator */
200
nbnd = graph->nbnd;
201
bndind = graph->bndind;
202
label = graph->label;
203
for (i=0; i<nbnd; i++)
204
order[label[bndind[i]]] = --lastvtx;
205
206
SplitGraphOrder(ctrl, graph, &lgraph, &rgraph);
207
208
/* Free the memory of the top level graph */
209
FreeGraph(&graph);
210
211
/* Recurse on lgraph first, as its lastvtx depends on rgraph->nvtxs, which
212
will not be defined upon return from MlevelNestedDissection. */
213
if (lgraph->nvtxs > MMDSWITCH && lgraph->nedges > 0)
214
MlevelNestedDissection(ctrl, lgraph, order, lastvtx-rgraph->nvtxs);
215
else {
216
MMDOrder(ctrl, lgraph, order, lastvtx-rgraph->nvtxs);
217
FreeGraph(&lgraph);
218
}
219
if (rgraph->nvtxs > MMDSWITCH && rgraph->nedges > 0)
220
MlevelNestedDissection(ctrl, rgraph, order, lastvtx);
221
else {
222
MMDOrder(ctrl, rgraph, order, lastvtx);
223
FreeGraph(&rgraph);
224
}
225
}
226
227
228
/*************************************************************************/
229
/*! This routine is similar to its non 'CC' counterpart. The difference is
230
that after each tri-section, the connected components of the original
231
graph that result after removing the separator vertises are ordered
232
independently (i.e., this may lead to more than just the left and
233
the right subgraphs).
234
*/
235
/*************************************************************************/
236
void MlevelNestedDissectionCC(ctrl_t *ctrl, graph_t *graph, idx_t *order,
237
idx_t lastvtx)
238
{
239
idx_t i, j, nvtxs, nbnd, ncmps, rnvtxs, snvtxs;
240
idx_t *label, *bndind;
241
idx_t *cptr, *cind;
242
graph_t **sgraphs;
243
244
nvtxs = graph->nvtxs;
245
246
MlevelNodeBisectionMultiple(ctrl, graph);
247
248
IFSET(ctrl->dbglvl, METIS_DBG_SEPINFO,
249
printf("Nvtxs: %6"PRIDX", [%6"PRIDX" %6"PRIDX" %6"PRIDX"]\n",
250
graph->nvtxs, graph->pwgts[0], graph->pwgts[1], graph->pwgts[2]));
251
252
/* Order the nodes in the separator */
253
nbnd = graph->nbnd;
254
bndind = graph->bndind;
255
label = graph->label;
256
for (i=0; i<nbnd; i++)
257
order[label[bndind[i]]] = --lastvtx;
258
259
WCOREPUSH;
260
cptr = iwspacemalloc(ctrl, nvtxs+1);
261
cind = iwspacemalloc(ctrl, nvtxs);
262
ncmps = FindSepInducedComponents(ctrl, graph, cptr, cind);
263
264
if (ctrl->dbglvl&METIS_DBG_INFO) {
265
if (ncmps > 2)
266
printf(" Bisection resulted in %"PRIDX" connected components\n", ncmps);
267
}
268
269
sgraphs = SplitGraphOrderCC(ctrl, graph, ncmps, cptr, cind);
270
271
WCOREPOP;
272
273
/* Free the memory of the top level graph */
274
FreeGraph(&graph);
275
276
/* Go and process the subgraphs */
277
for (rnvtxs=i=0; i<ncmps; i++) {
278
/* Save the number of vertices in sgraphs[i] because sgraphs[i] is freed
279
inside MlevelNestedDissectionCC, and as such it will be undefined. */
280
snvtxs = sgraphs[i]->nvtxs;
281
282
if (sgraphs[i]->nvtxs > MMDSWITCH && sgraphs[i]->nedges > 0) {
283
MlevelNestedDissectionCC(ctrl, sgraphs[i], order, lastvtx-rnvtxs);
284
}
285
else {
286
MMDOrder(ctrl, sgraphs[i], order, lastvtx-rnvtxs);
287
FreeGraph(&sgraphs[i]);
288
}
289
rnvtxs += snvtxs;
290
}
291
292
gk_free((void **)&sgraphs, LTERM);
293
}
294
295
296
/*************************************************************************/
297
/*! This function performs multilevel node bisection (i.e., tri-section).
298
It performs multiple bisections and selects the best. */
299
/*************************************************************************/
300
void MlevelNodeBisectionMultiple(ctrl_t *ctrl, graph_t *graph)
301
{
302
idx_t i, mincut;
303
idx_t *bestwhere;
304
305
/* if the graph is small, just find a single vertex separator */
306
if (ctrl->nseps == 1 || graph->nvtxs < (ctrl->compress ? 1000 : 2000)) {
307
MlevelNodeBisectionL2(ctrl, graph, LARGENIPARTS);
308
return;
309
}
310
311
WCOREPUSH;
312
313
bestwhere = iwspacemalloc(ctrl, graph->nvtxs);
314
315
mincut = graph->tvwgt[0];
316
for (i=0; i<ctrl->nseps; i++) {
317
MlevelNodeBisectionL2(ctrl, graph, LARGENIPARTS);
318
319
if (i == 0 || graph->mincut < mincut) {
320
mincut = graph->mincut;
321
if (i < ctrl->nseps-1)
322
icopy(graph->nvtxs, graph->where, bestwhere);
323
}
324
325
if (mincut == 0)
326
break;
327
328
if (i < ctrl->nseps-1)
329
FreeRData(graph);
330
}
331
332
if (mincut != graph->mincut) {
333
icopy(graph->nvtxs, bestwhere, graph->where);
334
Compute2WayNodePartitionParams(ctrl, graph);
335
}
336
337
WCOREPOP;
338
}
339
340
341
/*************************************************************************/
342
/*! This function performs multilevel node bisection (i.e., tri-section).
343
It performs multiple bisections and selects the best. */
344
/*************************************************************************/
345
void MlevelNodeBisectionL2(ctrl_t *ctrl, graph_t *graph, idx_t niparts)
346
{
347
idx_t i, mincut, nruns=5;
348
graph_t *cgraph;
349
idx_t *bestwhere;
350
351
/* if the graph is small, just find a single vertex separator */
352
if (graph->nvtxs < 5000) {
353
MlevelNodeBisectionL1(ctrl, graph, niparts);
354
return;
355
}
356
357
WCOREPUSH;
358
359
ctrl->CoarsenTo = gk_max(100, graph->nvtxs/30);
360
361
cgraph = CoarsenGraphNlevels(ctrl, graph, 4);
362
363
bestwhere = iwspacemalloc(ctrl, cgraph->nvtxs);
364
365
mincut = graph->tvwgt[0];
366
for (i=0; i<nruns; i++) {
367
MlevelNodeBisectionL1(ctrl, cgraph, 0.7*niparts);
368
369
if (i == 0 || cgraph->mincut < mincut) {
370
mincut = cgraph->mincut;
371
if (i < nruns-1)
372
icopy(cgraph->nvtxs, cgraph->where, bestwhere);
373
}
374
375
if (mincut == 0)
376
break;
377
378
if (i < nruns-1)
379
FreeRData(cgraph);
380
}
381
382
if (mincut != cgraph->mincut)
383
icopy(cgraph->nvtxs, bestwhere, cgraph->where);
384
385
WCOREPOP;
386
387
Refine2WayNode(ctrl, graph, cgraph);
388
389
}
390
391
392
/*************************************************************************/
393
/*! The top-level routine of the actual multilevel node bisection */
394
/*************************************************************************/
395
void MlevelNodeBisectionL1(ctrl_t *ctrl, graph_t *graph, idx_t niparts)
396
{
397
graph_t *cgraph;
398
399
ctrl->CoarsenTo = graph->nvtxs/8;
400
if (ctrl->CoarsenTo > 100)
401
ctrl->CoarsenTo = 100;
402
else if (ctrl->CoarsenTo < 40)
403
ctrl->CoarsenTo = 40;
404
405
cgraph = CoarsenGraph(ctrl, graph);
406
407
niparts = gk_max(1, (cgraph->nvtxs <= ctrl->CoarsenTo ? niparts/2: niparts));
408
/*niparts = (cgraph->nvtxs <= ctrl->CoarsenTo ? SMALLNIPARTS : LARGENIPARTS);*/
409
InitSeparator(ctrl, cgraph, niparts);
410
411
Refine2WayNode(ctrl, graph, cgraph);
412
}
413
414
415
/*************************************************************************/
416
/*! This function takes a graph and a tri-section (left, right, separator)
417
and splits it into two graphs.
418
419
This function relies on the fact that adjwgt is all equal to 1.
420
*/
421
/*************************************************************************/
422
void SplitGraphOrder(ctrl_t *ctrl, graph_t *graph, graph_t **r_lgraph,
423
graph_t **r_rgraph)
424
{
425
idx_t i, ii, j, k, l, istart, iend, mypart, nvtxs, snvtxs[3], snedges[3];
426
idx_t *xadj, *vwgt, *adjncy, *adjwgt, *label, *where, *bndptr, *bndind;
427
idx_t *sxadj[2], *svwgt[2], *sadjncy[2], *sadjwgt[2], *slabel[2];
428
idx_t *rename;
429
idx_t *auxadjncy;
430
graph_t *lgraph, *rgraph;
431
432
WCOREPUSH;
433
434
IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->SplitTmr));
435
436
nvtxs = graph->nvtxs;
437
xadj = graph->xadj;
438
vwgt = graph->vwgt;
439
adjncy = graph->adjncy;
440
adjwgt = graph->adjwgt;
441
label = graph->label;
442
where = graph->where;
443
bndptr = graph->bndptr;
444
bndind = graph->bndind;
445
ASSERT(bndptr != NULL);
446
447
rename = iwspacemalloc(ctrl, nvtxs);
448
449
snvtxs[0] = snvtxs[1] = snvtxs[2] = snedges[0] = snedges[1] = snedges[2] = 0;
450
for (i=0; i<nvtxs; i++) {
451
k = where[i];
452
rename[i] = snvtxs[k]++;
453
snedges[k] += xadj[i+1]-xadj[i];
454
}
455
456
lgraph = SetupSplitGraph(graph, snvtxs[0], snedges[0]);
457
sxadj[0] = lgraph->xadj;
458
svwgt[0] = lgraph->vwgt;
459
sadjncy[0] = lgraph->adjncy;
460
sadjwgt[0] = lgraph->adjwgt;
461
slabel[0] = lgraph->label;
462
463
rgraph = SetupSplitGraph(graph, snvtxs[1], snedges[1]);
464
sxadj[1] = rgraph->xadj;
465
svwgt[1] = rgraph->vwgt;
466
sadjncy[1] = rgraph->adjncy;
467
sadjwgt[1] = rgraph->adjwgt;
468
slabel[1] = rgraph->label;
469
470
/* Go and use bndptr to also mark the boundary nodes in the two partitions */
471
for (ii=0; ii<graph->nbnd; ii++) {
472
i = bndind[ii];
473
for (j=xadj[i]; j<xadj[i+1]; j++)
474
bndptr[adjncy[j]] = 1;
475
}
476
477
snvtxs[0] = snvtxs[1] = snedges[0] = snedges[1] = 0;
478
sxadj[0][0] = sxadj[1][0] = 0;
479
for (i=0; i<nvtxs; i++) {
480
if ((mypart = where[i]) == 2)
481
continue;
482
483
istart = xadj[i];
484
iend = xadj[i+1];
485
if (bndptr[i] == -1) { /* This is an interior vertex */
486
auxadjncy = sadjncy[mypart] + snedges[mypart] - istart;
487
for(j=istart; j<iend; j++)
488
auxadjncy[j] = adjncy[j];
489
snedges[mypart] += iend-istart;
490
}
491
else {
492
auxadjncy = sadjncy[mypart];
493
l = snedges[mypart];
494
for (j=istart; j<iend; j++) {
495
k = adjncy[j];
496
if (where[k] == mypart)
497
auxadjncy[l++] = k;
498
}
499
snedges[mypart] = l;
500
}
501
502
svwgt[mypart][snvtxs[mypart]] = vwgt[i];
503
slabel[mypart][snvtxs[mypart]] = label[i];
504
sxadj[mypart][++snvtxs[mypart]] = snedges[mypart];
505
}
506
507
for (mypart=0; mypart<2; mypart++) {
508
iend = snedges[mypart];
509
iset(iend, 1, sadjwgt[mypart]);
510
511
auxadjncy = sadjncy[mypart];
512
for (i=0; i<iend; i++)
513
auxadjncy[i] = rename[auxadjncy[i]];
514
}
515
516
lgraph->nvtxs = snvtxs[0];
517
lgraph->nedges = snedges[0];
518
rgraph->nvtxs = snvtxs[1];
519
rgraph->nedges = snedges[1];
520
521
SetupGraph_tvwgt(lgraph);
522
SetupGraph_tvwgt(rgraph);
523
524
IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->SplitTmr));
525
526
*r_lgraph = lgraph;
527
*r_rgraph = rgraph;
528
529
WCOREPOP;
530
}
531
532
533
/*************************************************************************/
534
/*! This function takes a graph and generates a set of graphs, each of
535
which is a connected component in the original graph.
536
537
This function relies on the fact that adjwgt is all equal to 1.
538
539
\param ctrl stores run state info.
540
\param graph is the graph to be split.
541
\param ncmps is the number of connected components.
542
\param cptr is an array of size ncmps+1 that marks the start and end
543
locations of the vertices in cind that make up the respective
544
components (i.e., cptr, cind is in CSR format).
545
\param cind is an array of size equal to the number of vertices in
546
the original graph and stores the vertices that belong to each
547
connected component.
548
549
\returns an array of subgraphs corresponding to the extracted subgraphs.
550
*/
551
/*************************************************************************/
552
graph_t **SplitGraphOrderCC(ctrl_t *ctrl, graph_t *graph, idx_t ncmps,
553
idx_t *cptr, idx_t *cind)
554
{
555
idx_t i, ii, iii, j, k, l, istart, iend, mypart, nvtxs, snvtxs, snedges;
556
idx_t *xadj, *vwgt, *adjncy, *adjwgt, *label, *where, *bndptr, *bndind;
557
idx_t *sxadj, *svwgt, *sadjncy, *sadjwgt, *slabel;
558
idx_t *rename;
559
idx_t *auxadjncy;
560
graph_t **sgraphs;
561
562
WCOREPUSH;
563
564
IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->SplitTmr));
565
566
nvtxs = graph->nvtxs;
567
xadj = graph->xadj;
568
vwgt = graph->vwgt;
569
adjncy = graph->adjncy;
570
adjwgt = graph->adjwgt;
571
label = graph->label;
572
where = graph->where;
573
bndptr = graph->bndptr;
574
bndind = graph->bndind;
575
ASSERT(bndptr != NULL);
576
577
/* Go and use bndptr to also mark the boundary nodes in the two partitions */
578
for (ii=0; ii<graph->nbnd; ii++) {
579
i = bndind[ii];
580
for (j=xadj[i]; j<xadj[i+1]; j++)
581
bndptr[adjncy[j]] = 1;
582
}
583
584
rename = iwspacemalloc(ctrl, nvtxs);
585
586
sgraphs = (graph_t **)gk_malloc(sizeof(graph_t *)*ncmps, "SplitGraphOrderCC: sgraphs");
587
588
/* Go and split the graph a component at a time */
589
for (iii=0; iii<ncmps; iii++) {
590
irandArrayPermute(cptr[iii+1]-cptr[iii], cind+cptr[iii], cptr[iii+1]-cptr[iii], 0);
591
snvtxs = snedges = 0;
592
for (j=cptr[iii]; j<cptr[iii+1]; j++) {
593
i = cind[j];
594
rename[i] = snvtxs++;
595
snedges += xadj[i+1]-xadj[i];
596
}
597
598
sgraphs[iii] = SetupSplitGraph(graph, snvtxs, snedges);
599
600
sxadj = sgraphs[iii]->xadj;
601
svwgt = sgraphs[iii]->vwgt;
602
sadjncy = sgraphs[iii]->adjncy;
603
sadjwgt = sgraphs[iii]->adjwgt;
604
slabel = sgraphs[iii]->label;
605
606
snvtxs = snedges = sxadj[0] = 0;
607
for (ii=cptr[iii]; ii<cptr[iii+1]; ii++) {
608
i = cind[ii];
609
610
istart = xadj[i];
611
iend = xadj[i+1];
612
if (bndptr[i] == -1) { /* This is an interior vertex */
613
auxadjncy = sadjncy + snedges - istart;
614
for(j=istart; j<iend; j++)
615
auxadjncy[j] = adjncy[j];
616
snedges += iend-istart;
617
}
618
else {
619
l = snedges;
620
for (j=istart; j<iend; j++) {
621
k = adjncy[j];
622
if (where[k] != 2)
623
sadjncy[l++] = k;
624
}
625
snedges = l;
626
}
627
628
svwgt[snvtxs] = vwgt[i];
629
slabel[snvtxs] = label[i];
630
sxadj[++snvtxs] = snedges;
631
}
632
633
iset(snedges, 1, sadjwgt);
634
for (i=0; i<snedges; i++)
635
sadjncy[i] = rename[sadjncy[i]];
636
637
sgraphs[iii]->nvtxs = snvtxs;
638
sgraphs[iii]->nedges = snedges;
639
640
SetupGraph_tvwgt(sgraphs[iii]);
641
}
642
643
IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->SplitTmr));
644
645
WCOREPOP;
646
647
return sgraphs;
648
}
649
650
651
/*************************************************************************/
652
/*! This function uses MMD to order the graph. The vertices are numbered
653
from lastvtx downwards. */
654
/*************************************************************************/
655
void MMDOrder(ctrl_t *ctrl, graph_t *graph, idx_t *order, idx_t lastvtx)
656
{
657
idx_t i, j, k, nvtxs, nofsub, firstvtx;
658
idx_t *xadj, *adjncy, *label;
659
idx_t *perm, *iperm, *head, *qsize, *list, *marker;
660
661
WCOREPUSH;
662
663
nvtxs = graph->nvtxs;
664
xadj = graph->xadj;
665
adjncy = graph->adjncy;
666
667
/* Relabel the vertices so that it starts from 1 */
668
k = xadj[nvtxs];
669
for (i=0; i<k; i++)
670
adjncy[i]++;
671
for (i=0; i<nvtxs+1; i++)
672
xadj[i]++;
673
674
perm = iwspacemalloc(ctrl, nvtxs+5);
675
iperm = iwspacemalloc(ctrl, nvtxs+5);
676
head = iwspacemalloc(ctrl, nvtxs+5);
677
qsize = iwspacemalloc(ctrl, nvtxs+5);
678
list = iwspacemalloc(ctrl, nvtxs+5);
679
marker = iwspacemalloc(ctrl, nvtxs+5);
680
681
genmmd(nvtxs, xadj, adjncy, iperm, perm, 1, head, qsize, list, marker, IDX_MAX, &nofsub);
682
683
label = graph->label;
684
firstvtx = lastvtx-nvtxs;
685
for (i=0; i<nvtxs; i++)
686
order[label[i]] = firstvtx+iperm[i]-1;
687
688
/* Relabel the vertices so that it starts from 0 */
689
for (i=0; i<nvtxs+1; i++)
690
xadj[i]--;
691
k = xadj[nvtxs];
692
for (i=0; i<k; i++)
693
adjncy[i]--;
694
695
WCOREPOP;
696
}
697
698
699
700
701
702
703