David Bernier
2017-06-14 04:39:46 UTC
Tabu Search is a method that can be applied to find
good graph colorings efficiently.
My reference for Tabu Search applied to graph coloring is:
Porumbel, Hao and Kuntz,
"Informed Reactive Tabu Search for Graph Coloring",
on the Web at:
cedric.cnam.fr/~porumbed/papers/irts.pdf
I implemented in the C programming language the Tabu Search algorithm
from Section 2 with the parameters suggested in
5.1.2, so alpha = 0.6 and A = 10.
There are various collections of graphs for
bench-marking graph coloring algorithms.
I used the graph referred to as DSJC125.5.col
with 125 vertices and 3891 edges as shown here:
< http://mat.gsia.cmu.edu/COLOR04/INSTANCES/DSJC125.5.col > .
I adopted Michael Trick's representation , without comments:
The file DSJC125.5.mt looks like this:
125 3891
2 1
3 1
4 1
4 2
4 3
5 1
5 2
5 3
6 1
[ 3881 following lines skipped ]
125 122
------------------------------- test ---------------------------------
$ time ./test45a.out DSJC125.5.mt 17
num_colors = 17 // coloring with at most 17 colors wanted
num_vertex = 125
num_edges = 3891
sum_adj_mat = 7782
First select a random 17 coloring of the 125 vertices...
9 conflicts at 462 iterations
8 conflicts at 471 iterations
7 conflicts at 566 iterations
6 conflicts at 1745 iterations
5 conflicts at 2149 iterations
4 conflicts at 21839 iterations
3 conflicts at 23540 iterations
2 conflicts at 25051 iterations
1 conflicts at 30212 iterations
0 conflicts at 2854777 iterations // after 2.8 million iterations,
// all conditions are satisfied.
real 2m13.898s // time elapsed
---------------------- solution check ------------------------------
$ ./check55a.out DSJC125.5.mt 17
num_colors = 17
num_vertex = 125
num_edges = 3891
sum_adj_mat = 7782
First select a random 17 coloring of the 125 vertices... // input =
Solution...
0 conflicts at 1 iterations
--------------------------------------------------------------------
Solution in file solution17:
1 12
2 15
3 3
4 9
5 8
6 7
7 10
8 14
9 9
10 11
11 2
12 16
13 1
14 8
15 9
16 15
17 4
18 8
19 6
20 9
21 2
22 14
23 10
24 7
25 6
26 3
27 14
28 9
29 13
30 5
31 7
32 7
33 5
34 1
35 12
36 6
37 1
38 16
39 2
40 7
41 10
42 11
43 13
44 5
45 4
46 14
47 16
48 9
49 4
50 17
51 13
52 8
53 9
54 11
55 5
56 3
57 7
58 16
59 5
60 4
61 1
62 17
63 8
64 17
65 12
66 1
67 14
68 17
69 8
70 17
71 13
72 3
73 3
74 12
75 12
76 6
77 15
78 6
79 1
80 9
81 14
82 8
83 16
84 2
85 10
86 4
87 13
88 4
89 12
90 12
91 6
92 15
93 14
94 2
95 17
96 2
97 7
98 3
99 16
100 11
101 1
102 3
103 17
104 10
105 13
106 15
107 15
108 10
109 6
110 16
111 13
112 11
113 4
114 10
115 2
116 5
117 10
118 12
119 14
120 5
121 4
122 7
123 13
124 1
125 2
------------------------------------------------------------------------------------
Source code in test45a.c :
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_VERTEX 1000
#define MAX_COLORS 200
int adj_mat[MAX_VERTEX][MAX_VERTEX];
int Gamma[MAX_VERTEX][MAX_COLORS];
int Fast_Gamma[MAX_VERTEX][MAX_COLORS];
int tabu_list[MAX_VERTEX][MAX_COLORS];
static unsigned long long Q[2097152], carry=0;
unsigned long long B64MWC(void)
{ unsigned long long t,x; static int jm=2097151;
jm=(jm+1)&2097151;
x=Q[jm]; t=(x<<28)+carry;
carry=(x>>36)-(t<x);
return (Q[jm]=t-x);
}
#define CNG ( cng=6906969069ULL*cng+13579 )
#define XS ( xs^=(xs<<13), xs^=(xs>>17), xs^=(xs<<43) )
#define KISS ( B64MWC()+CNG+XS )
int main(int argc, char *argv[] )
{
FILE *in;
unsigned long long im,cng=123456789987654321ULL,
xs=362436069362436069ULL;
unsigned long long mask = 2147483647ULL;
int num_colors;
int num_vertex;
int num_edges;
int num_conflicts;
int k;
int i;
int j;
int sum_adj_mat;
int ru;
int b;
int color;
int init_coloring[MAX_VERTEX];
int conflict_count;
int sum_Gamma;
int best_delta;
int delta;
int best_vertex;
int best_color;
int iter_counter;
int A;
float alpha;
int tl;
int b_tabu_rnd;
int tabu_rand;
int color_tabu;
int min_conflicts;
int job_done;
int differences;
FILE *out;
alpha = 0.6;
A = 10;
job_done = 0;
num_colors = atoi(argv[2]);
printf("num_colors = %d\n" , num_colors);
in = fopen(argv[1], "r");
fscanf(in, "%d %d", &num_vertex, &num_edges);
printf("num_vertex = %d\n", num_vertex);
printf("num_edges = %d\n", num_edges);
for(i = 0 ; i < MAX_VERTEX; i++)
{
for(j = 0 ; j < MAX_VERTEX; j++)
{
adj_mat[i][j] = 0;
}
}
for(k = 0; k < num_edges; k++)
{
fscanf(in, "%d %d", &j, &i);
if( i != j )
{
adj_mat[i-1][j-1] = 1;
adj_mat[j-1][i-1] = 1;
}
if(i == j)
{
printf("warning: edge %d is = %d %d\n", k+1, i, j);
}
}
fclose(in);
sum_adj_mat = 0;
for(i = 0 ; i < num_vertex; i++)
{
for(j = 0 ; j < num_vertex; j++)
{
if( (adj_mat[i][j] == 1) && (i!=j) )
{
sum_adj_mat++;
}
}
}
printf("sum_adj_mat = %d\n", sum_adj_mat);
printf("\n");
while( job_done == 0)
{
for(i = 0 ; i < num_vertex; i++)
{
for(j = 0 ; j < num_colors; j++)
{
tabu_list[i][j] = 0;
}
}
min_conflicts = 1000000;
b_tabu_rnd = ((int) mask)/A;
b_tabu_rnd = b_tabu_rnd + 1;
printf("\n");
printf("First select a random %d coloring of the %d vertices...\n",
num_colors, num_vertex);
b = ((int) mask)/num_colors;
b = b+1;
for(i = 0; i< num_vertex; i++)
{
ru = (int) (KISS&mask);
color = ru/b;
init_coloring[i] = color;
}
for(iter_counter = 1; iter_counter < 10000000; iter_counter++)
{
if( iter_counter == 1)
{
for(i = 0; i < num_vertex; i++)
{
for(j = 0; j < num_colors; j++)
{
conflict_count = 0;
for(k = 0; k< num_vertex; k++)
{
if( (i != k) && (adj_mat[i][k] == 1) && ( j == init_coloring[k]) )
{
conflict_count++;
}
}
Gamma[i][j] = conflict_count;
Fast_Gamma[i][j] = Gamma[i][j];
}
}
}
num_conflicts = 0;
for(i = 0; i < num_vertex; i++)
{
for(j = 0; j < i; j++)
{
if( (adj_mat[i][j] == 1) && ( init_coloring[i]== init_coloring[j]) )
{
num_conflicts++;
}
}
}
if( (num_conflicts < min_conflicts) && (num_conflicts < 10) )
{
min_conflicts = num_conflicts;
printf("%d conflicts at %d iterations\n", num_conflicts, iter_counter);
if(num_conflicts == 0)
{
job_done = 1;
break;
}
}
best_delta = 1000000;
tl = (int) (floor( alpha*((float) num_conflicts) + 0.5));
ru = (int) (KISS&mask);
tabu_rand = ru/b_tabu_rnd;
tabu_rand++;
tl = tl + tabu_rand;
for(i = 0; i < num_vertex; i++)
{
for(j = 0; j < num_colors; j++)
{
if(j != init_coloring[i])
{
delta = Fast_Gamma[i][j] - Fast_Gamma[i][init_coloring[i]];
if( delta < best_delta )
{
if( (tabu_list[i][j] < iter_counter) || ((tabu_list[i][j]
best_vertex = i;
best_color = j;
best_delta = delta;
}
}
}
}
}
color_tabu = init_coloring[best_vertex];
tabu_list[best_vertex][color_tabu] = tl + iter_counter;
init_coloring[best_vertex] = best_color;
for(i = 0; i < num_vertex; i++)
{
if( adj_mat[i][best_vertex] == 1)
{
Fast_Gamma[i][color_tabu] = Fast_Gamma[i][color_tabu]-1;
Fast_Gamma[i][best_color] = Fast_Gamma[i][best_color]+1;
}
}
}
}
out = fopen("solution17", "w");
for(i = 0; i < num_vertex; i++ )
{
fprintf(out, "%d %d\n", i+1, init_coloring[i]+1);
}
fclose(out);
return 0;
}
---------------------------------------------------------------------
David Bernier
good graph colorings efficiently.
My reference for Tabu Search applied to graph coloring is:
Porumbel, Hao and Kuntz,
"Informed Reactive Tabu Search for Graph Coloring",
on the Web at:
cedric.cnam.fr/~porumbed/papers/irts.pdf
I implemented in the C programming language the Tabu Search algorithm
from Section 2 with the parameters suggested in
5.1.2, so alpha = 0.6 and A = 10.
There are various collections of graphs for
bench-marking graph coloring algorithms.
I used the graph referred to as DSJC125.5.col
with 125 vertices and 3891 edges as shown here:
< http://mat.gsia.cmu.edu/COLOR04/INSTANCES/DSJC125.5.col > .
I adopted Michael Trick's representation , without comments:
The file DSJC125.5.mt looks like this:
125 3891
2 1
3 1
4 1
4 2
4 3
5 1
5 2
5 3
6 1
[ 3881 following lines skipped ]
125 122
------------------------------- test ---------------------------------
$ time ./test45a.out DSJC125.5.mt 17
num_colors = 17 // coloring with at most 17 colors wanted
num_vertex = 125
num_edges = 3891
sum_adj_mat = 7782
First select a random 17 coloring of the 125 vertices...
9 conflicts at 462 iterations
8 conflicts at 471 iterations
7 conflicts at 566 iterations
6 conflicts at 1745 iterations
5 conflicts at 2149 iterations
4 conflicts at 21839 iterations
3 conflicts at 23540 iterations
2 conflicts at 25051 iterations
1 conflicts at 30212 iterations
0 conflicts at 2854777 iterations // after 2.8 million iterations,
// all conditions are satisfied.
real 2m13.898s // time elapsed
---------------------- solution check ------------------------------
$ ./check55a.out DSJC125.5.mt 17
num_colors = 17
num_vertex = 125
num_edges = 3891
sum_adj_mat = 7782
First select a random 17 coloring of the 125 vertices... // input =
Solution...
0 conflicts at 1 iterations
--------------------------------------------------------------------
Solution in file solution17:
1 12
2 15
3 3
4 9
5 8
6 7
7 10
8 14
9 9
10 11
11 2
12 16
13 1
14 8
15 9
16 15
17 4
18 8
19 6
20 9
21 2
22 14
23 10
24 7
25 6
26 3
27 14
28 9
29 13
30 5
31 7
32 7
33 5
34 1
35 12
36 6
37 1
38 16
39 2
40 7
41 10
42 11
43 13
44 5
45 4
46 14
47 16
48 9
49 4
50 17
51 13
52 8
53 9
54 11
55 5
56 3
57 7
58 16
59 5
60 4
61 1
62 17
63 8
64 17
65 12
66 1
67 14
68 17
69 8
70 17
71 13
72 3
73 3
74 12
75 12
76 6
77 15
78 6
79 1
80 9
81 14
82 8
83 16
84 2
85 10
86 4
87 13
88 4
89 12
90 12
91 6
92 15
93 14
94 2
95 17
96 2
97 7
98 3
99 16
100 11
101 1
102 3
103 17
104 10
105 13
106 15
107 15
108 10
109 6
110 16
111 13
112 11
113 4
114 10
115 2
116 5
117 10
118 12
119 14
120 5
121 4
122 7
123 13
124 1
125 2
------------------------------------------------------------------------------------
Source code in test45a.c :
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_VERTEX 1000
#define MAX_COLORS 200
int adj_mat[MAX_VERTEX][MAX_VERTEX];
int Gamma[MAX_VERTEX][MAX_COLORS];
int Fast_Gamma[MAX_VERTEX][MAX_COLORS];
int tabu_list[MAX_VERTEX][MAX_COLORS];
static unsigned long long Q[2097152], carry=0;
unsigned long long B64MWC(void)
{ unsigned long long t,x; static int jm=2097151;
jm=(jm+1)&2097151;
x=Q[jm]; t=(x<<28)+carry;
carry=(x>>36)-(t<x);
return (Q[jm]=t-x);
}
#define CNG ( cng=6906969069ULL*cng+13579 )
#define XS ( xs^=(xs<<13), xs^=(xs>>17), xs^=(xs<<43) )
#define KISS ( B64MWC()+CNG+XS )
int main(int argc, char *argv[] )
{
FILE *in;
unsigned long long im,cng=123456789987654321ULL,
xs=362436069362436069ULL;
unsigned long long mask = 2147483647ULL;
int num_colors;
int num_vertex;
int num_edges;
int num_conflicts;
int k;
int i;
int j;
int sum_adj_mat;
int ru;
int b;
int color;
int init_coloring[MAX_VERTEX];
int conflict_count;
int sum_Gamma;
int best_delta;
int delta;
int best_vertex;
int best_color;
int iter_counter;
int A;
float alpha;
int tl;
int b_tabu_rnd;
int tabu_rand;
int color_tabu;
int min_conflicts;
int job_done;
int differences;
FILE *out;
alpha = 0.6;
A = 10;
job_done = 0;
num_colors = atoi(argv[2]);
printf("num_colors = %d\n" , num_colors);
in = fopen(argv[1], "r");
fscanf(in, "%d %d", &num_vertex, &num_edges);
printf("num_vertex = %d\n", num_vertex);
printf("num_edges = %d\n", num_edges);
for(i = 0 ; i < MAX_VERTEX; i++)
{
for(j = 0 ; j < MAX_VERTEX; j++)
{
adj_mat[i][j] = 0;
}
}
for(k = 0; k < num_edges; k++)
{
fscanf(in, "%d %d", &j, &i);
if( i != j )
{
adj_mat[i-1][j-1] = 1;
adj_mat[j-1][i-1] = 1;
}
if(i == j)
{
printf("warning: edge %d is = %d %d\n", k+1, i, j);
}
}
fclose(in);
sum_adj_mat = 0;
for(i = 0 ; i < num_vertex; i++)
{
for(j = 0 ; j < num_vertex; j++)
{
if( (adj_mat[i][j] == 1) && (i!=j) )
{
sum_adj_mat++;
}
}
}
printf("sum_adj_mat = %d\n", sum_adj_mat);
printf("\n");
while( job_done == 0)
{
for(i = 0 ; i < num_vertex; i++)
{
for(j = 0 ; j < num_colors; j++)
{
tabu_list[i][j] = 0;
}
}
min_conflicts = 1000000;
b_tabu_rnd = ((int) mask)/A;
b_tabu_rnd = b_tabu_rnd + 1;
printf("\n");
printf("First select a random %d coloring of the %d vertices...\n",
num_colors, num_vertex);
b = ((int) mask)/num_colors;
b = b+1;
for(i = 0; i< num_vertex; i++)
{
ru = (int) (KISS&mask);
color = ru/b;
init_coloring[i] = color;
}
for(iter_counter = 1; iter_counter < 10000000; iter_counter++)
{
if( iter_counter == 1)
{
for(i = 0; i < num_vertex; i++)
{
for(j = 0; j < num_colors; j++)
{
conflict_count = 0;
for(k = 0; k< num_vertex; k++)
{
if( (i != k) && (adj_mat[i][k] == 1) && ( j == init_coloring[k]) )
{
conflict_count++;
}
}
Gamma[i][j] = conflict_count;
Fast_Gamma[i][j] = Gamma[i][j];
}
}
}
num_conflicts = 0;
for(i = 0; i < num_vertex; i++)
{
for(j = 0; j < i; j++)
{
if( (adj_mat[i][j] == 1) && ( init_coloring[i]== init_coloring[j]) )
{
num_conflicts++;
}
}
}
if( (num_conflicts < min_conflicts) && (num_conflicts < 10) )
{
min_conflicts = num_conflicts;
printf("%d conflicts at %d iterations\n", num_conflicts, iter_counter);
if(num_conflicts == 0)
{
job_done = 1;
break;
}
}
best_delta = 1000000;
tl = (int) (floor( alpha*((float) num_conflicts) + 0.5));
ru = (int) (KISS&mask);
tabu_rand = ru/b_tabu_rnd;
tabu_rand++;
tl = tl + tabu_rand;
for(i = 0; i < num_vertex; i++)
{
for(j = 0; j < num_colors; j++)
{
if(j != init_coloring[i])
{
delta = Fast_Gamma[i][j] - Fast_Gamma[i][init_coloring[i]];
if( delta < best_delta )
{
if( (tabu_list[i][j] < iter_counter) || ((tabu_list[i][j]
= iter_counter)&&(0 == delta + num_conflicts)))
{best_vertex = i;
best_color = j;
best_delta = delta;
}
}
}
}
}
color_tabu = init_coloring[best_vertex];
tabu_list[best_vertex][color_tabu] = tl + iter_counter;
init_coloring[best_vertex] = best_color;
for(i = 0; i < num_vertex; i++)
{
if( adj_mat[i][best_vertex] == 1)
{
Fast_Gamma[i][color_tabu] = Fast_Gamma[i][color_tabu]-1;
Fast_Gamma[i][best_color] = Fast_Gamma[i][best_color]+1;
}
}
}
}
out = fopen("solution17", "w");
for(i = 0; i < num_vertex; i++ )
{
fprintf(out, "%d %d\n", i+1, init_coloring[i]+1);
}
fclose(out);
return 0;
}
---------------------------------------------------------------------
David Bernier