Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/metis-5.1.0/GKlib/graph.c
3206 views
1
/*!
2
* \file
3
*
4
* \brief Various routines with dealing with sparse graphs
5
*
6
* \author George Karypis
7
* \version\verbatim $Id: graph.c 13328 2012-12-31 14:57:40Z karypis $ \endverbatim
8
*/
9
10
#include <GKlib.h>
11
12
#define OMPMINOPS 50000
13
14
/*************************************************************************/
15
/*! Allocate memory for a graph and initializes it
16
\returns the allocated graph. The various fields are set to NULL.
17
*/
18
/**************************************************************************/
19
gk_graph_t *gk_graph_Create()
20
{
21
gk_graph_t *graph;
22
23
graph = (gk_graph_t *)gk_malloc(sizeof(gk_graph_t), "gk_graph_Create: graph");
24
25
gk_graph_Init(graph);
26
27
return graph;
28
}
29
30
31
/*************************************************************************/
32
/*! Initializes the graph.
33
\param graph is the graph to be initialized.
34
*/
35
/*************************************************************************/
36
void gk_graph_Init(gk_graph_t *graph)
37
{
38
memset(graph, 0, sizeof(gk_graph_t));
39
graph->nvtxs = -1;
40
}
41
42
43
/*************************************************************************/
44
/*! Frees all the memory allocated for a graph.
45
\param graph is the graph to be freed.
46
*/
47
/*************************************************************************/
48
void gk_graph_Free(gk_graph_t **graph)
49
{
50
if (*graph == NULL)
51
return;
52
gk_graph_FreeContents(*graph);
53
gk_free((void **)graph, LTERM);
54
}
55
56
57
/*************************************************************************/
58
/*! Frees only the memory allocated for the graph's different fields and
59
sets them to NULL.
60
\param graph is the graph whose contents will be freed.
61
*/
62
/*************************************************************************/
63
void gk_graph_FreeContents(gk_graph_t *graph)
64
{
65
gk_free((void *)&graph->xadj, &graph->adjncy,
66
&graph->iadjwgt, &graph->fadjwgt,
67
&graph->ivwgts, &graph->fvwgts,
68
&graph->ivsizes, &graph->fvsizes,
69
&graph->vlabels,
70
LTERM);
71
}
72
73
74
/**************************************************************************/
75
/*! Reads a sparse graph from the supplied file
76
\param filename is the file that stores the data.
77
\param format is the graph format. The supported values are:
78
GK_GRAPH_FMT_METIS.
79
\param isfewgts is 1 if the edge-weights should be read as floats
80
\param isfvwgts is 1 if the vertex-weights should be read as floats
81
\param isfvsizes is 1 if the vertex-sizes should be read as floats
82
\returns the graph that was read.
83
*/
84
/**************************************************************************/
85
gk_graph_t *gk_graph_Read(char *filename, int format, int isfewgts,
86
int isfvwgts, int isfvsizes)
87
{
88
ssize_t i, k, l;
89
size_t nfields, nvtxs, nedges, fmt, ncon, lnlen;
90
int32_t ival;
91
float fval;
92
int readsizes=0, readwgts=0, readvals=0, numbering=0;
93
char *line=NULL, *head, *tail, fmtstr[256];
94
FILE *fpin=NULL;
95
gk_graph_t *graph=NULL;
96
97
98
if (!gk_fexists(filename))
99
gk_errexit(SIGERR, "File %s does not exist!\n", filename);
100
101
if (format == GK_GRAPH_FMT_METIS) {
102
fpin = gk_fopen(filename, "r", "gk_graph_Read: fpin");
103
do {
104
if (gk_getline(&line, &lnlen, fpin) <= 0)
105
gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename);
106
} while (line[0] == '%');
107
108
fmt = ncon = 0;
109
nfields = sscanf(line, "%zu %zu %zu %zu", &nvtxs, &nedges, &fmt, &ncon);
110
if (nfields < 2)
111
gk_errexit(SIGERR, "Header line must contain at least 2 integers (#vtxs and #edges).\n");
112
113
nedges *= 2;
114
115
if (fmt > 111)
116
gk_errexit(SIGERR, "Cannot read this type of file format [fmt=%zu]!\n", fmt);
117
118
sprintf(fmtstr, "%03zu", fmt%1000);
119
readsizes = (fmtstr[0] == '1');
120
readwgts = (fmtstr[1] == '1');
121
readvals = (fmtstr[2] == '1');
122
numbering = 1;
123
ncon = (ncon == 0 ? 1 : ncon);
124
}
125
else {
126
gk_errexit(SIGERR, "Unrecognized format: %d\n", format);
127
}
128
129
graph = gk_graph_Create();
130
131
graph->nvtxs = nvtxs;
132
133
graph->xadj = gk_zmalloc(nvtxs+1, "gk_graph_Read: xadj");
134
graph->adjncy = gk_i32malloc(nedges, "gk_graph_Read: adjncy");
135
if (readvals) {
136
if (isfewgts)
137
graph->fadjwgt = gk_fmalloc(nedges, "gk_graph_Read: fadjwgt");
138
else
139
graph->iadjwgt = gk_i32malloc(nedges, "gk_graph_Read: iadjwgt");
140
}
141
142
if (readsizes) {
143
if (isfvsizes)
144
graph->fvsizes = gk_fmalloc(nvtxs, "gk_graph_Read: fvsizes");
145
else
146
graph->ivsizes = gk_i32malloc(nvtxs, "gk_graph_Read: ivsizes");
147
}
148
149
if (readwgts) {
150
if (isfvwgts)
151
graph->fvwgts = gk_fmalloc(nvtxs*ncon, "gk_graph_Read: fvwgts");
152
else
153
graph->ivwgts = gk_i32malloc(nvtxs*ncon, "gk_graph_Read: ivwgts");
154
}
155
156
157
/*----------------------------------------------------------------------
158
* Read the sparse graph file
159
*---------------------------------------------------------------------*/
160
numbering = (numbering ? - 1 : 0);
161
for (graph->xadj[0]=0, k=0, i=0; i<nvtxs; i++) {
162
do {
163
if (gk_getline(&line, &lnlen, fpin) == -1)
164
gk_errexit(SIGERR, "Pregraphure end of input file: file while reading row %d\n", i);
165
} while (line[0] == '%');
166
167
head = line;
168
tail = NULL;
169
170
/* Read vertex sizes */
171
if (readsizes) {
172
if (isfvsizes) {
173
#ifdef __MSC__
174
graph->fvsizes[i] = (float)strtod(head, &tail);
175
#else
176
graph->fvsizes[i] = strtof(head, &tail);
177
#endif
178
if (tail == head)
179
gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1);
180
if (graph->fvsizes[i] < 0)
181
gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1);
182
}
183
else {
184
graph->ivsizes[i] = strtol(head, &tail, 0);
185
if (tail == head)
186
gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1);
187
if (graph->ivsizes[i] < 0)
188
gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1);
189
}
190
head = tail;
191
}
192
193
/* Read vertex weights */
194
if (readwgts) {
195
for (l=0; l<ncon; l++) {
196
if (isfvwgts) {
197
#ifdef __MSC__
198
graph->fvwgts[i*ncon+l] = (float)strtod(head, &tail);
199
#else
200
graph->fvwgts[i*ncon+l] = strtof(head, &tail);
201
#endif
202
if (tail == head)
203
gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights "
204
"for the %d constraints.\n", i+1, ncon);
205
if (graph->fvwgts[i*ncon+l] < 0)
206
gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l);
207
}
208
else {
209
graph->ivwgts[i*ncon+l] = strtol(head, &tail, 0);
210
if (tail == head)
211
gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights "
212
"for the %d constraints.\n", i+1, ncon);
213
if (graph->ivwgts[i*ncon+l] < 0)
214
gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l);
215
}
216
head = tail;
217
}
218
}
219
220
221
/* Read the rest of the row */
222
while (1) {
223
ival = (int)strtol(head, &tail, 0);
224
if (tail == head)
225
break;
226
head = tail;
227
228
if ((graph->adjncy[k] = ival + numbering) < 0)
229
gk_errexit(SIGERR, "Error: Invalid column number %d at row %zd.\n", ival, i);
230
231
if (readvals) {
232
if (isfewgts) {
233
#ifdef __MSC__
234
fval = (float)strtod(head, &tail);
235
#else
236
fval = strtof(head, &tail);
237
#endif
238
if (tail == head)
239
gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k);
240
241
graph->fadjwgt[k] = fval;
242
}
243
else {
244
ival = strtol(head, &tail, 0);
245
if (tail == head)
246
gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k);
247
248
graph->iadjwgt[k] = ival;
249
}
250
head = tail;
251
}
252
k++;
253
}
254
graph->xadj[i+1] = k;
255
}
256
257
if (k != nedges)
258
gk_errexit(SIGERR, "gk_graph_Read: Something wrong with the number of edges in "
259
"the input file. nedges=%zd, Actualnedges=%zd.\n", nedges, k);
260
261
gk_fclose(fpin);
262
263
gk_free((void **)&line, LTERM);
264
265
return graph;
266
}
267
268
269
/**************************************************************************/
270
/*! Writes a graph into a file.
271
\param graph is the graph to be written,
272
\param filename is the name of the output file.
273
\param format is one of GK_GRAPH_FMT_METIS specifying
274
the format of the output file.
275
*/
276
/**************************************************************************/
277
void gk_graph_Write(gk_graph_t *graph, char *filename, int format)
278
{
279
ssize_t i, j;
280
int hasvwgts, hasvsizes, hasewgts;
281
FILE *fpout;
282
283
if (format != GK_GRAPH_FMT_METIS)
284
gk_errexit(SIGERR, "Unknown file format. %d\n", format);
285
286
if (filename)
287
fpout = gk_fopen(filename, "w", "gk_graph_Write: fpout");
288
else
289
fpout = stdout;
290
291
292
hasewgts = (graph->iadjwgt || graph->fadjwgt);
293
hasvwgts = (graph->ivwgts || graph->fvwgts);
294
hasvsizes = (graph->ivsizes || graph->fvsizes);
295
296
/* write the header line */
297
fprintf(fpout, "%d %zd", graph->nvtxs, graph->xadj[graph->nvtxs]/2);
298
if (hasvwgts || hasvsizes || hasewgts)
299
fprintf(fpout, " %d%d%d", hasvsizes, hasvwgts, hasewgts);
300
fprintf(fpout, "\n");
301
302
303
for (i=0; i<graph->nvtxs; i++) {
304
if (hasvsizes) {
305
if (graph->ivsizes)
306
fprintf(fpout, " %d", graph->ivsizes[i]);
307
else
308
fprintf(fpout, " %f", graph->fvsizes[i]);
309
}
310
311
if (hasvwgts) {
312
if (graph->ivwgts)
313
fprintf(fpout, " %d", graph->ivwgts[i]);
314
else
315
fprintf(fpout, " %f", graph->fvwgts[i]);
316
}
317
318
for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) {
319
fprintf(fpout, " %d", graph->adjncy[j]+1);
320
if (hasewgts) {
321
if (graph->iadjwgt)
322
fprintf(fpout, " %d", graph->iadjwgt[j]);
323
else
324
fprintf(fpout, " %f", graph->fadjwgt[j]);
325
}
326
}
327
fprintf(fpout, "\n");
328
}
329
if (filename)
330
gk_fclose(fpout);
331
}
332
333
334
/*************************************************************************/
335
/*! Returns a copy of a graph.
336
\param graph is the graph to be duplicated.
337
\returns the newly created copy of the graph.
338
*/
339
/**************************************************************************/
340
gk_graph_t *gk_graph_Dup(gk_graph_t *graph)
341
{
342
gk_graph_t *ngraph;
343
344
ngraph = gk_graph_Create();
345
346
ngraph->nvtxs = graph->nvtxs;
347
348
/* copy the adjacency structure */
349
if (graph->xadj)
350
ngraph->xadj = gk_zcopy(graph->nvtxs+1, graph->xadj,
351
gk_zmalloc(graph->nvtxs+1, "gk_graph_Dup: xadj"));
352
if (graph->ivwgts)
353
ngraph->ivwgts = gk_i32copy(graph->nvtxs, graph->ivwgts,
354
gk_i32malloc(graph->nvtxs, "gk_graph_Dup: ivwgts"));
355
if (graph->ivsizes)
356
ngraph->ivsizes = gk_i32copy(graph->nvtxs, graph->ivsizes,
357
gk_i32malloc(graph->nvtxs, "gk_graph_Dup: ivsizes"));
358
if (graph->vlabels)
359
ngraph->vlabels = gk_i32copy(graph->nvtxs, graph->vlabels,
360
gk_i32malloc(graph->nvtxs, "gk_graph_Dup: ivlabels"));
361
if (graph->fvwgts)
362
ngraph->fvwgts = gk_fcopy(graph->nvtxs, graph->fvwgts,
363
gk_fmalloc(graph->nvtxs, "gk_graph_Dup: fvwgts"));
364
if (graph->fvsizes)
365
ngraph->fvsizes = gk_fcopy(graph->nvtxs, graph->fvsizes,
366
gk_fmalloc(graph->nvtxs, "gk_graph_Dup: fvsizes"));
367
368
369
if (graph->adjncy)
370
ngraph->adjncy = gk_i32copy(graph->xadj[graph->nvtxs], graph->adjncy,
371
gk_i32malloc(graph->xadj[graph->nvtxs], "gk_graph_Dup: adjncy"));
372
if (graph->iadjwgt)
373
ngraph->iadjwgt = gk_i32copy(graph->xadj[graph->nvtxs], graph->iadjwgt,
374
gk_i32malloc(graph->xadj[graph->nvtxs], "gk_graph_Dup: iadjwgt"));
375
if (graph->fadjwgt)
376
ngraph->fadjwgt = gk_fcopy(graph->xadj[graph->nvtxs], graph->fadjwgt,
377
gk_fmalloc(graph->xadj[graph->nvtxs], "gk_graph_Dup: fadjwgt"));
378
379
return ngraph;
380
}
381
382
383
/*************************************************************************/
384
/*! Returns a subgraph containing a set of consecutive vertices.
385
\param graph is the original graph.
386
\param vstart is the starting vertex.
387
\param nvtxs is the number of vertices from vstart to extract.
388
\returns the newly created subgraph.
389
*/
390
/**************************************************************************/
391
gk_graph_t *gk_graph_ExtractSubgraph(gk_graph_t *graph, int vstart, int nvtxs)
392
{
393
ssize_t i;
394
gk_graph_t *ngraph;
395
396
if (vstart+nvtxs > graph->nvtxs)
397
return NULL;
398
399
ngraph = gk_graph_Create();
400
401
ngraph->nvtxs = nvtxs;
402
403
/* copy the adjancy structure */
404
if (graph->xadj)
405
ngraph->xadj = gk_zcopy(nvtxs+1, graph->xadj+vstart,
406
gk_zmalloc(nvtxs+1, "gk_graph_ExtractSubgraph: xadj"));
407
for (i=nvtxs; i>=0; i--)
408
ngraph->xadj[i] -= ngraph->xadj[0];
409
ASSERT(ngraph->xadj[0] == 0);
410
411
if (graph->ivwgts)
412
ngraph->ivwgts = gk_i32copy(nvtxs, graph->ivwgts+vstart,
413
gk_i32malloc(nvtxs, "gk_graph_ExtractSubgraph: ivwgts"));
414
if (graph->ivsizes)
415
ngraph->ivsizes = gk_i32copy(nvtxs, graph->ivsizes+vstart,
416
gk_i32malloc(nvtxs, "gk_graph_ExtractSubgraph: ivsizes"));
417
if (graph->vlabels)
418
ngraph->vlabels = gk_i32copy(nvtxs, graph->vlabels+vstart,
419
gk_i32malloc(nvtxs, "gk_graph_ExtractSubgraph: vlabels"));
420
421
if (graph->fvwgts)
422
ngraph->fvwgts = gk_fcopy(nvtxs, graph->fvwgts+vstart,
423
gk_fmalloc(nvtxs, "gk_graph_ExtractSubgraph: fvwgts"));
424
if (graph->fvsizes)
425
ngraph->fvsizes = gk_fcopy(nvtxs, graph->fvsizes+vstart,
426
gk_fmalloc(nvtxs, "gk_graph_ExtractSubgraph: fvsizes"));
427
428
429
ASSERT(ngraph->xadj[nvtxs] == graph->xadj[vstart+nvtxs]-graph->xadj[vstart]);
430
if (graph->adjncy)
431
ngraph->adjncy = gk_i32copy(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],
432
graph->adjncy+graph->xadj[vstart],
433
gk_i32malloc(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],
434
"gk_graph_ExtractSubgraph: adjncy"));
435
if (graph->iadjwgt)
436
ngraph->iadjwgt = gk_i32copy(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],
437
graph->iadjwgt+graph->xadj[vstart],
438
gk_i32malloc(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],
439
"gk_graph_ExtractSubgraph: iadjwgt"));
440
if (graph->fadjwgt)
441
ngraph->fadjwgt = gk_fcopy(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],
442
graph->fadjwgt+graph->xadj[vstart],
443
gk_fmalloc(graph->xadj[vstart+nvtxs]-graph->xadj[vstart],
444
"gk_graph_ExtractSubgraph: fadjwgt"));
445
446
return ngraph;
447
}
448
449
450
/*************************************************************************/
451
/*! Returns a graph that has been reordered according to the permutation.
452
\param[IN] graph is the graph to be re-ordered.
453
\param[IN] perm is the new ordering of the graph's vertices
454
\param[IN] iperm is the original ordering of the re-ordered graph's vertices
455
\returns the newly created copy of the graph.
456
457
\note Either perm or iperm can be NULL but not both.
458
*/
459
/**************************************************************************/
460
gk_graph_t *gk_graph_Reorder(gk_graph_t *graph, int32_t *perm, int32_t *iperm)
461
{
462
ssize_t j, jj, *xadj;
463
int i, k, u, v, nvtxs;
464
int freeperm=0, freeiperm=0;
465
int32_t *adjncy;
466
gk_graph_t *ngraph;
467
468
if (perm == NULL && iperm == NULL)
469
return NULL;
470
471
ngraph = gk_graph_Create();
472
473
ngraph->nvtxs = nvtxs = graph->nvtxs;
474
xadj = graph->xadj;
475
adjncy = graph->adjncy;
476
477
/* allocate memory for the different structures that are present in graph */
478
if (graph->xadj)
479
ngraph->xadj = gk_zmalloc(nvtxs+1, "gk_graph_Reorder: xadj");
480
481
if (graph->ivwgts)
482
ngraph->ivwgts = gk_i32malloc(nvtxs, "gk_graph_Reorder: ivwgts");
483
484
if (graph->ivsizes)
485
ngraph->ivsizes = gk_i32malloc(nvtxs, "gk_graph_Reorder: ivsizes");
486
487
if (graph->vlabels)
488
ngraph->vlabels = gk_i32malloc(nvtxs, "gk_graph_Reorder: ivlabels");
489
490
if (graph->fvwgts)
491
ngraph->fvwgts = gk_fmalloc(nvtxs, "gk_graph_Reorder: fvwgts");
492
493
if (graph->fvsizes)
494
ngraph->fvsizes = gk_fmalloc(nvtxs, "gk_graph_Reorder: fvsizes");
495
496
497
if (graph->adjncy)
498
ngraph->adjncy = gk_i32malloc(graph->xadj[nvtxs], "gk_graph_Reorder: adjncy");
499
500
if (graph->iadjwgt)
501
ngraph->iadjwgt = gk_i32malloc(graph->xadj[nvtxs], "gk_graph_Reorder: iadjwgt");
502
503
if (graph->fadjwgt)
504
ngraph->fadjwgt = gk_fmalloc(graph->xadj[nvtxs], "gk_graph_Reorder: fadjwgt");
505
506
507
/* create perm/iperm if not provided */
508
if (perm == NULL) {
509
freeperm = 1;
510
perm = gk_i32malloc(nvtxs, "gk_graph_Reorder: perm");
511
for (i=0; i<nvtxs; i++)
512
perm[iperm[i]] = i;
513
}
514
if (iperm == NULL) {
515
freeiperm = 1;
516
iperm = gk_i32malloc(nvtxs, "gk_graph_Reorder: iperm");
517
for (i=0; i<nvtxs; i++)
518
iperm[perm[i]] = i;
519
}
520
521
/* fill-in the information of the re-ordered graph */
522
ngraph->xadj[0] = jj = 0;
523
for (v=0; v<nvtxs; v++) {
524
u = iperm[v];
525
for (j=xadj[u]; j<xadj[u+1]; j++, jj++) {
526
ngraph->adjncy[jj] = perm[adjncy[j]];
527
if (graph->iadjwgt)
528
ngraph->iadjwgt[jj] = graph->iadjwgt[j];
529
if (graph->fadjwgt)
530
ngraph->fadjwgt[jj] = graph->fadjwgt[j];
531
}
532
if (graph->ivwgts)
533
ngraph->ivwgts[v] = graph->ivwgts[u];
534
if (graph->fvwgts)
535
ngraph->fvwgts[v] = graph->fvwgts[u];
536
if (graph->ivsizes)
537
ngraph->ivsizes[v] = graph->ivsizes[u];
538
if (graph->fvsizes)
539
ngraph->fvsizes[v] = graph->fvsizes[u];
540
if (graph->vlabels)
541
ngraph->vlabels[v] = graph->vlabels[u];
542
543
ngraph->xadj[v+1] = jj;
544
}
545
546
547
/* free memory */
548
if (freeperm)
549
gk_free((void **)&perm, LTERM);
550
if (freeiperm)
551
gk_free((void **)&iperm, LTERM);
552
553
return ngraph;
554
}
555
556
557
/*************************************************************************/
558
/*! This function finds the connected components in a graph.
559
560
\param graph is the graph structure
561
\param cptr is the ptr structure of the CSR representation of the
562
components. The length of this vector must be graph->nvtxs+1.
563
\param cind is the indices structure of the CSR representation of
564
the components. The length of this vector must be graph->nvtxs.
565
566
\returns the number of components that it found.
567
568
\note The cptr and cind parameters can be NULL, in which case only the
569
number of connected components is returned.
570
*/
571
/*************************************************************************/
572
int gk_graph_FindComponents(gk_graph_t *graph, int32_t *cptr, int32_t *cind)
573
{
574
ssize_t i, ii, j, jj, k, nvtxs, first, last, ntodo, ncmps;
575
ssize_t *xadj;
576
int32_t *adjncy, *pos, *todo;
577
int32_t mustfree_ccsr=0, mustfree_where=0;
578
579
nvtxs = graph->nvtxs;
580
xadj = graph->xadj;
581
adjncy = graph->adjncy;
582
583
/* Deal with NULL supplied cptr/cind vectors */
584
if (cptr == NULL) {
585
cptr = gk_i32malloc(nvtxs+1, "gk_graph_FindComponents: cptr");
586
cind = gk_i32malloc(nvtxs, "gk_graph_FindComponents: cind");
587
mustfree_ccsr = 1;
588
}
589
590
/* The list of vertices that have not been touched yet.
591
The valid entries are from [0..ntodo). */
592
todo = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: todo"));
593
594
/* For a vertex that has not been visited, pos[i] is the position in the
595
todo list that this vertex is stored.
596
If a vertex has been visited, pos[i] = -1. */
597
pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: pos"));
598
599
600
/* Find the connected componends */
601
ncmps = -1;
602
ntodo = nvtxs; /* All vertices have not been visited */
603
first = last = 0; /* Point to the first and last vertices that have been touched
604
but not explored.
605
These vertices are stored in cind[first]...cind[last-1]. */
606
while (ntodo > 0) {
607
if (first == last) { /* Find another starting vertex */
608
cptr[++ncmps] = first; /* Mark the end of the current CC */
609
610
ASSERT(pos[todo[0]] != -1);
611
i = todo[0];
612
613
cind[last++] = i;
614
pos[i] = -1;
615
}
616
617
i = cind[first++]; /* Get the first visited but unexplored vertex */
618
619
/* Remove i from the todo list and put the last item in the todo
620
list at the position that i was so that the todo list will be
621
consequtive. The pos[] array is updated accordingly to keep track
622
the location of the vertices in the todo[] list. */
623
k = pos[i];
624
j = todo[k] = todo[--ntodo];
625
pos[j] = k;
626
627
for (j=xadj[i]; j<xadj[i+1]; j++) {
628
k = adjncy[j];
629
if (pos[k] != -1) {
630
cind[last++] = k;
631
pos[k] = -1;
632
}
633
}
634
}
635
cptr[++ncmps] = first;
636
637
if (mustfree_ccsr)
638
gk_free((void **)&cptr, &cind, LTERM);
639
640
gk_free((void **)&pos, &todo, LTERM);
641
642
return (int) ncmps;
643
}
644
645
646
/*************************************************************************/
647
/*! This function computes a permutation of the vertices based on a
648
breadth-first-traversal. It can be used for re-ordering the graph
649
to reduce its bandwidth for better cache locality.
650
The algorithm used is a simplified version of the method used to find
651
the connected components.
652
653
\param[IN] graph is the graph structure
654
\param[IN] v is the starting vertex of the BFS
655
\param[OUT] perm[i] stores the ID of vertex i in the re-ordered graph.
656
\param[OUT] iperm[i] stores the ID of the vertex that corresponds to
657
the ith vertex in the re-ordered graph.
658
659
\note The perm or iperm (but not both) can be NULL, at which point,
660
the corresponding arrays are not returned. Though the program
661
works fine when both are NULL, doing that is not smart.
662
The returned arrays should be freed with gk_free().
663
*/
664
/*************************************************************************/
665
void gk_graph_ComputeBFSOrdering(gk_graph_t *graph, int v, int32_t **r_perm,
666
int32_t **r_iperm)
667
{
668
ssize_t j, *xadj;
669
int i, k, nvtxs, first, last;
670
int32_t *adjncy, *cot, *pos;
671
672
if (graph->nvtxs <= 0)
673
return;
674
675
nvtxs = graph->nvtxs;
676
xadj = graph->xadj;
677
adjncy = graph->adjncy;
678
679
/* This array will function like pos + touched of the CC method */
680
pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_ComputeBFSOrdering: pos"));
681
682
/* This array ([C]losed[O]pen[T]odo => cot) serves three purposes.
683
Positions from [0...first) is the current iperm[] vector of the explored vertices;
684
Positions from [first...last) is the OPEN list (i.e., visited vertices);
685
Positions from [last...nvtxs) is the todo list. */
686
cot = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_ComputeBFSOrdering: cot"));
687
688
689
/* put v at the front of the todo list */
690
pos[0] = cot[0] = v;
691
pos[v] = cot[v] = 0;
692
693
/* Find the connected componends induced by the partition */
694
first = last = 0;
695
while (first < nvtxs) {
696
if (first == last) { /* Find another starting vertex */
697
k = cot[last];
698
ASSERT(pos[k] != -1);
699
pos[k] = -1; /* mark node as being visited */
700
last++;
701
}
702
703
i = cot[first++]; /* the ++ advances the explored vertices */
704
for (j=xadj[i]; j<xadj[i+1]; j++) {
705
k = adjncy[j];
706
/* if a node has already been visited, its perm[] will be -1 */
707
if (pos[k] != -1) {
708
/* pos[k] is the location within iperm of where k resides (it is in the 'todo' part);
709
It is placed in that location cot[last] (end of OPEN list) that we
710
are about to overwrite and update pos[cot[last]] to reflect that. */
711
cot[pos[k]] = cot[last]; /* put the head of the todo list to
712
where k was in the todo list */
713
pos[cot[last]] = pos[k]; /* update perm to reflect the move */
714
715
cot[last++] = k; /* put node at the end of the OPEN list */
716
pos[k] = -1; /* mark node as being visited */
717
}
718
}
719
}
720
721
/* time to decide what to return */
722
if (r_perm != NULL) {
723
/* use the 'pos' array to build the perm array */
724
for (i=0; i<nvtxs; i++)
725
pos[cot[i]] = i;
726
727
*r_perm = pos;
728
pos = NULL;
729
}
730
731
if (r_iperm != NULL) {
732
*r_iperm = cot;
733
cot = NULL;
734
}
735
736
737
/* cleanup memory */
738
gk_free((void **)&pos, &cot, LTERM);
739
740
}
741
742
743
/*************************************************************************/
744
/*! This function computes a permutation of the vertices based on a
745
best-first-traversal. It can be used for re-ordering the graph
746
to reduce its bandwidth for better cache locality.
747
748
\param[IN] graph is the graph structure.
749
\param[IN] v is the starting vertex of the best-first traversal.
750
\param[IN] type indicates the criteria to use to measure the 'bestness'
751
of a vertex.
752
\param[OUT] perm[i] stores the ID of vertex i in the re-ordered graph.
753
\param[OUT] iperm[i] stores the ID of the vertex that corresponds to
754
the ith vertex in the re-ordered graph.
755
756
\note The perm or iperm (but not both) can be NULL, at which point,
757
the corresponding arrays are not returned. Though the program
758
works fine when both are NULL, doing that is not smart.
759
The returned arrays should be freed with gk_free().
760
*/
761
/*************************************************************************/
762
void gk_graph_ComputeBestFOrdering0(gk_graph_t *graph, int v, int type,
763
int32_t **r_perm, int32_t **r_iperm)
764
{
765
ssize_t j, jj, *xadj;
766
int i, k, u, nvtxs;
767
int32_t *adjncy, *perm, *degrees, *minIDs, *open;
768
gk_i32pq_t *queue;
769
770
if (graph->nvtxs <= 0)
771
return;
772
773
nvtxs = graph->nvtxs;
774
xadj = graph->xadj;
775
adjncy = graph->adjncy;
776
777
/* the degree of the vertices in the closed list */
778
degrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: degrees");
779
780
/* the minimum vertex ID of an open vertex to the closed list */
781
minIDs = gk_i32smalloc(nvtxs, nvtxs+1, "gk_graph_ComputeBestFOrdering: minIDs");
782
783
/* the open list */
784
open = gk_i32malloc(nvtxs, "gk_graph_ComputeBestFOrdering: open");
785
786
/* if perm[i] >= 0, then perm[i] is the order of vertex i;
787
otherwise perm[i] == -1.
788
*/
789
perm = gk_i32smalloc(nvtxs, -1, "gk_graph_ComputeBestFOrdering: perm");
790
791
/* create the queue and put everything in it */
792
queue = gk_i32pqCreate(nvtxs);
793
for (i=0; i<nvtxs; i++)
794
gk_i32pqInsert(queue, i, 0);
795
gk_i32pqUpdate(queue, v, 1);
796
797
open[0] = v;
798
799
/* start processing the nodes */
800
for (i=0; i<nvtxs; i++) {
801
if ((v = gk_i32pqGetTop(queue)) == -1)
802
gk_errexit(SIGERR, "The priority queue got empty ahead of time [i=%d].\n", i);
803
if (perm[v] != -1)
804
gk_errexit(SIGERR, "The perm[%d] has already been set.\n", v);
805
perm[v] = i;
806
807
808
for (j=xadj[v]; j<xadj[v+1]; j++) {
809
u = adjncy[j];
810
if (perm[u] == -1) {
811
degrees[u]++;
812
minIDs[u] = (i < minIDs[u] ? i : minIDs[u]);
813
814
switch (type) {
815
case 1: /* DFS */
816
gk_i32pqUpdate(queue, u, 1);
817
break;
818
case 2: /* Max in closed degree */
819
gk_i32pqUpdate(queue, u, degrees[u]);
820
break;
821
case 3: /* Sum of orders in closed list */
822
for (k=0, jj=xadj[u]; jj<xadj[u+1]; jj++) {
823
if (perm[adjncy[jj]] != -1)
824
k += perm[adjncy[jj]];
825
}
826
gk_i32pqUpdate(queue, u, k);
827
break;
828
case 4: /* Sum of order-differences (w.r.t. current number) in closed
829
list (updated once in a while) */
830
for (k=0, jj=xadj[u]; jj<xadj[u+1]; jj++) {
831
if (perm[adjncy[jj]] != -1)
832
k += (i-perm[adjncy[jj]]);
833
}
834
gk_i32pqUpdate(queue, u, k);
835
break;
836
default:
837
;
838
}
839
}
840
}
841
}
842
843
844
/* time to decide what to return */
845
if (r_perm != NULL) {
846
*r_perm = perm;
847
perm = NULL;
848
}
849
850
if (r_iperm != NULL) {
851
/* use the 'degrees' array to build the iperm array */
852
for (i=0; i<nvtxs; i++)
853
degrees[perm[i]] = i;
854
855
*r_iperm = degrees;
856
degrees = NULL;
857
}
858
859
860
861
/* cleanup memory */
862
gk_i32pqDestroy(queue);
863
gk_free((void **)&perm, &degrees, &minIDs, &open, LTERM);
864
865
}
866
867
868
/*************************************************************************/
869
/*! This function computes a permutation of the vertices based on a
870
best-first-traversal. It can be used for re-ordering the graph
871
to reduce its bandwidth for better cache locality.
872
873
\param[IN] graph is the graph structure.
874
\param[IN] v is the starting vertex of the best-first traversal.
875
\param[IN] type indicates the criteria to use to measure the 'bestness'
876
of a vertex.
877
\param[OUT] perm[i] stores the ID of vertex i in the re-ordered graph.
878
\param[OUT] iperm[i] stores the ID of the vertex that corresponds to
879
the ith vertex in the re-ordered graph.
880
881
\note The perm or iperm (but not both) can be NULL, at which point,
882
the corresponding arrays are not returned. Though the program
883
works fine when both are NULL, doing that is not smart.
884
The returned arrays should be freed with gk_free().
885
*/
886
/*************************************************************************/
887
void gk_graph_ComputeBestFOrdering(gk_graph_t *graph, int v, int type,
888
int32_t **r_perm, int32_t **r_iperm)
889
{
890
ssize_t j, jj, *xadj;
891
int i, k, u, nvtxs, nopen, ntodo;
892
int32_t *adjncy, *perm, *degrees, *wdegrees, *sod, *level, *ot, *pos;
893
gk_i32pq_t *queue;
894
895
if (graph->nvtxs <= 0)
896
return;
897
898
nvtxs = graph->nvtxs;
899
xadj = graph->xadj;
900
adjncy = graph->adjncy;
901
902
/* the degree of the vertices in the closed list */
903
degrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: degrees");
904
905
/* the weighted degree of the vertices in the closed list for type==3 */
906
wdegrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: wdegrees");
907
908
/* the sum of differences for type==4 */
909
sod = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: sod");
910
911
/* the encountering level of a vertex type==5 */
912
level = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: level");
913
914
/* The open+todo list of vertices.
915
The vertices from [0..nopen] are the open vertices.
916
The vertices from [nopen..ntodo) are the todo vertices.
917
*/
918
ot = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: ot"));
919
920
/* For a vertex that has not been explored, pos[i] is the position in the ot list. */
921
pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_graph_FindComponents: pos"));
922
923
/* if perm[i] >= 0, then perm[i] is the order of vertex i; otherwise perm[i] == -1. */
924
perm = gk_i32smalloc(nvtxs, -1, "gk_graph_ComputeBestFOrdering: perm");
925
926
/* create the queue and put the starting vertex in it */
927
queue = gk_i32pqCreate(nvtxs);
928
gk_i32pqInsert(queue, v, 1);
929
930
/* put v at the front of the open list */
931
pos[0] = ot[0] = v;
932
pos[v] = ot[v] = 0;
933
nopen = 1;
934
ntodo = nvtxs;
935
936
/* start processing the nodes */
937
for (i=0; i<nvtxs; i++) {
938
if (nopen == 0) { /* deal with non-connected graphs */
939
gk_i32pqInsert(queue, ot[0], 1);
940
nopen++;
941
}
942
943
if ((v = gk_i32pqGetTop(queue)) == -1)
944
gk_errexit(SIGERR, "The priority queue got empty ahead of time [i=%d].\n", i);
945
946
if (perm[v] != -1)
947
gk_errexit(SIGERR, "The perm[%d] has already been set.\n", v);
948
perm[v] = i;
949
950
if (ot[pos[v]] != v)
951
gk_errexit(SIGERR, "Something went wrong [ot[pos[%d]]!=%d.\n", v, v);
952
if (pos[v] >= nopen)
953
gk_errexit(SIGERR, "The position of v is not in open list. pos[%d]=%d is >=%d.\n", v, pos[v], nopen);
954
955
/* remove v from the open list and re-arrange the todo part of the list */
956
ot[pos[v]] = ot[nopen-1];
957
pos[ot[nopen-1]] = pos[v];
958
if (ntodo > nopen) {
959
ot[nopen-1] = ot[ntodo-1];
960
pos[ot[ntodo-1]] = nopen-1;
961
}
962
nopen--;
963
ntodo--;
964
965
for (j=xadj[v]; j<xadj[v+1]; j++) {
966
u = adjncy[j];
967
if (perm[u] == -1) {
968
/* update ot list, if u is not in the open list by putting it at the end
969
of the open list. */
970
if (degrees[u] == 0) {
971
ot[pos[u]] = ot[nopen];
972
pos[ot[nopen]] = pos[u];
973
ot[nopen] = u;
974
pos[u] = nopen;
975
nopen++;
976
977
level[u] = level[v]+1;
978
gk_i32pqInsert(queue, u, 0);
979
}
980
981
982
/* update the in-closed degree */
983
degrees[u]++;
984
985
/* update the queues based on the type */
986
switch (type) {
987
case 1: /* DFS */
988
gk_i32pqUpdate(queue, u, 1000*(i+1)+degrees[u]);
989
break;
990
991
case 2: /* Max in closed degree */
992
gk_i32pqUpdate(queue, u, degrees[u]);
993
break;
994
995
case 3: /* Sum of orders in closed list */
996
wdegrees[u] += i;
997
gk_i32pqUpdate(queue, u, wdegrees[u]);
998
break;
999
1000
case 4: /* Sum of order-differences */
1001
/* this is handled at the end of the loop */
1002
;
1003
break;
1004
1005
case 5: /* BFS with in degree priority */
1006
gk_i32pqUpdate(queue, u, -(1000*level[u] - degrees[u]));
1007
break;
1008
1009
case 6: /* Hybrid of 1+2 */
1010
gk_i32pqUpdate(queue, u, (i+1)*degrees[u]);
1011
break;
1012
1013
default:
1014
;
1015
}
1016
}
1017
}
1018
1019
if (type == 4) { /* update all the vertices in the open list */
1020
for (j=0; j<nopen; j++) {
1021
u = ot[j];
1022
if (perm[u] != -1)
1023
gk_errexit(SIGERR, "For i=%d, the open list contains a closed vertex: ot[%zd]=%d, perm[%d]=%d.\n", i, j, u, u, perm[u]);
1024
sod[u] += degrees[u];
1025
if (i<1000 || i%25==0)
1026
gk_i32pqUpdate(queue, u, sod[u]);
1027
}
1028
}
1029
1030
/*
1031
for (j=0; j<ntodo; j++) {
1032
if (pos[ot[j]] != j)
1033
gk_errexit(SIGERR, "pos[ot[%zd]] != %zd.\n", j, j);
1034
}
1035
*/
1036
1037
}
1038
1039
1040
/* time to decide what to return */
1041
if (r_perm != NULL) {
1042
*r_perm = perm;
1043
perm = NULL;
1044
}
1045
1046
if (r_iperm != NULL) {
1047
/* use the 'degrees' array to build the iperm array */
1048
for (i=0; i<nvtxs; i++)
1049
degrees[perm[i]] = i;
1050
1051
*r_iperm = degrees;
1052
degrees = NULL;
1053
}
1054
1055
1056
1057
/* cleanup memory */
1058
gk_i32pqDestroy(queue);
1059
gk_free((void **)&perm, &degrees, &wdegrees, &sod, &ot, &pos, &level, LTERM);
1060
1061
}
1062
1063
1064
/*************************************************************************/
1065
/*! This function computes the single-source shortest path lengths from the
1066
root node to all the other nodes in the graph. If the graph is not
1067
connected then, the sortest part to the vertices in the other components
1068
is -1.
1069
1070
\param[IN] graph is the graph structure.
1071
\param[IN] v is the root of the single-source shortest path computations.
1072
\param[IN] type indicates the criteria to use to measure the 'bestness'
1073
of a vertex.
1074
\param[OUT] sps[i] stores the length of the shortest path from v to vertex i.
1075
If no such path exists, then it is -1. Note that the returned
1076
array will be either an array of int32_t or an array of floats.
1077
The specific type is determined by the existance of non NULL
1078
iadjwgt and fadjwgt arrays. If both of these arrays exist, then
1079
priority is given to iadjwgt.
1080
1081
\note The returned array should be freed with gk_free().
1082
*/
1083
/*************************************************************************/
1084
void gk_graph_SingleSourceShortestPaths(gk_graph_t *graph, int v, void **r_sps)
1085
{
1086
ssize_t *xadj;
1087
int i, u, nvtxs;
1088
int32_t *adjncy, *inqueue;
1089
1090
if (graph->nvtxs <= 0)
1091
return;
1092
1093
nvtxs = graph->nvtxs;
1094
xadj = graph->xadj;
1095
adjncy = graph->adjncy;
1096
1097
inqueue = gk_i32smalloc(nvtxs, 0, "gk_graph_SingleSourceShortestPaths: inqueue");
1098
1099
/* determine if you will be computing using int32_t or float and proceed from there */
1100
if (graph->iadjwgt != NULL) {
1101
gk_i32pq_t *queue;
1102
int32_t *adjwgt;
1103
int32_t *sps;
1104
1105
adjwgt = graph->iadjwgt;
1106
1107
queue = gk_i32pqCreate(nvtxs);
1108
gk_i32pqInsert(queue, v, 0);
1109
inqueue[v] = 1;
1110
1111
sps = gk_i32smalloc(nvtxs, -1, "gk_graph_SingleSourceShortestPaths: sps");
1112
sps[v] = 0;
1113
1114
/* start processing the nodes */
1115
while ((v = gk_i32pqGetTop(queue)) != -1) {
1116
inqueue[v] = 2;
1117
1118
/* relax the adjacent edges */
1119
for (i=xadj[v]; i<xadj[v+1]; i++) {
1120
u = adjncy[i];
1121
if (inqueue[u] == 2)
1122
continue;
1123
1124
if (sps[u] < 0 || sps[v]+adjwgt[i] < sps[u]) {
1125
sps[u] = sps[v]+adjwgt[i];
1126
1127
if (inqueue[u])
1128
gk_i32pqUpdate(queue, u, -sps[u]);
1129
else {
1130
gk_i32pqInsert(queue, u, -sps[u]);
1131
inqueue[u] = 1;
1132
}
1133
}
1134
}
1135
}
1136
1137
*r_sps = (void *)sps;
1138
1139
gk_i32pqDestroy(queue);
1140
}
1141
else {
1142
gk_fpq_t *queue;
1143
float *adjwgt;
1144
float *sps;
1145
1146
adjwgt = graph->fadjwgt;
1147
1148
queue = gk_fpqCreate(nvtxs);
1149
gk_fpqInsert(queue, v, 0);
1150
inqueue[v] = 1;
1151
1152
sps = gk_fsmalloc(nvtxs, -1, "gk_graph_SingleSourceShortestPaths: sps");
1153
sps[v] = 0;
1154
1155
/* start processing the nodes */
1156
while ((v = gk_fpqGetTop(queue)) != -1) {
1157
inqueue[v] = 2;
1158
1159
/* relax the adjacent edges */
1160
for (i=xadj[v]; i<xadj[v+1]; i++) {
1161
u = adjncy[i];
1162
if (inqueue[u] == 2)
1163
continue;
1164
1165
if (sps[u] < 0 || sps[v]+adjwgt[i] < sps[u]) {
1166
sps[u] = sps[v]+adjwgt[i];
1167
1168
if (inqueue[u])
1169
gk_fpqUpdate(queue, u, -sps[u]);
1170
else {
1171
gk_fpqInsert(queue, u, -sps[u]);
1172
inqueue[u] = 1;
1173
}
1174
}
1175
}
1176
}
1177
1178
*r_sps = (void *)sps;
1179
1180
gk_fpqDestroy(queue);
1181
}
1182
1183
gk_free((void **)&inqueue, LTERM);
1184
1185
}
1186
1187
1188
1189
#ifdef XXX
1190
1191
/*************************************************************************/
1192
/*! Sorts the adjacency lists in increasing vertex order
1193
\param graph the graph itself,
1194
*/
1195
/**************************************************************************/
1196
void gk_graph_SortAdjacencies(gk_graph_t *graph)
1197
{
1198
int n, nn=0;
1199
ssize_t *ptr;
1200
int *ind;
1201
float *val;
1202
1203
switch (what) {
1204
case GK_CSR_ROW:
1205
if (!graph->rowptr)
1206
gk_errexit(SIGERR, "Row-based view of the graphrix does not exists.\n");
1207
1208
n = graph->nrows;
1209
ptr = graph->rowptr;
1210
ind = graph->rowind;
1211
val = graph->rowval;
1212
break;
1213
1214
case GK_CSR_COL:
1215
if (!graph->colptr)
1216
gk_errexit(SIGERR, "Column-based view of the graphrix does not exists.\n");
1217
1218
n = graph->ncols;
1219
ptr = graph->colptr;
1220
ind = graph->colind;
1221
val = graph->colval;
1222
break;
1223
1224
default:
1225
gk_errexit(SIGERR, "Invalid index type of %d.\n", what);
1226
return;
1227
}
1228
1229
#pragma omp parallel if (n > 100)
1230
{
1231
ssize_t i, j, k;
1232
gk_ikv_t *cand;
1233
float *tval;
1234
1235
#pragma omp single
1236
for (i=0; i<n; i++)
1237
nn = gk_max(nn, ptr[i+1]-ptr[i]);
1238
1239
cand = gk_ikvmalloc(nn, "gk_graph_SortIndices: cand");
1240
tval = gk_fmalloc(nn, "gk_graph_SortIndices: tval");
1241
1242
#pragma omp for schedule(static)
1243
for (i=0; i<n; i++) {
1244
for (k=0, j=ptr[i]; j<ptr[i+1]; j++) {
1245
if (j > ptr[i] && ind[j] < ind[j-1])
1246
k = 1; /* an inversion */
1247
cand[j-ptr[i]].val = j-ptr[i];
1248
cand[j-ptr[i]].key = ind[j];
1249
tval[j-ptr[i]] = val[j];
1250
}
1251
if (k) {
1252
gk_ikvsorti(ptr[i+1]-ptr[i], cand);
1253
for (j=ptr[i]; j<ptr[i+1]; j++) {
1254
ind[j] = cand[j-ptr[i]].key;
1255
val[j] = tval[cand[j-ptr[i]].val];
1256
}
1257
}
1258
}
1259
1260
gk_free((void **)&cand, &tval, LTERM);
1261
}
1262
1263
}
1264
1265
1266
/*************************************************************************/
1267
/*! Returns a subgraphrix containing a certain set of rows.
1268
\param graph is the original graphrix.
1269
\param nrows is the number of rows to extract.
1270
\param rind is the set of row numbers to extract.
1271
\returns the row structure of the newly created subgraphrix.
1272
*/
1273
/**************************************************************************/
1274
gk_graph_t *gk_graph_ExtractRows(gk_graph_t *graph, int nrows, int *rind)
1275
{
1276
ssize_t i, ii, j, nnz;
1277
gk_graph_t *ngraph;
1278
1279
ngraph = gk_graph_Create();
1280
1281
ngraph->nrows = nrows;
1282
ngraph->ncols = graph->ncols;
1283
1284
for (nnz=0, i=0; i<nrows; i++)
1285
nnz += graph->rowptr[rind[i]+1]-graph->rowptr[rind[i]];
1286
1287
ngraph->rowptr = gk_zmalloc(ngraph->nrows+1, "gk_graph_ExtractPartition: rowptr");
1288
ngraph->rowind = gk_imalloc(nnz, "gk_graph_ExtractPartition: rowind");
1289
ngraph->rowval = gk_fmalloc(nnz, "gk_graph_ExtractPartition: rowval");
1290
1291
ngraph->rowptr[0] = 0;
1292
for (nnz=0, j=0, ii=0; ii<nrows; ii++) {
1293
i = rind[ii];
1294
gk_icopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowind+graph->rowptr[i], ngraph->rowind+nnz);
1295
gk_fcopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowval+graph->rowptr[i], ngraph->rowval+nnz);
1296
nnz += graph->rowptr[i+1]-graph->rowptr[i];
1297
ngraph->rowptr[++j] = nnz;
1298
}
1299
ASSERT(j == ngraph->nrows);
1300
1301
return ngraph;
1302
}
1303
1304
1305
/*************************************************************************/
1306
/*! Returns a subgraphrix corresponding to a specified partitioning of rows.
1307
\param graph is the original graphrix.
1308
\param part is the partitioning vector of the rows.
1309
\param pid is the partition ID that will be extracted.
1310
\returns the row structure of the newly created subgraphrix.
1311
*/
1312
/**************************************************************************/
1313
gk_graph_t *gk_graph_ExtractPartition(gk_graph_t *graph, int *part, int pid)
1314
{
1315
ssize_t i, j, nnz;
1316
gk_graph_t *ngraph;
1317
1318
ngraph = gk_graph_Create();
1319
1320
ngraph->nrows = 0;
1321
ngraph->ncols = graph->ncols;
1322
1323
for (nnz=0, i=0; i<graph->nrows; i++) {
1324
if (part[i] == pid) {
1325
ngraph->nrows++;
1326
nnz += graph->rowptr[i+1]-graph->rowptr[i];
1327
}
1328
}
1329
1330
ngraph->rowptr = gk_zmalloc(ngraph->nrows+1, "gk_graph_ExtractPartition: rowptr");
1331
ngraph->rowind = gk_imalloc(nnz, "gk_graph_ExtractPartition: rowind");
1332
ngraph->rowval = gk_fmalloc(nnz, "gk_graph_ExtractPartition: rowval");
1333
1334
ngraph->rowptr[0] = 0;
1335
for (nnz=0, j=0, i=0; i<graph->nrows; i++) {
1336
if (part[i] == pid) {
1337
gk_icopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowind+graph->rowptr[i], ngraph->rowind+nnz);
1338
gk_fcopy(graph->rowptr[i+1]-graph->rowptr[i], graph->rowval+graph->rowptr[i], ngraph->rowval+nnz);
1339
nnz += graph->rowptr[i+1]-graph->rowptr[i];
1340
ngraph->rowptr[++j] = nnz;
1341
}
1342
}
1343
ASSERT(j == ngraph->nrows);
1344
1345
return ngraph;
1346
}
1347
1348
1349
/*************************************************************************/
1350
/*! Splits the graphrix into multiple sub-graphrices based on the provided
1351
color array.
1352
\param graph is the original graphrix.
1353
\param color is an array of size equal to the number of non-zeros
1354
in the graphrix (row-wise structure). The graphrix is split into
1355
as many parts as the number of colors. For meaningfull results,
1356
the colors should be numbered consecutively starting from 0.
1357
\returns an array of graphrices for each supplied color number.
1358
*/
1359
/**************************************************************************/
1360
gk_graph_t **gk_graph_Split(gk_graph_t *graph, int *color)
1361
{
1362
ssize_t i, j;
1363
int nrows, ncolors;
1364
ssize_t *rowptr;
1365
int *rowind;
1366
float *rowval;
1367
gk_graph_t **sgraphs;
1368
1369
nrows = graph->nrows;
1370
rowptr = graph->rowptr;
1371
rowind = graph->rowind;
1372
rowval = graph->rowval;
1373
1374
ncolors = gk_imax(rowptr[nrows], color)+1;
1375
1376
sgraphs = (gk_graph_t **)gk_malloc(sizeof(gk_graph_t *)*ncolors, "gk_graph_Split: sgraphs");
1377
for (i=0; i<ncolors; i++) {
1378
sgraphs[i] = gk_graph_Create();
1379
sgraphs[i]->nrows = graph->nrows;
1380
sgraphs[i]->ncols = graph->ncols;
1381
sgraphs[i]->rowptr = gk_zsmalloc(nrows+1, 0, "gk_graph_Split: sgraphs[i]->rowptr");
1382
}
1383
1384
for (i=0; i<nrows; i++) {
1385
for (j=rowptr[i]; j<rowptr[i+1]; j++)
1386
sgraphs[color[j]]->rowptr[i]++;
1387
}
1388
for (i=0; i<ncolors; i++)
1389
MAKECSR(j, nrows, sgraphs[i]->rowptr);
1390
1391
for (i=0; i<ncolors; i++) {
1392
sgraphs[i]->rowind = gk_imalloc(sgraphs[i]->rowptr[nrows], "gk_graph_Split: sgraphs[i]->rowind");
1393
sgraphs[i]->rowval = gk_fmalloc(sgraphs[i]->rowptr[nrows], "gk_graph_Split: sgraphs[i]->rowval");
1394
}
1395
1396
for (i=0; i<nrows; i++) {
1397
for (j=rowptr[i]; j<rowptr[i+1]; j++) {
1398
sgraphs[color[j]]->rowind[sgraphs[color[j]]->rowptr[i]] = rowind[j];
1399
sgraphs[color[j]]->rowval[sgraphs[color[j]]->rowptr[i]] = rowval[j];
1400
sgraphs[color[j]]->rowptr[i]++;
1401
}
1402
}
1403
1404
for (i=0; i<ncolors; i++)
1405
SHIFTCSR(j, nrows, sgraphs[i]->rowptr);
1406
1407
return sgraphs;
1408
}
1409
1410
1411
/*************************************************************************/
1412
/*! Prunes certain rows/columns of the graphrix. The prunning takes place
1413
by analyzing the row structure of the graphrix. The prunning takes place
1414
by removing rows/columns but it does not affect the numbering of the
1415
remaining rows/columns.
1416
1417
\param graph the graphrix to be prunned,
1418
\param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL)
1419
of the graphrix will be prunned,
1420
\param minf is the minimum number of rows (columns) that a column (row) must
1421
be present in order to be kept,
1422
\param maxf is the maximum number of rows (columns) that a column (row) must
1423
be present at in order to be kept.
1424
\returns the prunned graphrix consisting only of its row-based structure.
1425
The input graphrix is not modified.
1426
*/
1427
/**************************************************************************/
1428
gk_graph_t *gk_graph_Prune(gk_graph_t *graph, int what, int minf, int maxf)
1429
{
1430
ssize_t i, j, nnz;
1431
int nrows, ncols;
1432
ssize_t *rowptr, *nrowptr;
1433
int *rowind, *nrowind, *collen;
1434
float *rowval, *nrowval;
1435
gk_graph_t *ngraph;
1436
1437
ngraph = gk_graph_Create();
1438
1439
nrows = ngraph->nrows = graph->nrows;
1440
ncols = ngraph->ncols = graph->ncols;
1441
1442
rowptr = graph->rowptr;
1443
rowind = graph->rowind;
1444
rowval = graph->rowval;
1445
1446
nrowptr = ngraph->rowptr = gk_zmalloc(nrows+1, "gk_graph_Prune: nrowptr");
1447
nrowind = ngraph->rowind = gk_imalloc(rowptr[nrows], "gk_graph_Prune: nrowind");
1448
nrowval = ngraph->rowval = gk_fmalloc(rowptr[nrows], "gk_graph_Prune: nrowval");
1449
1450
1451
switch (what) {
1452
case GK_CSR_COL:
1453
collen = gk_ismalloc(ncols, 0, "gk_graph_Prune: collen");
1454
1455
for (i=0; i<nrows; i++) {
1456
for (j=rowptr[i]; j<rowptr[i+1]; j++) {
1457
ASSERT(rowind[j] < ncols);
1458
collen[rowind[j]]++;
1459
}
1460
}
1461
for (i=0; i<ncols; i++)
1462
collen[i] = (collen[i] >= minf && collen[i] <= maxf ? 1 : 0);
1463
1464
nrowptr[0] = 0;
1465
for (nnz=0, i=0; i<nrows; i++) {
1466
for (j=rowptr[i]; j<rowptr[i+1]; j++) {
1467
if (collen[rowind[j]]) {
1468
nrowind[nnz] = rowind[j];
1469
nrowval[nnz] = rowval[j];
1470
nnz++;
1471
}
1472
}
1473
nrowptr[i+1] = nnz;
1474
}
1475
gk_free((void **)&collen, LTERM);
1476
break;
1477
1478
case GK_CSR_ROW:
1479
nrowptr[0] = 0;
1480
for (nnz=0, i=0; i<nrows; i++) {
1481
if (rowptr[i+1]-rowptr[i] >= minf && rowptr[i+1]-rowptr[i] <= maxf) {
1482
for (j=rowptr[i]; j<rowptr[i+1]; j++, nnz++) {
1483
nrowind[nnz] = rowind[j];
1484
nrowval[nnz] = rowval[j];
1485
}
1486
}
1487
nrowptr[i+1] = nnz;
1488
}
1489
break;
1490
1491
default:
1492
gk_graph_Free(&ngraph);
1493
gk_errexit(SIGERR, "Unknown prunning type of %d\n", what);
1494
return NULL;
1495
}
1496
1497
return ngraph;
1498
}
1499
1500
1501
1502
/*************************************************************************/
1503
/*! Normalizes the rows/columns of the graphrix to be unit
1504
length.
1505
\param graph the graphrix itself,
1506
\param what indicates what will be normalized and is obtained by
1507
specifying GK_CSR_ROW, GK_CSR_COL, GK_CSR_ROW|GK_CSR_COL.
1508
\param norm indicates what norm is to normalize to, 1: 1-norm, 2: 2-norm
1509
*/
1510
/**************************************************************************/
1511
void gk_graph_Normalize(gk_graph_t *graph, int what, int norm)
1512
{
1513
ssize_t i, j;
1514
int n;
1515
ssize_t *ptr;
1516
float *val, sum;
1517
1518
if (what&GK_CSR_ROW && graph->rowval) {
1519
n = graph->nrows;
1520
ptr = graph->rowptr;
1521
val = graph->rowval;
1522
1523
#pragma omp parallel if (ptr[n] > OMPMINOPS)
1524
{
1525
#pragma omp for private(j,sum) schedule(static)
1526
for (i=0; i<n; i++) {
1527
for (sum=0.0, j=ptr[i]; j<ptr[i+1]; j++){
1528
if (norm == 2)
1529
sum += val[j]*val[j];
1530
else if (norm == 1)
1531
sum += val[j]; /* assume val[j] > 0 */
1532
}
1533
if (sum > 0) {
1534
if (norm == 2)
1535
sum=1.0/sqrt(sum);
1536
else if (norm == 1)
1537
sum=1.0/sum;
1538
for (j=ptr[i]; j<ptr[i+1]; j++)
1539
val[j] *= sum;
1540
1541
}
1542
}
1543
}
1544
}
1545
1546
if (what&GK_CSR_COL && graph->colval) {
1547
n = graph->ncols;
1548
ptr = graph->colptr;
1549
val = graph->colval;
1550
1551
#pragma omp parallel if (ptr[n] > OMPMINOPS)
1552
{
1553
#pragma omp for private(j,sum) schedule(static)
1554
for (i=0; i<n; i++) {
1555
for (sum=0.0, j=ptr[i]; j<ptr[i+1]; j++)
1556
if (norm == 2)
1557
sum += val[j]*val[j];
1558
else if (norm == 1)
1559
sum += val[j];
1560
if (sum > 0) {
1561
if (norm == 2)
1562
sum=1.0/sqrt(sum);
1563
else if (norm == 1)
1564
sum=1.0/sum;
1565
for (j=ptr[i]; j<ptr[i+1]; j++)
1566
val[j] *= sum;
1567
}
1568
}
1569
}
1570
}
1571
}
1572
1573
1574
#endif
1575
1576