1 /* Copyright 2007-2010,2012 IPB, Universite de Bordeaux, INRIA & CNRS
2 **
3 ** This file is part of the Scotch software package for static mapping,
4 ** graph partitioning and sparse matrix ordering.
5 **
6 ** This software is governed by the CeCILL-C license under French law
7 ** and abiding by the rules of distribution of free software. You can
8 ** use, modify and/or redistribute the software under the terms of the
9 ** CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
10 ** URL: "http://www.cecill.info".
11 **
12 ** As a counterpart to the access to the source code and rights to copy,
13 ** modify and redistribute granted by the license, users are provided
14 ** only with a limited warranty and the software's author, the holder of
15 ** the economic rights, and the successive licensors have only limited
16 ** liability.
17 **
18 ** In this respect, the user's attention is drawn to the risks associated
19 ** with loading, using, modifying and/or developing or reproducing the
20 ** software by the user in light of its specific status of free software,
21 ** that may mean that it is complicated to manipulate, and that also
22 ** therefore means that it is reserved for developers and experienced
23 ** professionals having in-depth computer knowledge. Users are therefore
24 ** encouraged to load and test the software's suitability as regards
25 ** their requirements in conditions enabling the security of their
26 ** systems and/or data to be ensured and, more generally, to use and
27 ** operate it in the same conditions as regards security.
28 **
29 ** The fact that you are presently reading this means that you have had
30 ** knowledge of the CeCILL-C license and that you accept its terms.
31 */
32 /************************************************************/
33 /** **/
34 /** NAME : dgraph_induce.c **/
35 /** **/
36 /** AUTHOR : Francois PELLEGRINI **/
37 /** Jun-Ho HER (v6.0) **/
38 /** **/
39 /** FUNCTION : This module handles the source graph **/
40 /** subgraph-making functions. **/
41 /** **/
42 /** DATES : # Version 5.0 : from : 08 apr 2006 **/
43 /** to : 10 sep 2007 **/
44 /** # Version 5.1 : from : 31 mar 2008 **/
45 /** to : 30 jul 2010 **/
46 /** # Version 6.0 : from : 29 aug 2012 **/
47 /** to : 13 sep 2012 **/
48 /** **/
49 /************************************************************/
50
51 /*
52 ** The defines and includes.
53 */
54
55 #define DGRAPH
56 #define DGRAPH_INDUCE
57
58 #include "module.h"
59 #include "common.h"
60 #include "dgraph.h"
61
62 /****************************************/
63 /* */
64 /* These routines handle source graphs. */
65 /* */
66 /****************************************/
67
68 int
dgraphInduce2(Dgraph * restrict const orggrafptr,Gnum (* orgfuncptr)(Dgraph * restrict const,Dgraph * restrict const,const void * restrict const,Gnum * restrict const),const void * const orgdataptr,const Gnum indvertlocnbr,Gnum * indvnumloctmp,Dgraph * restrict const indgrafptr)69 dgraphInduce2 (
70 Dgraph * restrict const orggrafptr,
71 Gnum (* orgfuncptr) (Dgraph * restrict const, Dgraph * restrict const, const void * restrict const, Gnum * restrict const),
72 const void * const orgdataptr, /* Pointer to routine-specific data */
73 const Gnum indvertlocnbr, /* Number of vertices in induced subgraph */
74 Gnum * indvnumloctmp, /* Pointer to temporary index array; TRICK: [alias] */
75 Dgraph * restrict const indgrafptr)
76 {
77 Gnum * restrict orgindxgsttax; /* Based access to vertex translation array */
78 Gnum indvertlocnnd; /* Based index of end of local vertex array */
79 Gnum indvertlocnum; /* Number of current vertex in induced graph */
80 Gnum indvertglbnum; /* Number of current vertex in global ordering */
81 Gnum indvelolocnbr; /* Size of local vertex load array */
82 Gnum indvelolocsum; /* Sum of vertex loads */
83 Gnum * indvnumloctax; /* TRICK: maybe alias of indvnumloctmp */
84 Gnum indvlbllocnbr; /* Size of local vertex label array */
85 Gnum indedgelocmax; /* (Approximate) number of edges in induced graph */
86 Gnum indedgelocnbr; /* Real number of edges in induced graph */
87 Gnum indedgelocnum;
88 Gnum * restrict indedloloctax;
89 Gnum inddegrlocmax; /* Local maximum degree */
90 const Gnum * restrict indlisttax;
91 Gnum baseval;
92 int cheklocval;
93 int chekglbval;
94
95 const Gnum * restrict const orgvertloctax = orggrafptr->vertloctax;
96 const Gnum * restrict const orgvendloctax = orggrafptr->vendloctax;
97 const Gnum * restrict const orgvnumloctax = orggrafptr->vnumloctax;
98 const Gnum * restrict const orgvlblloctax = orggrafptr->vlblloctax;
99 const Gnum * restrict const orgveloloctax = orggrafptr->veloloctax;
100 const Gnum * restrict const orgedloloctax = orggrafptr->edloloctax;
101
102 if (dgraphGhst (orggrafptr) != 0) { /* Compute ghost edge array if not already present */
103 errorPrint ("dgraphInduce2: cannot compute ghost edge array");
104 return (1);
105 }
106
107 baseval = orggrafptr->baseval;
108 indgrafptr->flagval |= (DGRAPHFREEALL ^ DGRAPHFREECOMM) | DGRAPHVERTGROUP | DGRAPHEDGEGROUP;
109 indgrafptr->baseval = baseval;
110 indgrafptr->vertlocnbr = indvertlocnbr; /* Must be set before orgfuncptr() is called */
111 indgrafptr->vertlocnnd = indvertlocnbr + baseval;
112
113 if (orgveloloctax != NULL) {
114 indvelolocnbr = indvertlocnbr;
115 indvelolocsum = 0;
116 }
117 else {
118 indvelolocnbr = 0;
119 indvelolocsum = indvertlocnbr;
120 }
121 indvlbllocnbr = (orgvlblloctax != NULL) ? indvertlocnbr : 0;
122 indedgelocmax = orggrafptr->edgelocnbr; /* Choose best upper bound on number of edges (avoid multiply overflow) */
123 if ((orggrafptr->degrglbmax > 0) && (indvertlocnbr < (indedgelocmax / orggrafptr->degrglbmax)))
124 indedgelocmax = indvertlocnbr * orggrafptr->degrglbmax;
125 if (orggrafptr->edloloctax != NULL) /* If graph has edge weights */
126 indedgelocmax *= 2; /* Account for edge weights */
127
128 cheklocval =
129 chekglbval = 0;
130 if (memAllocGroup ((void **) (void *) /* Allocate distributed graph private data */
131 &indgrafptr->procdsptab, (size_t) ((orggrafptr->procglbnbr + 1) * sizeof (Gnum)),
132 &indgrafptr->proccnttab, (size_t) (orggrafptr->procglbnbr * sizeof (Gnum)),
133 &indgrafptr->procngbtab, (size_t) (orggrafptr->procglbnbr * sizeof (int)),
134 &indgrafptr->procrcvtab, (size_t) (orggrafptr->procglbnbr * sizeof (int)),
135 &indgrafptr->procsndtab, (size_t) (orggrafptr->procglbnbr * sizeof (int)), NULL) == NULL) {
136 errorPrint ("dgraphInduce2: out of memory (1)");
137 cheklocval = 1;
138 }
139 else if (memAllocGroup ((void **) (void *) /* Allocate distributed graph public data */
140 &indgrafptr->vertloctax, (size_t) ((indvertlocnbr + 1) * sizeof (Gnum)), /* Compact vertex array */
141 &indgrafptr->vnumloctax, (size_t) (indvertlocnbr * sizeof (Gnum)),
142 &indgrafptr->veloloctax, (size_t) (indvelolocnbr * sizeof (Gnum)),
143 &indgrafptr->vlblloctax, (size_t) (indvlbllocnbr * sizeof (Gnum)), NULL) == NULL) {
144 errorPrint ("dgraphInduce2: out of memory (2)");
145 cheklocval = 1;
146 }
147 else if (indgrafptr->vertloctax -= baseval,
148 indgrafptr->vnumloctax -= baseval,
149 indgrafptr->veloloctax = (orgveloloctax != NULL) ? indgrafptr->veloloctax - baseval : NULL,
150 indgrafptr->vlblloctax = indgrafptr->vlblloctax - baseval, /* If no vertex labels, vlblloctax will point to vnumloctax afterward */
151 memAllocGroup ((void **) (void *)
152 &indgrafptr->edgeloctax, (size_t) (indedgelocmax * sizeof (Gnum)), /* Pre-allocate space for edgetab (and edlotab) */
153 &orgindxgsttax, (size_t) (orggrafptr->vertgstnbr * sizeof (Gnum)), NULL) == NULL) { /* orgindxgsttab is at the end */
154 errorPrint ("dgraphInduce2: out of memory (3)");
155 cheklocval = 1;
156 }
157 else
158 indgrafptr->edgeloctax -= baseval;
159
160 if (cheklocval != 0) { /* In case of memory error */
161 Gnum procngbnum;
162 Gnum dummyval;
163
164 dummyval = -1;
165 chekglbval = 1;
166 if (MPI_Allgather (&dummyval, 1, GNUM_MPI, /* Use proccnttab of orggraf as dummy receive array (will be regenerated) */
167 orggrafptr->proccnttab, 1, GNUM_MPI, indgrafptr->proccomm) != MPI_SUCCESS)
168 errorPrint ("dgraphInduce2: communication error (1)");
169
170 for (procngbnum = 1; procngbnum <= orggrafptr->procglbnbr; procngbnum ++) /* Rebuild proccnttab of orggraf */
171 orggrafptr->proccnttab[procngbnum - 1] = orggrafptr->procdsptab[procngbnum] - orggrafptr->procdsptab[procngbnum - 1];
172 }
173 else {
174 indgrafptr->procdsptab[0] = indvertlocnbr;
175 if (MPI_Allgather (&indgrafptr->procdsptab[0], 1, GNUM_MPI,
176 &indgrafptr->proccnttab[0], 1, GNUM_MPI, indgrafptr->proccomm) != MPI_SUCCESS) {
177 errorPrint ("dgraphInduce2: communication error (2)");
178 chekglbval = 1;
179 }
180 else {
181 Gnum procngbnum;
182
183 indgrafptr->procdsptab[0] = baseval; /* Build vertex-to-process array */
184 for (procngbnum = 0; procngbnum < indgrafptr->procglbnbr; procngbnum ++) { /* Process potential error flags from other processes */
185 if (indgrafptr->procdsptab[procngbnum] < 0) { /* If error notified by another process */
186 chekglbval = 1;
187 break;
188 }
189 indgrafptr->procdsptab[procngbnum + 1] = indgrafptr->procdsptab[procngbnum] + indgrafptr->proccnttab[procngbnum];
190 }
191 }
192 indgrafptr->procvrttab = indgrafptr->procdsptab; /* Graph does not have holes */
193 }
194 if (chekglbval != 0) { /* If something went wrong in all of the above */
195 dgraphFree (indgrafptr);
196 return (1);
197 }
198
199 memSet (orgindxgsttax, ~0, orggrafptr->vertlocnbr * sizeof (Gnum)); /* Preset index array */
200 orgindxgsttax -= baseval;
201
202 indedgelocmax = orgfuncptr (indgrafptr, orggrafptr, orgdataptr, orgindxgsttax); /* Call flagging subroutine */
203
204 if (dgraphHaloSync (orggrafptr, (byte *) (orgindxgsttax + baseval), GNUM_MPI) != 0) { /* Share global indexing of subgraph vertices */
205 errorPrint ("dgraphInduce2: cannot perform halo exchange");
206 dgraphFree (indgrafptr);
207 return (1);
208 }
209
210 if (indvnumloctmp == NULL) /* indgrafptr->vnumloctax did not exist when function was called */
211 indvnumloctmp = indgrafptr->vnumloctax;
212
213 indedloloctax = (orggrafptr->edloloctax != NULL) ? indgrafptr->edgeloctax + indedgelocmax : NULL;
214 inddegrlocmax = 0;
215 for (indvertlocnum = indedgelocnum = baseval, indvertlocnnd = indvertlocnbr + baseval;
216 indvertlocnum < indvertlocnnd; indvertlocnum ++) {
217 Gnum orgvertlocnum;
218 Gnum orgedgelocnum;
219
220 orgvertlocnum = indvnumloctmp[indvertlocnum];
221 indgrafptr->vertloctax[indvertlocnum] = indedgelocnum;
222 if (orgveloloctax != NULL) { /* If graph has vertex weights */
223 indvelolocsum += /* Accumulate vertex loads */
224 indgrafptr->veloloctax[indvertlocnum] = orgveloloctax[orgvertlocnum];
225 }
226 if (orgvlblloctax != NULL) /* If graph has vertex labels */
227 indgrafptr->vlblloctax[indvertlocnum] = orgvlblloctax[orgvertlocnum];
228
229 for (orgedgelocnum = orgvertloctax[orgvertlocnum];
230 orgedgelocnum < orgvendloctax[orgvertlocnum]; orgedgelocnum ++) {
231 Gnum indvertgstend;
232
233 indvertgstend = orgindxgsttax[orggrafptr->edgegsttax[orgedgelocnum]];
234 if (indvertgstend != ~0) { /* If edge should be kept */
235 indgrafptr->edgeloctax[indedgelocnum] = indvertgstend;
236 if (indedloloctax != NULL)
237 indedloloctax[indedgelocnum] = orgedloloctax[orgedgelocnum];
238 indedgelocnum ++;
239 }
240 }
241 if (inddegrlocmax < (indedgelocnum - indgrafptr->vertloctax[indvertlocnum]))
242 inddegrlocmax = (indedgelocnum - indgrafptr->vertloctax[indvertlocnum]);
243 }
244 indedgelocnbr = indedgelocnum - baseval;
245 indgrafptr->vertloctax[indvertlocnum] = indedgelocnum; /* Mark end of edge array */
246 indgrafptr->vendloctax = indgrafptr->vertloctax + 1; /* Induced graph is compact */
247 indgrafptr->velolocsum = indvelolocsum;
248 indgrafptr->edgelocnbr = indedgelocnbr;
249 indgrafptr->edgelocsiz = indedgelocnbr;
250 if (orgvlblloctax == NULL) /* If we didn't have vertex labels, use vertex index array as vertex label array */
251 indgrafptr->vlblloctax = indgrafptr->vnumloctax;
252
253 if (indedloloctax != NULL) { /* Re-allocate arrays and delete orgindxtab */
254 size_t indedlooftval; /* Offset of edge load array with respect to edge array */
255
256 indedlooftval = indedloloctax - indgrafptr->edgeloctax;
257 indgrafptr->edgeloctax = memRealloc (indgrafptr->edgeloctax + baseval, (indedlooftval + indedgelocnbr) * sizeof (Gnum));
258 indgrafptr->edgeloctax -= baseval;
259 indedloloctax = indgrafptr->edgeloctax + indedlooftval; /* Use old index into old array as new index to avoid alignment problems */
260 }
261 else {
262 indgrafptr->edgeloctax = memRealloc (indgrafptr->edgeloctax + baseval, indedgelocnbr * sizeof (Gnum));
263 indgrafptr->edgeloctax -= baseval;
264 }
265
266 indvertlocnum = baseval;
267 indvnumloctax = indgrafptr->vnumloctax; /* TRICK: maybe alias */
268 if (orgvnumloctax != NULL) { /* Adjust vnumloctax */
269 for ( ; indvertlocnum < indvertlocnnd; indvertlocnum ++)
270 indvnumloctax[indvertlocnum] = orgvnumloctax[indvnumloctmp[indvertlocnum]]; /* TRICK: indvnumloctmp and indgrafptr->vnumloctax may be aliases */
271 }
272 else {
273 Gnum orgvertglbadj;
274
275 orgvertglbadj = orggrafptr->procvrttab[orggrafptr->proclocnum] - baseval; /* Set adjustement for global indexing */
276 for ( ; indvertlocnum < indvertlocnnd; indvertlocnum ++)
277 indvnumloctax[indvertlocnum] = indvnumloctmp[indvertlocnum] + orgvertglbadj; /* TRICK: indvnumloctmp and indgrafptr->vnumloctax may be aliases */
278 }
279
280 indgrafptr->edloloctax = indedloloctax;
281 indgrafptr->degrglbmax = inddegrlocmax; /* Local maximum degree will be turned into global maximum degree */
282 if (dgraphBuild4 (indgrafptr) != 0) {
283 errorPrint ("dgraphInduce2: cannot build induced graph");
284 return (1);
285 }
286 #ifdef SCOTCH_DEBUG_DGRAPH2
287 if (dgraphCheck (indgrafptr) != 0) { /* Check graph consistency */
288 errorPrint ("dgraphInduce2: inconsistent graph data");
289 dgraphFree (indgrafptr);
290 return (1);
291 }
292 #endif /* SCOTCH_DEBUG_DGRAPH2 */
293
294 return (0);
295 }
296
297 /* This routine builds the graph induced
298 ** by the original graph and the list of
299 ** selected vertices.
300 ** The induced vnumtab array is the global
301 ** translation of the list array if the
302 ** original graph does not have a vnumtab,
303 ** or the proper subset of the original
304 ** vnumtab else.
305 ** It returns:
306 ** - 0 : on success.
307 ** - !0 : on error.
308 */
309
310 static
311 Gnum
dgraphInduceList2(Dgraph * restrict const indgrafptr,Dgraph * restrict const orggrafptr,const void * restrict const orgdataptr,Gnum * restrict const orgindxgsttax)312 dgraphInduceList2 (
313 Dgraph * restrict const indgrafptr,
314 Dgraph * restrict const orggrafptr,
315 const void * restrict const orgdataptr, /* Data pointer is list array pointer */
316 Gnum * restrict const orgindxgsttax)
317 {
318 Gnum orglistnbr;
319 Gnum orglistnum;
320 Gnum indvertglbnum;
321 Gnum indedgelocmax;
322
323 const Gnum * restrict const orgvertloctax = orggrafptr->vertloctax;
324 const Gnum * restrict const orgvendloctax = orggrafptr->vendloctax;
325 const Gnum * restrict const orglisttab = (const Gnum * restrict) orgdataptr;
326
327 for (orglistnum = 0, indvertglbnum = indgrafptr->procvrttab[indgrafptr->proclocnum], /* Fill index array while recomputing tighter upper bound on arcs */
328 orglistnbr = indgrafptr->vertlocnbr, indedgelocmax = 0;
329 orglistnum < orglistnbr; orglistnum ++, indvertglbnum ++) {
330 Gnum orgvertlocnum;
331
332 orgvertlocnum = orglisttab[orglistnum];
333 orgindxgsttax[orgvertlocnum] = indvertglbnum; /* Mark selected vertices */
334 indedgelocmax += orgvendloctax[orgvertlocnum] - orgvertloctax[orgvertlocnum];
335 }
336
337 return (indedgelocmax);
338 }
339
340 int
dgraphInduceList(Dgraph * restrict const orggrafptr,const Gnum orglistnbr,const Gnum * const orglisttab,Dgraph * restrict const indgrafptr)341 dgraphInduceList (
342 Dgraph * restrict const orggrafptr,
343 const Gnum orglistnbr,
344 const Gnum * const orglisttab, /* Local list of kept vertices */
345 Dgraph * restrict const indgrafptr)
346 {
347 return (dgraphInduce2 (orggrafptr, dgraphInduceList2, (const void * const) orglisttab, orglistnbr, (Gnum * const) (orglisttab - orggrafptr->baseval), indgrafptr));
348 }
349
350 /* This routine builds the graph induced
351 ** by the original graph and the vector of
352 ** selected vertices.
353 ** The induced vnumtab array is the global
354 ** translation of the list array if the
355 ** original graph does not have a vnumtab,
356 ** or the proper subset of the original
357 ** vnumtab else.
358 ** It returns:
359 ** - 0 : on success.
360 ** - !0 : on error.
361 */
362
363 typedef struct DgraphInducePartData_ {
364 const GraphPart * orgpartloctax;
365 GraphPart indpartval;
366 } DgraphInducePartData;
367
368 static
369 Gnum
dgraphInducePart2(Dgraph * restrict const indgrafptr,Dgraph * restrict const orggrafptr,const void * restrict const orgdataptr,Gnum * restrict const orgindxgsttax)370 dgraphInducePart2 (
371 Dgraph * restrict const indgrafptr,
372 Dgraph * restrict const orggrafptr,
373 const void * restrict const orgdataptr,
374 Gnum * restrict const orgindxgsttax)
375 {
376 Gnum orgvertlocnnd;
377 Gnum orgvertlocnum;
378 Gnum indvertlocnum;
379 Gnum indvertglbnum;
380 Gnum indedgelocmax;
381
382 const Gnum * restrict const orgvertloctax = orggrafptr->vertloctax;
383 const Gnum * restrict const orgvendloctax = orggrafptr->vendloctax;
384 const GraphPart * restrict const orgpartloctax = ((const DgraphInducePartData * restrict const) orgdataptr)->orgpartloctax;
385 const GraphPart indpartval = ((const DgraphInducePartData * restrict const) orgdataptr)->indpartval;
386 Gnum * restrict const indvnumloctax = indgrafptr->vnumloctax;
387
388 for (orgvertlocnum = indvertlocnum = orggrafptr->baseval, indvertglbnum = indgrafptr->procvrttab[indgrafptr->proclocnum], /* Fill index array while recomputing tighter upper bound on arcs */
389 orgvertlocnnd = orggrafptr->vertlocnnd, indedgelocmax = 0;
390 orgvertlocnum < orgvertlocnnd; orgvertlocnum ++) {
391 if (orgpartloctax[orgvertlocnum] == indpartval) {
392 orgindxgsttax[orgvertlocnum] = indvertglbnum; /* Mark selected vertices */
393 indvnumloctax[indvertlocnum] = orgvertlocnum;
394 indedgelocmax += orgvendloctax[orgvertlocnum] - orgvertloctax[orgvertlocnum];
395 indvertlocnum ++, indvertglbnum ++;
396 }
397 else
398 orgindxgsttax[orgvertlocnum] = ~0;
399 }
400 #ifdef SCOTCH_DEBUG_DGRAPH2
401 if ((indvertlocnum - orggrafptr->baseval) != indgrafptr->vertlocnbr) {
402 errorPrint ("dgraphInducePart2: inconsistent data");
403 dgraphFree (indgrafptr);
404 return (1);
405 }
406 #endif /* SCOTCH_DEBUG_DGRAPH2 */
407
408 return (indedgelocmax);
409 }
410
411 int
dgraphInducePart(Dgraph * restrict const orggrafptr,const GraphPart * restrict const orgpartloctax,const Gnum indvertlocnbr,const GraphPart indpartval,Dgraph * restrict const indgrafptr)412 dgraphInducePart (
413 Dgraph * restrict const orggrafptr, /* Pointer to original distributed graph */
414 const GraphPart * restrict const orgpartloctax, /* Based array of local vertex partition flags */
415 const Gnum indvertlocnbr, /* Number of local vertices in selected part */
416 const GraphPart indpartval,
417 Dgraph * restrict const indgrafptr)
418 {
419 DgraphInducePartData orgdatadat;
420
421 orgdatadat.orgpartloctax = orgpartloctax;
422 orgdatadat.indpartval = indpartval;
423
424 return (dgraphInduce2 (orggrafptr, dgraphInducePart2, &orgdatadat, indvertlocnbr, NULL, indgrafptr));
425 }
426