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