2 * libsortnetwork - src/sn-evolution-cut.c
3 * Copyright (C) 2008-2010 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 <ff at octo.it>
30 #include <sys/types.h>
41 #include <population.h>
43 #include "sn_network.h"
44 #include "sn_random.h"
46 #if !defined(__GNUC__) || !__GNUC__
47 # define __attribute__(x) /**/
50 typedef int individuum_t;
52 static int inputs_num = 0;
53 static int outputs_num = 0;
54 static int cuts_num = 0;
56 static char *initial_input_file = NULL;
57 static const sn_network_t *initial_network = NULL;
58 static char *best_output_file = NULL;
60 static int stats_interval = 0;
62 static int max_population_size = 128;
63 static population_t *population = NULL;
65 static int evolution_threads_num = 4;
67 static int do_loop = 0;
68 static uint64_t iteration_counter = 0;
69 static uint64_t max_iterations = 0;
71 static int target_rating = 0;
73 static void sigint_handler (int signal __attribute__((unused)))
76 } /* void sigint_handler */
78 static void exit_usage (const char *name)
80 printf ("Usage: %s [options]\n"
82 "Valid options are:\n"
83 " -i <file> Initial input file (REQUIRED)\n"
84 " -o <file> Write the current best solution to <file>\n"
85 " -O <num> Number of outputs (default: inputs / 2)\n"
86 " -p <num> Size of the population (default: 128)\n"
87 " -P <peer> Send individuals to <peer> (may be repeated)\n"
88 " -t <num> Number of threads (default: 4)\n"
89 " -n <num> Maximum number of steps (iterations) to perform\n"
90 " -r <num> Target rating: Stop loop when rating is less then or equal\n"
95 } /* void exit_usage */
97 int read_options (int argc, char **argv) /* {{{ */
101 while ((option = getopt (argc, argv, "i:o:O:p:P:s:t:n:r:h")) != -1)
107 if (initial_input_file != NULL)
108 free (initial_input_file);
109 initial_input_file = strdup (optarg);
115 if (best_output_file != NULL)
116 free (best_output_file);
117 best_output_file = strdup (optarg);
123 int tmp = atoi (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;
172 max_iterations = (uint64_t) strtoull (optarg,
177 fprintf (stderr, "Parsing integer argument failed: %s\n",
179 exit_usage (argv[0]);
186 int tmp = atoi (optarg);
194 exit_usage (argv[0]);
199 } /* }}} int read_options */
201 static int rate_network (const sn_network_t *n) /* {{{ */
205 rate = SN_NETWORK_STAGE_NUM (n) * SN_NETWORK_INPUT_NUM (n)
206 + sn_network_get_comparator_num (n);
209 } /* }}} int rate_network */
211 static sn_network_t *individuum_to_network (const individuum_t *ind) /* {{{ */
214 int mask[SN_NETWORK_INPUT_NUM (initial_network)];
216 memcpy (mask, ind, sizeof (mask));
218 n = sn_network_clone (initial_network);
222 sn_network_cut (n, mask);
224 sn_network_normalize (n);
225 sn_network_compress (n);
228 } /* }}} sn_network_t *individuum_to_network */
230 static int ind_rate (const void *arg) /* {{{ */
235 n = individuum_to_network (arg);
239 status = rate_network (n);
240 sn_network_destroy (n);
243 } /* }}} int ind_rate */
245 static void *ind_copy (const void *in) /* {{{ */
247 size_t s = sizeof (individuum_t) * inputs_num;
256 } /* }}} void *ind_copy */
258 static void ind_free (void *ind) /* {{{ */
262 } /* }}} void ind_free */
264 static void ind_print (const individuum_t *ind) /* {{{ */
268 for (i = 0; i < inputs_num; i++)
270 printf ("%3i: %s\n", i, (ind[i] == 0) ? "-" :
271 (ind[i] < 0) ? "MIN" : "MAX");
275 for (i = 0; i < inputs_num; i++)
279 printf (" %i:%s", i, (ind[i] < 0) ? "MIN" : "MAX");
282 } /* }}} void ind_print */
284 /* Simply makes sure the right amount of cutting positions exist. */
285 static void mutate (individuum_t *ind, int this_cuts_num) /* {{{ */
289 if (this_cuts_num < 0)
292 for (i = 0; i < inputs_num; i++)
297 while (this_cuts_num != cuts_num)
299 i = sn_bounded_random (0, inputs_num - 1);
301 if ((this_cuts_num < cuts_num)
304 ind[i] = (sn_bounded_random (0, 1) * 2) - 1;
305 assert (ind[i] != 0);
308 else if ((this_cuts_num > cuts_num)
315 } /* }}} void mutate */
317 static individuum_t *recombine (individuum_t *i0, individuum_t *i1) /* {{{ */
319 individuum_t *offspring;
323 if ((i0 == NULL) || (i1 == NULL))
326 offspring = malloc (sizeof (*offspring) * inputs_num);
327 if (offspring == NULL)
329 memset (offspring, 0, sizeof (*offspring) * inputs_num);
332 for (i = 0; i < this_cuts_num; i++)
334 if (sn_bounded_random (0, 1) == 0)
335 offspring[i] = i0[i];
337 offspring[i] = i1[i];
339 if (offspring[i] != 0)
343 mutate (offspring, this_cuts_num);
346 } /* }}} individuum_t *recombine */
348 static int create_offspring (void) /* {{{ */
354 i0 = population_get_random (population);
355 i1 = population_get_random (population);
357 i2 = recombine (i0, i1);
359 population_insert (population, i2);
366 } /* }}} int create_offspring */
368 static void *evolution_thread (void *arg __attribute__((unused))) /* {{{ */
373 /* XXX: Not synchronized! */
378 } /* }}} int start_evolution */
380 static int evolution_start (int threads_num) /* {{{ */
382 pthread_t threads[threads_num]; /* C99 ftw! */
385 for (i = 0; i < threads_num; i++)
389 status = pthread_create (&threads[i], /* attr = */ NULL,
390 evolution_thread, /* arg = */ NULL);
393 fprintf (stderr, "evolution_start: pthread_create[%i] failed "
414 iter = iteration_counter;
416 ind = population_get_fittest (population);
417 n = individuum_to_network (ind);
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);
434 printf ("Best after approximately %i iterations: "
435 "%i comparators in %i stages. Rating: %i.\n",
436 iter, comparators_num, stages_num, rating);
438 if ((target_rating > 0) && (rating <= target_rating))
442 if ((max_iterations > 0) && (iteration_counter >= max_iterations))
446 for (i = 0; i < threads_num; i++)
450 pthread_join (threads[i], /* value_ptr = */ NULL);
454 } /* }}} int evolution_start */
456 int main (int argc, char **argv) /* {{{ */
458 struct sigaction sigint_action;
459 struct sigaction sigterm_action;
462 population = population_create (ind_rate, ind_copy, ind_free);
463 if (population == NULL)
465 fprintf (stderr, "population_create failed.\n");
470 population_set_serialization (population,
471 (pi_serialize_f) sn_network_serialize,
472 (pi_unserialize_f) sn_network_unserialize);
475 read_options (argc, argv);
476 if (initial_input_file == NULL)
477 exit_usage (argv[0]);
479 memset (&sigint_action, '\0', sizeof (sigint_action));
480 sigint_action.sa_handler = sigint_handler;
481 sigaction (SIGINT, &sigint_action, NULL);
483 memset (&sigterm_action, '\0', sizeof (sigterm_action));
484 sigterm_action.sa_handler = sigint_handler;
485 sigaction (SIGTERM, &sigterm_action, NULL);
487 /* population_start_listen_thread (population, NULL, NULL); */
489 initial_network = sn_network_read_file (initial_input_file);
490 if (initial_network == NULL)
492 fprintf (stderr, "Reading input file failed.\n");
496 inputs_num = SN_NETWORK_INPUT_NUM(initial_network);
497 if (outputs_num == 0)
498 outputs_num = inputs_num / 2;
500 if (outputs_num >= inputs_num)
502 fprintf (stderr, "Number of inputs (%i) is smaller than "
503 "(or equal to) the number of outputs (%i).\n",
504 inputs_num, outputs_num);
508 cuts_num = inputs_num - outputs_num;
509 assert (cuts_num >= 1);
511 for (i = 0; i < max_population_size; i++)
512 { /* create a random initial individuum */
515 ind = calloc (inputs_num, sizeof (*ind));
518 fprintf (stderr, "calloc failed.\n");
521 mutate (ind, /* num cuts = */ 0);
523 population_insert (population, ind);
527 printf ("Current configuration:\n"
528 " Initial network: %s\n"
529 " Number of inputs: %3i\n"
530 " Number of outputs: %3i\n"
531 " Population size: %3i\n"
532 "=======================\n",
533 initial_input_file, inputs_num, outputs_num, max_population_size);
535 evolution_start (evolution_threads_num);
537 printf ("Exiting after %"PRIu64" iterations.\n",
544 ind = population_get_fittest (population);
547 n = individuum_to_network (ind);
548 if (best_output_file != NULL)
549 sn_network_write_file (n, best_output_file);
551 sn_network_destroy (n);
558 population_destroy (population);
563 /* vim: set shiftwidth=2 softtabstop=2 et fdm=marker : */