src/sn-evolution.c: Added a first version of evolutionary optimization.
[sort-networks.git] / src / sn-evolution.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <assert.h>
10
11 #include "sn_network.h"
12
13 struct population_entry_s
14 {
15   sn_network_t *network;
16   int rating;
17 };
18 typedef struct population_entry_s population_entry_t;
19
20 static int iterations_num  = 10000;
21 static int max_population_size = 64;
22 static int inputs_num      = 16;
23
24 static population_entry_t *population = NULL;
25 int population_size = 0;
26
27 static int init_random (void)
28 {
29   int fd;
30   unsigned int r;
31
32   fd = open ("/dev/random", O_RDONLY);
33   if (fd < 0)
34   {
35     perror ("open");
36     return (-1);
37   }
38
39   read (fd, (void *) &r, sizeof (r));
40   close (fd);
41
42   srand (r);
43
44   return (0);
45 } /* int init_random */
46
47 static int bounded_random (int upper_bound)
48 {
49   double r = ((double) rand ()) / ((double) RAND_MAX);
50   return ((int) (r * upper_bound));
51 }
52
53 static void exit_usage (const char *name)
54 {
55   printf ("%s <file0>\n", name);
56   exit (1);
57 } /* void exit_usage */
58
59 static int rate_network (const sn_network_t *n)
60 {
61   int rate;
62   int i;
63
64   rate = SN_NETWORK_STAGE_NUM (n) * SN_NETWORK_INPUT_NUM (n);
65   for (i = 0; i < SN_NETWORK_STAGE_NUM (n); i++)
66   {
67     sn_stage_t *s = SN_NETWORK_STAGE_GET (n, i);
68     rate += SN_STAGE_COMP_NUM (s);
69   }
70
71   return (rate);
72 } /* int rate_network */
73
74 static int population_print_stats (int iterations)
75 {
76   int best = -1;
77   int total = 0;
78   int i;
79
80   for (i = 0; i < population_size; i++)
81   {
82     if ((best == -1) || (best > population[i].rating))
83       best = population[i].rating;
84     total += population[i].rating;
85   }
86
87   printf ("Iterations: %6i; Best: %i; Average: %.2f;\n",
88       iterations, best, ((double) total) / ((double) population_size));
89
90   return (0);
91 } /* int population_print_stats */
92
93 static int insert_into_population (sn_network_t *n)
94 {
95   int rating;
96   int i;
97
98   rating = rate_network (n);
99
100   if (population_size < max_population_size)
101   {
102     population[population_size].network = n;
103     population[population_size].rating  = rating;
104     population_size++;
105     return (0);
106   }
107
108   for (i = 0; i < population_size; i++)
109     if (population[i].rating > rating)
110       break;
111
112   if (i < population_size)
113   {
114     sn_network_destroy (population[i].network);
115     population[i].network = n;
116     population[i].rating  = rating;
117   }
118   else
119   {
120     sn_network_destroy (n);
121   }
122
123   return (0);
124 } /* int insert_into_population */
125
126 static int create_offspring (void)
127 {
128   int p0;
129   int p1;
130   sn_network_t *n;
131
132   p0 = bounded_random (population_size);
133   p1 = bounded_random (population_size);
134
135   n = sn_network_combine (population[p0].network, population[p1].network);
136
137   while (SN_NETWORK_INPUT_NUM (n) > inputs_num)
138   {
139     int pos;
140     enum sn_network_cut_dir_e dir;
141
142     pos = bounded_random (SN_NETWORK_INPUT_NUM (n));
143     dir = (bounded_random (2) == 0) ? DIR_MIN : DIR_MAX;
144
145     assert ((pos >= 0) && (pos < SN_NETWORK_INPUT_NUM (n)));
146
147     sn_network_cut_at (n, pos, dir);
148   }
149
150   insert_into_population (n);
151
152   return (0);
153 } /* int create_offspring */
154
155 static int start_evolution (void)
156 {
157   int i;
158
159   for (i = 0; i < iterations_num; i++)
160   {
161     if ((i % 100) == 0)
162       population_print_stats (i);
163
164     create_offspring ();
165   }
166
167   return (0);
168 } /* int start_evolution */
169
170 int main (int argc, char **argv)
171 {
172   if (argc != 2)
173     exit_usage (argv[0]);
174
175   init_random ();
176
177   population = (population_entry_t *) malloc (max_population_size
178       * sizeof (population_entry_t));
179   if (population == NULL)
180   {
181     printf ("Malloc failed.\n");
182     return (-1);
183   }
184   memset (population, '\0', max_population_size
185       * sizeof (population_entry_t));
186
187   {
188     sn_network_t *n = sn_network_read_file (argv[1]);
189     if (n == NULL)
190     {
191       printf ("n == NULL\n");
192       return (1);
193     }
194     population[0].network = n;
195     population[0].rating  = rate_network (n);
196     population_size++;
197   }
198
199   start_evolution ();
200
201   if (0) {
202     int i;
203     for (i = 0; i < population_size; i++)
204     {
205       sn_network_show (population[i].network);
206       printf ("=============\n");
207     }
208   }
209
210   return (0);
211 } /* int main */
212
213 /* vim: set shiftwidth=2 softtabstop=2 : */