1 /*****************************************************************************
2 /
3 / SPACE (SPArse Cholesky Elimination) Library: nestdiss.c
4 /
5 / author J"urgen Schulze, University of Paderborn
6 / created 00dec29
7 /
8 / This file contains functions dealing with the rec. nested dissection object
9 /
10 ******************************************************************************
11
12 Data type: struct nestdiss
13 graph_t *G; pointer to original graph
14 int *map; maps nodes of G to constructed subgraph
15 int depth; depth in nested dissection tree
16 int nvint; number of vertices in subgraph
17 int *intvertex; internal vertices of subgraph
18 int *intcolor; color of vertices in intvertex
19 int cwght[3]; weights of bisection
20 struct nestdiss *parent; pointer to parent nd node
21 struct nestdiss *childB; pointer to black descendant nd node
22 struct nestdiss *childW; pointer to white descendand nd node
23 Comments:
24 o Structure used to build the nested dissection tree. Vector intvertex
25 holds the vertices of the subgraph to be partitioned. Once a separator
26 has been computed, the coloring of vertex u = intvertex[i] is stored in
27 vector intcolor[i] and the partition weights are stored in cwght[GRAY],
28 cwght[BLACK], and cwght[WHITE].
29 o Structure does not own graph object G => it will not be freed
30 Note: G is the original graph
31 o Structure does not own map array => it will not be freed
32 Note: map is a "global" array that is used when constructing the subgraph
33 induced by the vertices in intvertex. The array maps the vertices
34 of the original graph G to the vertices of the subgraph.
35 Methods in lib/nestdiss.c:
36 - nd = newNDnode(graph_t *G, int *map, int nvint);
37 o Initial: depth = 0, cwght[GRAY] = cwght[BLACK] = cwght[WHITE] = 0,
38 and parent = childB = childW = NULL;
39 - void freeNDnode(nestdiss_t *nd);
40 - ndroot = setupNDroot(graph_t *G, int *map);
41 o sets up the root of the nested dissection tree; the function first
42 calls newNDnode to allocate memory for ndroot and, then, sets
43 intvertex[i] = i for all 0 <= i < G->nvtx
44 - void splitNDnode(nestdiss_t *nd, options_t *options, timings_t *cpus);
45 o constructs the subgraph induced by nd->intvertex and computes a
46 bisection for it by calling constructSeparator and smoothSeparator.
47 Then, the nd object is splitted in a black one that holds the black
48 partition and a white one that holds the white partition.
49 o used options: (see constructSeparator and smoothSeparator)
50 OPTION_MSGLVL, OPTION_NODE_SELECTION3
51 o returned timings: (also see constructSeparator)
52 TIME_INITDOMDEC, TIME_COARSEDOMDEC, TIME_INITSEP, TIME_REFINESEP
53 TIME_MULTILEVEL, TIME_SMOOTH
54 - void buildNDtree(nestdiss_t *ndroot, options_t *options, timings_t *cpus);
55 o builds the nested dissection tree under root ndroot, i.e. it applies
56 the nested dissection process to the (sub)graph induced by
57 ndroot->intvertex by iteratively calling function splitNDnode.
58 o used options: (also see splitNDnode)
59 OPTION_DOMAIN_SIZE, OPTION_MSGLVL, OPTION_NODE_SELECTION3
60 o returned timings: (see splitNDnode)
61 TIME_INITDOMDEC, TIME_COARSEDOMDEC, TIME_INITSEP, TIME_REFINESEP
62 TIME_MULTILEVEL, TIME_SMOOTH
63 - void freeNDtree(nestdiss_t *ndroot);
64 o removes the nested dissection tree under root ndroot
65 Note: ndroot is not freed
66
67 ******************************************************************************/
68
69 #include <space.h>
70
71
72 /*****************************************************************************
73 ******************************************************************************/
74 nestdiss_t*
newNDnode(graph_t * G,PORD_INT * map,PORD_INT nvint)75 newNDnode(graph_t *G, PORD_INT *map, PORD_INT nvint)
76 { nestdiss_t *nd;
77
78 mymalloc(nd, 1, nestdiss_t);
79 mymalloc(nd->intvertex, nvint, PORD_INT);
80 mymalloc(nd->intcolor, nvint, PORD_INT);
81
82 nd->G = G;
83 nd->map = map;
84 nd->depth = 0;
85 nd->nvint = nvint;
86 nd->cwght[GRAY] = nd->cwght[BLACK] = nd->cwght[WHITE] = 0;
87 nd->parent = nd->childB = nd->childW = NULL;
88
89 return(nd);
90 }
91
92
93 /*****************************************************************************
94 ******************************************************************************/
95 void
freeNDnode(nestdiss_t * nd)96 freeNDnode(nestdiss_t *nd)
97 {
98 free(nd->intvertex);
99 free(nd->intcolor);
100 free(nd);
101 }
102
103
104 /*****************************************************************************
105 ******************************************************************************/
106 nestdiss_t*
setupNDroot(graph_t * G,PORD_INT * map)107 setupNDroot(graph_t *G, PORD_INT *map)
108 { nestdiss_t *ndroot;
109 PORD_INT *intvertex, nvtx, i;
110
111 nvtx = G->nvtx;
112 ndroot = newNDnode(G, map, nvtx);
113 intvertex = ndroot->intvertex;
114
115 for (i = 0; i < nvtx; i++)
116 intvertex[i] = i;
117
118 return(ndroot);
119 }
120
121
122 /*****************************************************************************
123 ******************************************************************************/
124 void
splitNDnode(nestdiss_t * nd,options_t * options,timings_t * cpus)125 splitNDnode(nestdiss_t *nd, options_t *options, timings_t *cpus)
126 { nestdiss_t *b_nd, *w_nd;
127 graph_t *Gsub;
128 gbisect_t *Gbisect;
129 PORD_INT *map, *intvertex, *intcolor, *b_intvertex, *w_intvertex;
130 PORD_INT nvint, b_nvint, w_nvint, u, i;
131
132 map = nd->map;
133 nvint = nd->nvint;
134 intvertex = nd->intvertex;
135 intcolor = nd->intcolor;
136
137 /* -------------------------------------------------------------
138 extract the subgraph for which a bisection has to be computed
139 ------------------------------------------------------------- */
140 if (nd->G->nvtx == nd->nvint)
141 { Gsub = nd->G; /* a hack to save time and space */
142 for (u = 0; u < nd->nvint; u++) /* but do not forget the map vector */
143 map[u] = u;
144 }
145 else
146 Gsub = setupSubgraph(nd->G, intvertex, nvint, map);
147 Gbisect = newGbisect(Gsub);
148
149 /* ---------------------------------
150 compute the bisection for Gbisect
151 --------------------------------- */
152 pord_starttimer(cpus[TIME_MULTILEVEL]);
153 constructSeparator(Gbisect, options, cpus);
154 pord_stoptimer(cpus[TIME_MULTILEVEL]);
155
156 pord_starttimer(cpus[TIME_SMOOTH]);
157 if (Gbisect->cwght[GRAY] > 0)
158 smoothSeparator(Gbisect, options);
159 pord_stoptimer(cpus[TIME_SMOOTH]);
160
161 /* ----------------------------------------
162 copy the bisection back to the nd object
163 ---------------------------------------- */
164 b_nvint = w_nvint = 0;
165 nd->cwght[GRAY] = Gbisect->cwght[GRAY];
166 nd->cwght[BLACK] = Gbisect->cwght[BLACK];
167 nd->cwght[WHITE] = Gbisect->cwght[WHITE];
168 for (i = 0; i < nvint; i++)
169 { u = intvertex[i];
170 intcolor[i] = Gbisect->color[map[u]];
171 switch(intcolor[i])
172 { case GRAY: break;
173 case BLACK: b_nvint++; break;
174 case WHITE: w_nvint++; break;
175 default:
176 fprintf(stderr, "\nError in function splitNDnode\n"
177 " node %d has unrecognized color %d\n", u, intcolor[i]);
178 quit();
179 }
180 }
181
182 /* ------------------------------------------------------
183 and now split the nd object according to the bisection
184 ------------------------------------------------------ */
185 b_nd = newNDnode(nd->G, map, b_nvint);
186 b_intvertex = b_nd->intvertex;
187 w_nd = newNDnode(nd->G, map, w_nvint);
188 w_intvertex = w_nd->intvertex;
189
190 b_nvint = w_nvint = 0;
191 for (i = 0; i < nvint; i++)
192 { u = intvertex[i];
193 if (intcolor[i] == BLACK) b_intvertex[b_nvint++] = u;
194 if (intcolor[i] == WHITE) w_intvertex[w_nvint++] = u;
195 }
196 nd->childB = b_nd; b_nd->parent = nd;
197 nd->childW = w_nd; w_nd->parent = nd;
198 b_nd->depth = nd->depth + 1;
199 w_nd->depth = nd->depth + 1;
200
201 /* -----------------
202 free the subgraph
203 ----------------- */
204 if (Gsub != nd->G)
205 freeGraph(Gsub);
206 freeGbisect(Gbisect);
207 }
208
209
210 /*****************************************************************************
211 ******************************************************************************/
212 void
buildNDtree(nestdiss_t * ndroot,options_t * options,timings_t * cpus)213 buildNDtree(nestdiss_t *ndroot, options_t *options, timings_t *cpus)
214 { nestdiss_t *nd;
215 nestdiss_t *queue[2*MAX_SEPS+1];
216 PORD_INT maxseps, seps, domainsize, qhead, qtail;
217
218 maxseps = MAX_SEPS;
219 domainsize = options[OPTION_DOMAIN_SIZE];
220 if (domainsize == 1) maxseps = DEFAULT_SEPS; /* secret switch */
221
222 /* --------------------------------------------------
223 build the nested dissection tree under root ndroot
224 -------------------------------------------------- */
225 queue[0] = ndroot;
226 qhead = 0; qtail = 1; seps = 0;
227 while ((qhead != qtail) && (seps < maxseps))
228 { seps++;
229 nd = queue[qhead++];
230
231 splitNDnode(nd, options, cpus);
232 if ((nd->childB == NULL) || (nd->childW == NULL))
233 { fprintf(stderr, "\nError in function buildNDtree\n"
234 " recursive nested dissection process failed\n");
235 quit();
236 }
237
238 if (options[OPTION_MSGLVL] > 1)
239 printf("%4d. S %6d, B %6d, W %6d [bal %4.2f, rel %6.4f, cost %7.2f]\n",
240 seps, nd->cwght[GRAY], nd->cwght[BLACK], nd->cwght[WHITE],
241 (FLOAT)min(nd->cwght[BLACK], nd->cwght[WHITE])
242 / max(nd->cwght[BLACK], nd->cwght[WHITE]),
243 (FLOAT)nd->cwght[GRAY]
244 / (nd->cwght[GRAY] + nd->cwght[BLACK] + nd->cwght[WHITE]),
245 F(nd->cwght[GRAY], nd->cwght[BLACK], nd->cwght[WHITE]));
246
247 if ((nd->childB->nvint > MIN_NODES)
248 && ((nd->cwght[BLACK] > domainsize) || (qtail < DEFAULT_SEPS)))
249 queue[qtail++] = nd->childB;
250 if ((nd->childW->nvint > MIN_NODES)
251 && ((nd->cwght[WHITE] > domainsize) || (qtail < DEFAULT_SEPS)))
252 queue[qtail++] = nd->childW;
253 }
254 }
255
256
257 /*****************************************************************************
258 ******************************************************************************/
259 void
freeNDtree(nestdiss_t * ndroot)260 freeNDtree(nestdiss_t *ndroot)
261 { nestdiss_t *nd, *parent;
262
263 /* ------------------------------------------------------
264 to remove the nested dissection tree under root ndroot
265 visit the nodes in post-order
266 ------------------------------------------------------ */
267 for (nd = ndroot; nd->childB != NULL; nd = nd->childB);
268 while (nd != ndroot)
269 { parent = nd->parent;
270 if ((parent == NULL) || (parent->childB == NULL)
271 || (parent->childW == NULL))
272 { fprintf(stderr, "\nError in function removeNDtree\n"
273 " nested dissection tree corrupted\n");
274 quit();
275 }
276 if (parent->childB == nd) /* left subtree of parent visited */
277 { freeNDnode(nd); /* free root of left subtree and goto right */
278 for (nd = parent->childW; nd->childB != NULL; nd = nd->childB);
279 }
280 else /* right subtree of parent visited */
281 { freeNDnode(nd); /* free root of right subtree and goto parent */
282 nd = parent;
283 }
284 }
285 }
286