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>
46 #include <population.h>
48 #include "sn_network.h"
49 #include "sn_random.h"
51 #define SNE_MIN(a,b) ((a) < (b) ? (a) : (b))
52 #define SNE_MAX(a,b) ((a) > (b) ? (a) : (b))
54 /* Yes, this is ugly, but the GNU libc doesn't export it with the above flags.
56 char *strdup (const char *s);
58 static uint64_t iteration_counter = 0;
59 static int inputs_num = -1;
61 static int comparators_num = -1;
63 static char *best_output_file = NULL;
65 static int stats_interval = 0;
67 static int max_population_size = 128;
68 static population_t *population;
70 static int evolution_threads_num = 4;
72 static int do_loop = 0;
74 static void sigint_handler (int signal)
77 } /* void sigint_handler */
79 static void exit_usage (const char *name)
81 printf ("Usage: %s [options]\n"
83 "Valid options are:\n"
84 " -i <inputs> Number of inputs\n"
85 " -c <comparators> Number of comparators\n"
86 " -o <file> Write the current best solution to <file>\n"
87 " -p <num> Size of the population (default: 128)\n"
88 " -P <peer> Send individuals to <peer> (may be repeated)\n"
89 " -t <num> Number of threads (default: 4)\n"
93 } /* void exit_usage */
95 int read_options (int argc, char **argv)
99 while ((option = getopt (argc, argv, "i:c:o:p:P:s:t:h")) != -1)
117 comparators_num = tmp;
123 if (best_output_file != NULL)
124 free (best_output_file);
125 best_output_file = strdup (optarg);
131 int tmp = atoi (optarg);
134 max_population_size = tmp;
135 population_set_size (population, (size_t) max_population_size);
144 status = population_add_peer (population, optarg, /* port = */ NULL);
147 fprintf (stderr, "population_add_peer failed with status %i.\n",
155 int tmp = atoi (optarg);
157 stats_interval = tmp;
163 int tmp = atoi (optarg);
165 evolution_threads_num = tmp;
171 exit_usage (argv[0]);
176 } /* int read_options */
178 static int rate_network (sn_network_t *n) /* {{{ */
180 int test_pattern[n->inputs_num];
181 int values[n->inputs_num];
183 int patterns_sorted = 0;
184 int patterns_failed = 0;
186 memset (test_pattern, 0, sizeof (test_pattern));
194 /* Copy the current pattern and let the network sort it */
195 memcpy (values, test_pattern, sizeof (values));
196 status = sn_network_sort (n, values);
200 /* Check if the array is now sorted. */
201 previous = values[0];
203 for (i = 1; i < n->inputs_num; i++)
205 if (previous > values[i])
211 previous = values[i];
217 /* Generate the next test pattern */
219 for (i = 0; i < n->inputs_num; i++)
221 if (test_pattern[i] == 0)
234 /* Break out of the while loop if we tested all possible patterns */
239 /* All tests successfull */
240 return (SN_NETWORK_STAGE_NUM (n) + patterns_failed);
241 } /* }}} int rate_network */
243 static sn_comparator_t get_random_comparator (void) /* {{{ */
247 c.min = sn_bounded_random (0, inputs_num - 1);
249 while (c.max == c.min)
250 c.max = sn_bounded_random (0, inputs_num - 1);
253 } /* }}} sn_comparator_t get_random_comparator */
255 static int mutate_network (sn_comparator_t *comparators, int comparators_num)
257 static int old_comparators_num = -1;
258 static int cut_off = 1000000;
262 if (old_comparators_num != comparators_num)
266 p = powl (0.5, (1.0 / ((double) comparators_num)));
267 cut_off = (int) (((double) 1000000) * p);
269 old_comparators_num = comparators_num;
272 for (i = 0; i < comparators_num; i++)
273 if (sn_bounded_random (0, 1000000) >= cut_off)
274 comparators[i] = get_random_comparator ();
277 } /* int mutate_network */
279 static int create_offspring (void)
282 sn_comparator_t p0_comparators[comparators_num];
283 int p0_comparators_num;
286 sn_comparator_t p1_comparators[comparators_num];
287 int p1_comparators_num;
290 sn_comparator_t n_comparators[comparators_num];
291 int n_comparators_num;
295 p0 = population_get_random (population);
296 p1 = population_get_random (population);
301 p0_comparators_num = 0;
302 for (i = 0; i < SN_NETWORK_STAGE_NUM (p0); i++)
307 s = SN_NETWORK_STAGE_GET (p0, i);
309 for (j = 0; j < SN_STAGE_COMP_NUM (s); j++)
313 c = SN_STAGE_COMP_GET (s, j);
314 p0_comparators[p0_comparators_num] = *c;
315 p0_comparators_num++;
318 while (p0_comparators_num < comparators_num)
320 p0_comparators[p0_comparators_num] = get_random_comparator ();
321 p0_comparators_num++;
323 sn_network_destroy (p0);
326 p1_comparators_num = 0;
327 for (i = 0; i < SN_NETWORK_STAGE_NUM (p1); i++)
332 s = SN_NETWORK_STAGE_GET (p1, i);
334 for (j = 0; j < SN_STAGE_COMP_NUM (s); j++)
338 c = SN_STAGE_COMP_GET (s, j);
339 p1_comparators[p1_comparators_num] = *c;
340 p1_comparators_num++;
343 while (p1_comparators_num < comparators_num)
345 p1_comparators[p1_comparators_num] = get_random_comparator ();
346 p1_comparators_num++;
348 sn_network_destroy (p1);
351 n_comparators_num = sn_bounded_random (SNE_MIN (p0_comparators_num, p1_comparators_num),
352 SNE_MAX (p0_comparators_num, p1_comparators_num));
354 for (i = 0; i < n_comparators_num; i++)
356 if (i >= p0_comparators_num)
357 n_comparators[i] = p1_comparators[i];
358 else if (i >= p1_comparators_num)
359 n_comparators[i] = p0_comparators[i];
360 else if (sn_bounded_random (0, 1) == 0)
361 n_comparators[i] = p1_comparators[i];
363 n_comparators[i] = p0_comparators[i];
367 mutate_network (n_comparators, n_comparators_num);
369 n = sn_network_create (inputs_num);
370 for (i = 0; i < n_comparators_num; i++)
371 sn_network_comparator_add (n, &n_comparators[i]);
373 /* compress the network to get a compact representation */
374 sn_network_compress (n);
376 assert (SN_NETWORK_INPUT_NUM (n) == inputs_num);
378 population_insert (population, n);
380 sn_network_destroy (n);
383 } /* int create_offspring */
385 static void *evolution_thread (void *arg)
390 /* XXX: Not synchronized! */
395 } /* int start_evolution */
397 static int evolution_start (int threads_num)
399 pthread_t threads[threads_num]; /* C99 ftw! */
402 for (i = 0; i < threads_num; i++)
406 status = pthread_create (&threads[i], /* attr = */ NULL,
407 evolution_thread, /* arg = */ NULL);
410 fprintf (stderr, "evolution_start: pthread_create[%i] failed "
430 iter = iteration_counter;
432 n = population_get_fittest (population);
434 rating = rate_network (n);
436 stages_num = SN_NETWORK_STAGE_NUM (n);
438 for (i = 0; i < stages_num; i++)
442 s = SN_NETWORK_STAGE_GET (n, i);
443 comparators_num += SN_STAGE_COMP_NUM (s);
446 sn_network_destroy (n);
448 printf ("Best after approximately %i iterations: "
449 "%i comparators in %i stages. Rating: %i (%i not sorted).\n",
450 iter, comparators_num, stages_num, rating,
451 rating - stages_num);
455 for (i = 0; i < threads_num; i++)
459 pthread_join (threads[i], /* value_ptr = */ NULL);
463 } /* int evolution_start */
465 int main (int argc, char **argv)
467 struct sigaction sigint_action;
468 struct sigaction sigterm_action;
470 population = population_create ((pi_rate_f) rate_network,
471 (pi_copy_f) sn_network_clone,
472 (pi_free_f) sn_network_destroy);
473 if (population == NULL)
475 fprintf (stderr, "population_create failed.\n");
479 population_set_serialization (population,
480 (pi_serialize_f) sn_network_serialize,
481 (pi_unserialize_f) sn_network_unserialize);
483 read_options (argc, argv);
485 if ((inputs_num <= 0) || (comparators_num <= 0))
486 exit_usage (argv[0]);
488 memset (&sigint_action, '\0', sizeof (sigint_action));
489 sigint_action.sa_handler = sigint_handler;
490 sigaction (SIGINT, &sigint_action, NULL);
492 memset (&sigterm_action, '\0', sizeof (sigterm_action));
493 sigterm_action.sa_handler = sigint_handler;
494 sigaction (SIGTERM, &sigterm_action, NULL);
496 population_start_listen_thread (population, NULL, NULL);
502 n = sn_network_create (inputs_num);
503 for (i = 0; i < comparators_num; i++)
507 c = get_random_comparator ();
508 sn_network_comparator_add (n, &c);
511 population_insert (population, n);
512 sn_network_destroy (n);
515 printf ("Current configuration:\n"
516 " Number of inputs: %3i\n"
517 " Number of comparators: %3i\n"
518 " Population size: %3i\n"
519 "=======================\n",
520 inputs_num, comparators_num, max_population_size);
522 evolution_start (evolution_threads_num);
524 printf ("Exiting after %llu iterations.\n",
525 (unsigned long long) iteration_counter);
530 n = population_get_fittest (population);
533 if (best_output_file != NULL)
534 sn_network_write_file (n, best_output_file);
536 sn_network_destroy (n);
540 population_destroy (population);
545 /* vim: set shiftwidth=2 softtabstop=2 : */