1
2 /*
3 * This file contains the vertex reordering routines.
4 *
5 * Copyright (C) 2002 Sampo Niskanen, Patric �sterg�rd.
6 * Licensed under the GNU GPL, read the file LICENSE for details.
7 */
8
9 #include "cliquer/reorder.h"
10
11 #include <time.h>
12 #include <sys/times.h>
13 #include <stdlib.h>
14
15 #include <limits.h>
16
17
18 /*
19 * reorder_set()
20 *
21 * Reorders the set s with a function i -> order[i].
22 *
23 * Note: Assumes that order is the same size as SET_MAX_SIZE(s).
24 */
reorder_set(set_t s,int * order)25 void reorder_set(set_t s,int *order) {
26 set_t tmp;
27 int i,j;
28 setelement e;
29
30 ASSERT(reorder_is_bijection(order,SET_MAX_SIZE(s)));
31
32 tmp=set_new(SET_MAX_SIZE(s));
33
34 for (i=0; i<(SET_MAX_SIZE(s)/ELEMENTSIZE); i++) {
35 e=s[i];
36 if (e==0)
37 continue;
38 for (j=0; j<ELEMENTSIZE; j++) {
39 if (e&1) {
40 SET_ADD_ELEMENT(tmp,order[i*ELEMENTSIZE+j]);
41 }
42 e = e>>1;
43 }
44 }
45 if (SET_MAX_SIZE(s)%ELEMENTSIZE) {
46 e=s[i];
47 for (j=0; j<(SET_MAX_SIZE(s)%ELEMENTSIZE); j++) {
48 if (e&1) {
49 SET_ADD_ELEMENT(tmp,order[i*ELEMENTSIZE+j]);
50 }
51 e = e>>1;
52 }
53 }
54 set_copy(s,tmp);
55 set_free(tmp);
56 return;
57 }
58
59
60 /*
61 * reorder_graph()
62 *
63 * Reorders the vertices in the graph with function i -> order[i].
64 *
65 * Note: Assumes that order is of size g->n.
66 */
reorder_graph(graph_t * g,int * order)67 void reorder_graph(graph_t *g, int *order) {
68 int i;
69 set_t *tmp_e;
70 int *tmp_w;
71
72 ASSERT(reorder_is_bijection(order,g->n));
73
74 tmp_e=malloc(g->n * sizeof(set_t));
75 tmp_w=malloc(g->n * sizeof(int));
76 for (i=0; i<g->n; i++) {
77 reorder_set(g->edges[i],order);
78 tmp_e[order[i]]=g->edges[i];
79 tmp_w[order[i]]=g->weights[i];
80 }
81 for (i=0; i<g->n; i++) {
82 g->edges[i]=tmp_e[i];
83 g->weights[i]=tmp_w[i];
84 }
85 free(tmp_e);
86 free(tmp_w);
87 return;
88 }
89
90
91
92 /*
93 * reorder_duplicate()
94 *
95 * Returns a newly allocated duplicate of the given ordering.
96 */
reorder_duplicate(int * order,int n)97 int *reorder_duplicate(int *order,int n) {
98 int *new;
99
100 new=malloc(n*sizeof(int));
101 memcpy(new,order,n*sizeof(int));
102 return new;
103 }
104
105 /*
106 * reorder_invert()
107 *
108 * Inverts the given ordering so that new[old[i]]==i.
109 *
110 * Note: Asserts that order is a bijection.
111 */
reorder_invert(int * order,int n)112 void reorder_invert(int *order,int n) {
113 int *new;
114 int i;
115
116 ASSERT(reorder_is_bijection(order,n));
117
118 new=malloc(n*sizeof(int));
119 for (i=0; i<n; i++)
120 new[order[i]]=i;
121 for (i=0; i<n; i++)
122 order[i]=new[i];
123 free(new);
124 return;
125 }
126
127 /*
128 * reorder_reverse()
129 *
130 * Reverses the given ordering so that new[i] == n-1 - old[i].
131 */
reorder_reverse(int * order,int n)132 void reorder_reverse(int *order,int n) {
133 int i;
134
135 for (i=0; i<n; i++)
136 order[i] = n-1 - order[i];
137 return;
138 }
139
140 /*
141 * reorder_is_bijection
142 *
143 * Checks that an ordering is a bijection {0,...,n-1} -> {0,...,n-1}.
144 *
145 * Returns TRUE if it is a bijection, FALSE otherwise.
146 */
reorder_is_bijection(int * order,int n)147 boolean reorder_is_bijection(int *order,int n) {
148 boolean *used;
149 int i;
150
151 used=calloc(n,sizeof(boolean));
152 for (i=0; i<n; i++) {
153 if (order[i]<0 || order[i]>=n) {
154 free(used);
155 return FALSE;
156 }
157 if (used[order[i]]) {
158 free(used);
159 return FALSE;
160 }
161 used[order[i]]=TRUE;
162 }
163 for (i=0; i<n; i++) {
164 if (!used[i]) {
165 free(used);
166 return FALSE;
167 }
168 }
169 free(used);
170 return TRUE;
171 }
172
173 /*
174 * reorder_ident()
175 *
176 * Returns a newly allocated identity ordering of size n, ie. order[i]==i.
177 */
reorder_ident(int n)178 int *reorder_ident(int n) {
179 int i;
180 int *order;
181
182 order=malloc(n*sizeof(int));
183 for (i=0; i<n; i++)
184 order[i]=i;
185 return order;
186 }
187
188
189
190 /*** Reordering functions for use in clique_options ***/
191
192 /*
193 * reorder_by_ident()
194 *
195 * Returns an identity ordering.
196 */
reorder_by_ident(graph_t * g,boolean weighted)197 int *reorder_by_ident(graph_t *g,boolean weighted) {
198 return reorder_ident(g->n);
199 }
200
201 /*
202 * reorder_by_reverse()
203 *
204 * Returns a reverse identity ordering.
205 */
reorder_by_reverse(graph_t * g,boolean weighted)206 int *reorder_by_reverse(graph_t *g,boolean weighted) {
207 int i;
208 int *order;
209
210 order=malloc(g->n * sizeof(int));
211 for (i=0; i < g->n; i++)
212 order[i]=g->n-i-1;
213 return order;
214 }
215
216 /*
217 * reorder_by_greedy_coloring()
218 *
219 * Equivalent to reorder_by_weighted_greedy_coloring or
220 * reorder_by_unweighted_greedy_coloring according to the value of weighted.
221 */
reorder_by_greedy_coloring(graph_t * g,boolean weighted)222 int *reorder_by_greedy_coloring(graph_t *g,boolean weighted) {
223 if (weighted)
224 return reorder_by_weighted_greedy_coloring(g,weighted);
225 else
226 return reorder_by_unweighted_greedy_coloring(g,weighted);
227 }
228
229
230 /*
231 * reorder_by_unweighted_greedy_coloring()
232 *
233 * Returns an ordering for the graph g by coloring the clique one
234 * color at a time, always adding the vertex of largest degree within
235 * the uncolored graph, and numbering these vertices 0, 1, ...
236 *
237 * Experimentally efficient for use with unweighted graphs.
238 */
reorder_by_unweighted_greedy_coloring(graph_t * g,boolean weighted)239 int *reorder_by_unweighted_greedy_coloring(graph_t *g,boolean weighted) {
240 int i,j,v;
241 boolean *tmp_used;
242 int *degree; /* -1 for used vertices */
243 int *order;
244 int maxdegree,maxvertex=0;
245 boolean samecolor;
246
247 tmp_used=calloc(g->n,sizeof(boolean));
248 degree=calloc(g->n,sizeof(int));
249 order=calloc(g->n,sizeof(int));
250
251 for (i=0; i < g->n; i++) {
252 for (j=0; j < g->n; j++) {
253 ASSERT(!((i==j) && GRAPH_IS_EDGE(g,i,j)));
254 if (GRAPH_IS_EDGE(g,i,j))
255 degree[i]++;
256 }
257 }
258
259 v=0;
260 while (v < g->n) {
261 /* Reset tmp_used. */
262 memset(tmp_used,0,g->n * sizeof(boolean));
263
264 do {
265 /* Find vertex to be colored. */
266 maxdegree=0;
267 samecolor=FALSE;
268 for (i=0; i < g->n; i++) {
269 if (!tmp_used[i] && degree[i] >= maxdegree) {
270 maxvertex=i;
271 maxdegree=degree[i];
272 samecolor=TRUE;
273 }
274 }
275 if (samecolor) {
276 order[v]=maxvertex;
277 degree[maxvertex]=-1;
278 v++;
279
280 /* Mark neighbors not to color with same
281 * color and update neighbor degrees. */
282 for (i=0; i < g->n; i++) {
283 if (GRAPH_IS_EDGE(g,maxvertex,i)) {
284 tmp_used[i]=TRUE;
285 degree[i]--;
286 }
287 }
288 }
289 } while (samecolor);
290 }
291
292 free(tmp_used);
293 free(degree);
294 return order;
295 }
296
297 /*
298 * reorder_by_weighted_greedy_coloring()
299 *
300 * Returns an ordering for the graph g by coloring the clique one
301 * color at a time, always adding the vertex that (in order of importance):
302 * 1. has the minimum weight in the remaining graph
303 * 2. has the largest sum of weights surrounding the vertex
304 *
305 * Experimentally efficient for use with weighted graphs.
306 */
reorder_by_weighted_greedy_coloring(graph_t * g,boolean weighted)307 int *reorder_by_weighted_greedy_coloring(graph_t *g, boolean weighted) {
308 int i,j,p=0;
309 int cnt;
310 int *nwt; /* Sum of surrounding vertices' weights */
311 int min_wt,max_nwt;
312 boolean *used;
313 int *order;
314
315 nwt=malloc(g->n * sizeof(int));
316 order=malloc(g->n * sizeof(int));
317 used=calloc(g->n,sizeof(boolean));
318
319 for (i=0; i < g->n; i++) {
320 nwt[i]=0;
321 for (j=0; j < g->n; j++)
322 if (GRAPH_IS_EDGE(g, i, j))
323 nwt[i] += g->weights[j];
324 }
325
326 for (cnt=0; cnt < g->n; cnt++) {
327 min_wt=INT_MAX;
328 max_nwt=-1;
329 for (i=g->n-1; i>=0; i--)
330 if ((!used[i]) && (g->weights[i] < min_wt))
331 min_wt=g->weights[i];
332 for (i=g->n-1; i>=0; i--) {
333 if (used[i] || (g->weights[i] > min_wt))
334 continue;
335 if (nwt[i] > max_nwt) {
336 max_nwt=nwt[i];
337 p=i;
338 }
339 }
340 order[cnt]=p;
341 used[p]=TRUE;
342 for (j=0; j < g->n; j++)
343 if ((!used[j]) && (GRAPH_IS_EDGE(g, p, j)))
344 nwt[j] -= g->weights[p];
345 }
346
347 free(nwt);
348 free(used);
349
350 ASSERT(reorder_is_bijection(order,g->n));
351
352 return order;
353 }
354
355 /*
356 * reorder_by_degree()
357 *
358 * Returns a reordering of the graph g so that the vertices with largest
359 * degrees (most neighbors) are first.
360 */
reorder_by_degree(graph_t * g,boolean weighted)361 int *reorder_by_degree(graph_t *g, boolean weighted) {
362 int i,j,v;
363 int *degree;
364 int *order;
365 int maxdegree,maxvertex=0;
366
367 degree=calloc(g->n,sizeof(int));
368 order=calloc(g->n,sizeof(int));
369
370 for (i=0; i < g->n; i++) {
371 for (j=0; j < g->n; j++) {
372 ASSERT(!((i==j) && GRAPH_IS_EDGE(g,i,j)));
373 if (GRAPH_IS_EDGE(g,i,j))
374 degree[i]++;
375 }
376 }
377
378 for (v=0; v < g->n; v++) {
379 maxdegree=0;
380 for (i=0; i < g->n; i++) {
381 if (degree[i] >= maxdegree) {
382 maxvertex=i;
383 maxdegree=degree[i];
384 }
385 }
386 order[v]=maxvertex;
387 degree[maxvertex]=-1; /* used */
388 /*** Max. degree withing unselected graph:
389 for (i=0; i < g->n; i++) {
390 if (GRAPH_IS_EDGE(g,maxvertex,i))
391 degree[i]--;
392 }
393 ***/
394 }
395
396 free(degree);
397 return order;
398 }
399
400 /*
401 * reorder_by_random()
402 *
403 * Returns a random reordering for graph g.
404 * Note: Used the functions rand() and srand() to generate the random
405 * numbers. srand() is re-initialized every time reorder_by_random()
406 * is called using the system time.
407 */
reorder_by_random(graph_t * g,boolean weighted)408 int *reorder_by_random(graph_t *g, boolean weighted) {
409 struct tms t;
410 int i,r;
411 int *new;
412 boolean *used;
413
414 srand(times(&t)+time(NULL));
415
416 new=calloc(g->n, sizeof(int));
417 used=calloc(g->n, sizeof(boolean));
418 for (i=0; i < g->n; i++) {
419 do {
420 r=rand() % g->n;
421 } while (used[r]);
422 new[i]=r;
423 used[r]=TRUE;
424 }
425 free(used);
426 return new;
427 }
428
429