1 /* Copyright 2010,2014 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 : wgraph_part_rb.c **/
35 /** **/
36 /** AUTHOR : Jun-Ho HER (v6.0) **/
37 /** Francois PELLEGRINI **/
38 /** **/
39 /** FUNCTION : This module performs the vertex overla- **/
40 /** pped graph partitioning based on recur- **/
41 /** sive bipartitioning approach. **/
42 /** **/
43 /** DATES : # Version 6.0 : from : 16 mar 2010 **/
44 /** to 12 aug 2014 **/
45 /** **/
46 /** NOTES : # This code derives from the code of **/
47 /** kgraph_map_rb_part.c for the vertex **/
48 /** overlapped graph partitioning. **/
49 /** **/
50 /************************************************************/
51
52 /*
53 ** The defines and includes.
54 */
55
56 #define WGRAPH_PART_RB
57
58 #include "module.h"
59 #include "common.h"
60 #include "parser.h"
61 #include "graph.h"
62 #include "arch.h"
63 #include "arch_cmplt.h"
64 #include "mapping.h"
65 #include "vgraph.h"
66 #include "vgraph_separate_st.h"
67 #include "vgraph_separate_zr.h"
68 #include "wgraph.h"
69 #include "wgraph_part_rb.h"
70 #include "scotch.h"
71
72 /*
73 ** The static variables.
74 */
75
76 static const Gnum wgraphpartrbloadone = 1;
77
78 /********************************************/
79 /* */
80 /* This is the entry point for the vertex */
81 /* overlapped graph partitioning based on */
82 /* recursive bipartitioning approach. */
83 /* */
84 /********************************************/
85
86 /* This routine runs recursive
87 ** bipartitioning approach.
88 ** It returns:
89 ** - 0 : on success.
90 ** - !0 : on error.
91 */
92
93 static
94 int
wgraphPartRb3(const Graph * restrict const orggrafptr,const GraphPart * restrict const orgparttax,const GraphPart indpartval,const int domnnum,Mapping * restrict const mappptr)95 wgraphPartRb3 (
96 const Graph * restrict const orggrafptr, /* Graph to induce and bipartition */
97 const GraphPart * restrict const orgparttax, /* Part array of original graph */
98 const GraphPart indpartval, /* Part of graph to consider */
99 const int domnnum, /* Index of domain onto which map the part */
100 Mapping * restrict const mappptr) /* Final mapping */
101 {
102 Gnum vertnum;
103
104 if (orgparttax == NULL) { /* If graph is full graph */
105 #ifdef SCOTCH_DEBUG_WGRAPH2
106 if ((orggrafptr->vnumtax != NULL) || (domnnum != 0)) {
107 errorPrint ("wgraphPartRb3: internal error");
108 return (1);
109 }
110 #endif /* SCOTCH_DEBUG_WGRAPH2 */
111 memSet (mappptr->parttax + mappptr->grafptr->baseval, 0, orggrafptr->vertnbr * sizeof (ArchDomNum));
112 }
113 else { /* Graph to consider is a subgraph of the original graph */
114 if (orggrafptr->vnumtax == NULL) { /* If original graph is not itself a subgraph */
115 for (vertnum = orggrafptr->baseval; vertnum < orggrafptr->vertnnd; vertnum ++) { /* For all graph vertices */
116 if (orgparttax[vertnum] == indpartval) /* If vertex belongs to the right part */
117 mappptr->parttax[vertnum] = domnnum;
118 }
119 }
120 else {
121 for (vertnum = orggrafptr->baseval; vertnum < orggrafptr->vertnnd; vertnum ++) { /* For all graph vertices */
122 if (orgparttax[vertnum] == indpartval) /* If vertex belongs to the right part */
123 mappptr->parttax[orggrafptr->vnumtax[vertnum]] = domnnum;
124 }
125 }
126 }
127
128 return (0);
129 }
130
131 static
132 int
wgraphPartRb2(WgraphPartRbData * restrict const dataptr,Graph * restrict const orggrafptr,const GraphPart * restrict const orgparttax,const GraphPart indpartval,const int indvertnbr,const int domnnum)133 wgraphPartRb2 (
134 WgraphPartRbData * restrict const dataptr, /* Top-level graph and partition data */
135 Graph * restrict const orggrafptr, /* Graph to induce and bipartition */
136 const GraphPart * restrict const orgparttax, /* Part array of original graph to consider */
137 const GraphPart indpartval, /* Part of graph to consider */
138 const int indvertnbr, /* Number of vertices in part or in graph */
139 const int domnnum) /* Index of domain onto which map the part */
140 {
141 Graph indgrafdat;
142 Graph * indgrafptr;
143 Vgraph actgrafdat;
144 Anum domnsubidx;
145 Anum domnsubdlt;
146 ArchDom domnsubtab[2]; /* Target subdomains */
147 Anum domnsubnum[2]; /* Index of subdomains in mapping */
148 Gnum grafsubsiz[2];
149 Gnum vertnum;
150 Mapping * restrict mappptr;
151 int i;
152 int o;
153
154 mappptr = &dataptr->mappdat;
155 o = archDomBipart (mappptr->archptr, &mappptr->domntab[domnnum], &domnsubtab[0], &domnsubtab[1]);
156
157 switch (o) {
158 case 1 : /* If target domain is terminal */
159 return (wgraphPartRb3 (orggrafptr, orgparttax, indpartval, domnnum, mappptr)); /* Update mapping and return */
160 case 2 : /* On error */
161 errorPrint ("wgraphPartRb2: cannot bipartition domain");
162 return (1);
163 }
164
165 indgrafptr = orggrafptr; /* Assume we will work on the original graph */
166 if (orgparttax != NULL) { /* If not the case, build induced subgraph */
167 indgrafptr = &indgrafdat;
168 if (graphInducePart (orggrafptr, orgparttax, indvertnbr, indpartval, &indgrafdat) != 0) {
169 errorPrint ("wgraphPartRb2: cannot induce graph");
170 return (1);
171 }
172 }
173
174 actgrafdat.s = *indgrafptr;
175 actgrafdat.s.vlbltax = NULL;
176 if ((actgrafdat.frontab = (Gnum *) memAlloc (actgrafdat.s.vertnbr * sizeof (Gnum))) == NULL) {
177 errorPrint ("wgraphPartRb2: out of memory (1)");
178 return (1);
179 }
180 if ((actgrafdat.parttax = (GraphPart *) memAlloc (actgrafdat.s.vertnbr * sizeof (GraphPart))) == NULL) {
181 errorPrint ("wgraphPartRb2: out of memory (2)");
182 memFree (actgrafdat.frontab);
183 return (1);
184 }
185 actgrafdat.parttax -= actgrafdat.s.baseval;
186 vgraphZero (&actgrafdat); /* Create active graph */
187 if (vgraphSeparateSt (&actgrafdat, dataptr->stratptr) != 0) { /* Perform bipartitioning */
188 errorPrint ("wgraphPartRb2: cannot bipartition graph");
189 vgraphExit (&actgrafdat);
190 return (1);
191 }
192
193 if (actgrafdat.s.vnumtax == NULL) { /* If the active graph is not itself a subgraph */
194 for (vertnum = actgrafdat.s.baseval; vertnum < actgrafdat.s.vertnnd; vertnum ++) { /* For all graph vertices */
195 if (actgrafdat.parttax[vertnum] == 2) { /* If vertex belongs to frontier */
196 mappptr->parttax[vertnum] = -1;
197 actgrafdat.parttax[vertnum] = 3;
198 }
199 }
200 }
201 else {
202 for (vertnum = actgrafdat.s.baseval; vertnum < actgrafdat.s.vertnnd; vertnum ++) { /* For all graph vertices */
203 if (actgrafdat.parttax[vertnum] == 2) { /* If vertex belongs to frontier */
204 mappptr->parttax[actgrafdat.s.vnumtax[vertnum]]= -1;
205 actgrafdat.parttax[vertnum] = 3;
206 }
207 }
208 }
209
210
211 domnsubdlt = mappptr->domnnbr - domnnum; /* Increment in domain number */
212 domnsubidx = domnnum - domnsubdlt; /* Place where to insert subdomain */
213 mappptr->domnnbr --; /* One less subdomain as for now */
214 grafsubsiz[0] = actgrafdat.compsize[0];
215 grafsubsiz[1] = actgrafdat.compsize[1];
216
217 o = 0;
218 for (i = 1; i >= 0; i --) { /* For all subparts */
219 if (grafsubsiz[i] <= 0) /* If subpart is empty, skip it */
220 continue;
221 mappptr->domnnbr ++; /* One more subdomain to account for */
222 domnsubidx += domnsubdlt; /* Compute location of subdomain */
223 domnsubnum[i] = domnsubidx; /* Record it before recursion */
224 mappptr->domntab[domnsubidx] = domnsubtab[i]; /* Write it at this place */
225 }
226
227 if (o == 0) {
228 for (i = 1; i >= 0; i --) { /* For all subparts */
229 if (grafsubsiz[i] <= 0) /* If subpart is empty, skip it */
230 continue;
231
232 if ((o = wgraphPartRb2 (dataptr, indgrafptr, actgrafdat.parttax, (GraphPart) i, grafsubsiz[i], domnsubnum[i])) != 0)
233 return (1); /* If problem in recursion, stop */
234 }
235 }
236
237 memFree (actgrafdat.frontab); /* Frontier array of bipartitioning graph is no longer necessary */
238 memFree (actgrafdat.parttax + actgrafdat.s.baseval); /* Frontier array of bipartitioning graph is no longer necessary */
239 if (indgrafptr == &indgrafdat) /* If an induced subgraph had been created */
240 graphExit (indgrafptr); /* Free it */
241
242 return (o);
243 }
244
245 int
wgraphPartRb(Wgraph * restrict const grafptr,const WgraphPartRbParam * restrict const paraptr)246 wgraphPartRb (
247 Wgraph * restrict const grafptr,
248 const WgraphPartRbParam * restrict const paraptr)
249 {
250 const Anum * restrict parttax;
251 Anum partval;
252 Gnum vertnum;
253 Gnum velomsk;
254 const Gnum * restrict velobax; /* Data for handling of optional arrays */
255 Gnum * restrict frontab;
256 Gnum fronnbr;
257 Gnum fronload;
258 Gnum * restrict compload;
259 Gnum * restrict compsize;
260 WgraphPartRbData datadat;
261 Arch archdat;
262 WgraphPartList * restrict listtab;
263
264 const Gnum * restrict const verttax = grafptr->s.verttax;
265 const Gnum * restrict const vendtax = grafptr->s.vendtax;
266 const Gnum * restrict const edgetax = grafptr->s.edgetax;
267
268 if ((listtab = (WgraphPartList *) memAlloc ((grafptr->partnbr + 1) * sizeof (WgraphPartList))) == NULL) { /* TRICK: "+1" to create slot for a "-1" index */
269 errorPrint ("wgraphPartRb: out of memory (1)");
270 return (1);
271 }
272 listtab ++; /* TRICK: Trim array so that listtab[-1] is valid */
273 memSet (listtab, ~0, grafptr->partnbr * sizeof (WgraphPartList)); /* Set vertex indices to ~0 */
274
275 datadat.grafptr = &grafptr->s;
276 datadat.frontab = grafptr->frontab; /* Re-use frontier array */
277 datadat.fronnbr = 0;
278 datadat.stratptr = paraptr->stratptr;
279 datadat.mappdat.grafptr = &grafptr->s;
280 datadat.mappdat.parttax = grafptr->parttax; /* Re-use part array */
281 datadat.mappdat.domnmax = grafptr->partnbr + 1;
282 datadat.mappdat.domnnbr = 1;
283
284 SCOTCH_archCmplt ((SCOTCH_Arch *) &archdat, grafptr->partnbr); /* Create a complete graph architecture */
285 datadat.mappdat.archptr = &archdat;
286
287 archDomFrst (datadat.mappdat.archptr, &datadat.mappdat.domnorg); /* Get first domain of architecture */
288 if ((datadat.mappdat.domntab = (ArchDom *) memAlloc ((grafptr->partnbr + 2) * sizeof (ArchDom))) == NULL) {
289 errorPrint ("wgraphPartRb: out of memory (2)");
290 memFree (listtab - 1); /* TRICK: free array using its real beginning */
291 return (1);
292 }
293 datadat.mappdat.domntab[0] = datadat.mappdat.domnorg; /* Set first domain */
294
295 if (wgraphPartRb2 (&datadat, &grafptr->s, NULL, 0, grafptr->s.vertnbr, 0) != 0) {
296 errorPrint ("wgraphPartRb: internal error (1)");
297 return (1);
298 }
299
300 if (grafptr->s.velotax == NULL) { /* Set accesses to optional arrays */
301 velobax = &wgraphpartrbloadone; /* In case vertices not weighted (least often) */
302 velomsk = 0;
303 }
304 else {
305 velobax = grafptr->s.velotax;
306 velomsk = ~((Gnum) 0);
307 }
308
309 compload = grafptr->compload;
310 compsize = grafptr->compsize;
311 memSet (compload, 0, grafptr->partnbr * sizeof (Gnum));
312 memSet (compsize, 0, grafptr->partnbr * sizeof (Gnum));
313
314 parttax = grafptr->parttax;
315 frontab = grafptr->frontab;
316 fronnbr =
317 fronload = 0;
318 for (vertnum = grafptr->s.baseval; vertnum < grafptr->s.vertnnd; vertnum ++) {
319 Gnum partval;
320
321 partval = parttax[vertnum];
322 if (partval >= 0) {
323 compload[partval] += velobax[vertnum & velomsk];
324 compsize[partval] ++;
325 }
326 else { /* Vertex is in separator */
327 Gnum listidx; /* Index of first neighbor part */
328 Gnum edgenum;
329 Gnum veloval;
330
331 frontab[fronnbr ++] = vertnum; /* Add vertex to frontier */
332 fronload += velobax[vertnum & velomsk];
333
334 listidx = -1; /* No neighboring parts recorded yet */
335 listtab[-1].vertnum = vertnum; /* Separator neighbors will not be considered */
336 for (edgenum = verttax[vertnum];
337 edgenum < vendtax[vertnum]; edgenum ++) { /* Compute gain */
338 Gnum vertend;
339 Gnum partend;
340
341 vertend = edgetax[edgenum];
342 partend = parttax[vertend];
343 if (listtab[partend].vertnum != vertnum) { /* If part not yet considered */
344 listtab[partend].vertnum = vertnum; /* Link it in list of neighbors */
345 listtab[partend].nextidx = listidx;
346 listidx = partend;
347 }
348 }
349
350 veloval = velobax[vertnum & velomsk];
351
352 while (listidx != -1) { /* For all neighboring parts found */
353 compload[listidx] += veloval; /* Add load of separator vertex to part */
354 compsize[listidx] ++;
355 listidx = listtab[listidx].nextidx;
356 }
357 }
358 }
359 grafptr->fronnbr = fronnbr;
360 grafptr->fronload = fronload;
361
362 #if 0 /* TODO REMOVE */
363 for (partval = 0; partval < grafptr->partnbr; partval ++)
364 printf("\033[0;33mcompload[%d] %d %d\033[0m\n", partval, grafptr->compload[partval], grafptr->compsize[partval]);
365 #endif
366
367 memFree (datadat.mappdat.domntab); /* Free only newly allocated array of mapping */
368 memFree (listtab - 1); /* TRICK: free array using its real beginning */
369
370 #ifdef SCOTCH_DEBUG_WGRAPH2
371 if (wgraphCheck (grafptr) != 0) {
372 errorPrint ("wgraphPartRb: inconsistent graph data");
373 return (1);
374 }
375 #endif /* SCOTCH_DEBUG_WGRAPH2 */
376
377 return (0);
378 }
379