2 * collectd - src/sn-evolution.c
3 * Copyright (C) 2008,2009 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian octo Forster <octo at verplant.org>
22 #ifndef _ISOC99_SOURCE
23 # define _ISOC99_SOURCE
25 #ifndef _POSIX_C_SOURCE
26 # define _POSIX_C_SOURCE 200112L
34 #include <sys/types.h>
44 #include <population.h>
46 #include "sn_network.h"
47 #include "sn_random.h"
49 #define SNE_MIN(a,b) ((a) < (b) ? (a) : (b))
50 #define SNE_MAX(a,b) ((a) > (b) ? (a) : (b))
52 /* Yes, this is ugly, but the GNU libc doesn't export it with the above flags.
54 char *strdup (const char *s);
56 static uint64_t iteration_counter = 0;
57 static int inputs_num = -1;
59 static int comparators_num = -1;
61 static char *best_output_file = NULL;
63 static int stats_interval = 0;
65 static int max_population_size = 128;
66 static population_t *population;
68 static int evolution_threads_num = 4;
70 static int do_loop = 0;
72 static void sigint_handler (int signal)
75 } /* void sigint_handler */
77 static void exit_usage (const char *name)
79 printf ("Usage: %s [options]\n"
81 "Valid options are:\n"
82 " -i <inputs> Number of inputs\n"
83 " -c <comparators> Number of comparators\n"
84 " -o <file> Write the current best solution to <file>\n"
85 " -p <num> Size of the population (default: 128)\n"
86 " -P <peer> Send individuals to <peer> (may be repeated)\n"
87 " -t <num> Number of threads (default: 4)\n"
91 } /* void exit_usage */
93 int read_options (int argc, char **argv)
97 while ((option = getopt (argc, argv, "i:c:o:p:P:s:t:h")) != -1)
115 comparators_num = tmp;
121 if (best_output_file != NULL)
122 free (best_output_file);
123 best_output_file = strdup (optarg);
129 int tmp = atoi (optarg);
132 max_population_size = tmp;
133 population_set_size (population, (size_t) max_population_size);
142 status = population_add_peer (population, optarg, /* port = */ NULL);
145 fprintf (stderr, "population_add_peer failed with status %i.\n",
153 int tmp = atoi (optarg);
155 stats_interval = tmp;
161 int tmp = atoi (optarg);
163 evolution_threads_num = tmp;
169 exit_usage (argv[0]);
174 } /* int read_options */
176 static int rate_network (sn_network_t *n) /* {{{ */
178 int test_pattern[n->inputs_num];
179 int values[n->inputs_num];
181 int patterns_sorted = 0;
182 int patterns_failed = 0;
184 memset (test_pattern, 0, sizeof (test_pattern));
192 /* Copy the current pattern and let the network sort it */
193 memcpy (values, test_pattern, sizeof (values));
194 status = sn_network_sort (n, values);
198 /* Check if the array is now sorted. */
199 previous = values[0];
201 for (i = 1; i < n->inputs_num; i++)
203 if (previous > values[i])
209 previous = values[i];
215 /* Generate the next test pattern */
217 for (i = 0; i < n->inputs_num; i++)
219 if (test_pattern[i] == 0)
232 /* Break out of the while loop if we tested all possible patterns */
237 /* All tests successfull */
238 return (SN_NETWORK_STAGE_NUM (n) + patterns_failed);
239 } /* }}} int rate_network */
241 static sn_comparator_t get_random_comparator (void) /* {{{ */
245 c.min = sn_bounded_random (0, inputs_num - 1);
247 while (c.max == c.min)
248 c.max = sn_bounded_random (0, inputs_num - 1);
251 } /* }}} sn_comparator_t get_random_comparator */
253 static int mutate_network (sn_comparator_t *comparators, int comparators_num)
257 for (i = 0; i < comparators_num; i++)
258 if (sn_bounded_random (0, 1000000) >= 972655)
259 comparators[i] = get_random_comparator ();
262 } /* int mutate_network */
264 static int create_offspring (void)
267 sn_comparator_t p0_comparators[comparators_num];
268 int p0_comparators_num;
271 sn_comparator_t p1_comparators[comparators_num];
272 int p1_comparators_num;
275 sn_comparator_t n_comparators[comparators_num];
276 int n_comparators_num;
280 p0 = population_get_random (population);
281 p1 = population_get_random (population);
286 p0_comparators_num = 0;
287 for (i = 0; i < SN_NETWORK_STAGE_NUM (p0); i++)
292 s = SN_NETWORK_STAGE_GET (p0, i);
294 for (j = 0; j < SN_STAGE_COMP_NUM (s); j++)
298 c = SN_STAGE_COMP_GET (s, j);
299 p0_comparators[p0_comparators_num] = *c;
300 p0_comparators_num++;
303 while (p0_comparators_num < comparators_num)
305 p0_comparators[p0_comparators_num] = get_random_comparator ();
306 p0_comparators_num++;
308 sn_network_destroy (p0);
311 p1_comparators_num = 0;
312 for (i = 0; i < SN_NETWORK_STAGE_NUM (p1); i++)
317 s = SN_NETWORK_STAGE_GET (p1, i);
319 for (j = 0; j < SN_STAGE_COMP_NUM (s); j++)
323 c = SN_STAGE_COMP_GET (s, j);
324 p1_comparators[p1_comparators_num] = *c;
325 p1_comparators_num++;
328 while (p1_comparators_num < comparators_num)
330 p1_comparators[p1_comparators_num] = get_random_comparator ();
331 p1_comparators_num++;
333 sn_network_destroy (p1);
336 n_comparators_num = sn_bounded_random (SNE_MIN (p0_comparators_num, p1_comparators_num),
337 SNE_MAX (p0_comparators_num, p1_comparators_num));
339 for (i = 0; i < n_comparators_num; i++)
341 if (i >= p0_comparators_num)
342 n_comparators[i] = p1_comparators[i];
343 else if (i >= p1_comparators_num)
344 n_comparators[i] = p0_comparators[i];
345 else if (sn_bounded_random (0, 1) == 0)
346 n_comparators[i] = p1_comparators[i];
348 n_comparators[i] = p0_comparators[i];
352 mutate_network (n_comparators, n_comparators_num);
354 n = sn_network_create (inputs_num);
355 for (i = 0; i < n_comparators_num; i++)
356 sn_network_comparator_add (n, &n_comparators[i]);
358 /* compress the network to get a compact representation */
359 sn_network_compress (n);
361 assert (SN_NETWORK_INPUT_NUM (n) == inputs_num);
363 population_insert (population, n);
365 sn_network_destroy (n);
368 } /* int create_offspring */
370 static void *evolution_thread (void *arg)
375 /* XXX: Not synchronized! */
380 } /* int start_evolution */
382 static int evolution_start (int threads_num)
384 pthread_t threads[threads_num]; /* C99 ftw! */
387 for (i = 0; i < threads_num; i++)
391 status = pthread_create (&threads[i], /* attr = */ NULL,
392 evolution_thread, /* arg = */ NULL);
395 fprintf (stderr, "evolution_start: pthread_create[%i] failed "
415 iter = iteration_counter;
417 n = population_get_fittest (population);
419 rating = rate_network (n);
421 stages_num = SN_NETWORK_STAGE_NUM (n);
423 for (i = 0; i < stages_num; i++)
427 s = SN_NETWORK_STAGE_GET (n, i);
428 comparators_num += SN_STAGE_COMP_NUM (s);
431 sn_network_destroy (n);
433 printf ("Best after approximately %i iterations: "
434 "%i comparators in %i stages. Rating: %i (%i not sorted).\n",
435 iter, comparators_num, stages_num, rating,
436 rating - stages_num);
440 for (i = 0; i < threads_num; i++)
444 pthread_join (threads[i], /* value_ptr = */ NULL);
448 } /* int evolution_start */
450 int main (int argc, char **argv)
452 struct sigaction sigint_action;
453 struct sigaction sigterm_action;
455 population = population_create ((pi_rate_f) rate_network,
456 (pi_copy_f) sn_network_clone,
457 (pi_free_f) sn_network_destroy);
458 if (population == NULL)
460 fprintf (stderr, "population_create failed.\n");
464 population_set_serialization (population,
465 (pi_serialize_f) sn_network_serialize,
466 (pi_unserialize_f) sn_network_unserialize);
468 read_options (argc, argv);
470 if ((inputs_num <= 0) || (comparators_num <= 0))
471 exit_usage (argv[0]);
473 memset (&sigint_action, '\0', sizeof (sigint_action));
474 sigint_action.sa_handler = sigint_handler;
475 sigaction (SIGINT, &sigint_action, NULL);
477 memset (&sigterm_action, '\0', sizeof (sigterm_action));
478 sigterm_action.sa_handler = sigint_handler;
479 sigaction (SIGTERM, &sigterm_action, NULL);
481 population_start_listen_thread (population, NULL, NULL);
487 n = sn_network_create (inputs_num);
488 for (i = 0; i < comparators_num; i++)
492 c = get_random_comparator ();
493 sn_network_comparator_add (n, &c);
496 population_insert (population, n);
497 sn_network_destroy (n);
500 printf ("Current configuration:\n"
501 " Number of inputs: %3i\n"
502 " Number of comparators: %3i\n"
503 " Population size: %3i\n"
504 "=======================\n",
505 inputs_num, comparators_num, max_population_size);
507 evolution_start (evolution_threads_num);
509 printf ("Exiting after %llu iterations.\n",
510 (unsigned long long) iteration_counter);
515 n = population_get_fittest (population);
518 if (best_output_file != NULL)
519 sn_network_write_file (n, best_output_file);
521 sn_network_destroy (n);
525 population_destroy (population);
530 /* vim: set shiftwidth=2 softtabstop=2 : */