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