From 927c3f062bda3494fbbd5803c5d08c3552138b89 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Wed, 11 Mar 2009 11:21:37 +0100 Subject: [PATCH] src/sn-evolution2: Added a true random evolutionary algorithm. --- src/Makefile | 6 + src/sn-evolution2.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sn_network.c | 41 ++++ src/sn_network.h | 4 + 4 files changed, 582 insertions(+) create mode 100644 src/sn-evolution2.c diff --git a/src/Makefile b/src/Makefile index 135e30e..4b1e438 100644 --- a/src/Makefile +++ b/src/Makefile @@ -38,6 +38,12 @@ sn-evolution: CFLAGS += $(POPULATION_CFLAGS) sn-evolution: LDFLAGS += $(POPULATION_LDFLAGS) sn-evolution: sn-evolution.c sn_network.o sn_stage.o sn_comparator.o sn_population.o sn_random.o +sn-evolution2: CFLAGS += $(POPULATION_CFLAGS) +sn-evolution2: LDFLAGS += $(POPULATION_LDFLAGS) +sn-evolution2: sn-evolution2.c sn_network.o sn_stage.o sn_comparator.o sn_population.o sn_random.o + +sn-find-9: sn-find-9.c sn_network.o sn_stage.o sn_comparator.o sn_random.o + sn-merge: sn-merge.c sn_network.o sn_stage.o sn_comparator.o sn_random.o sn-normalize: sn-normalize.c sn_network.o sn_stage.o sn_comparator.o sn_random.o diff --git a/src/sn-evolution2.c b/src/sn-evolution2.c new file mode 100644 index 0000000..b5beca4 --- /dev/null +++ b/src/sn-evolution2.c @@ -0,0 +1,531 @@ +/** + * collectd - src/sn-evolution.c + * Copyright (C) 2008,2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#ifndef _ISOC99_SOURCE +# define _ISOC99_SOURCE +#endif +#ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "sn_network.h" +#include "sn_random.h" + +#define SNE_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define SNE_MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* Yes, this is ugly, but the GNU libc doesn't export it with the above flags. + * */ +char *strdup (const char *s); + +static uint64_t iteration_counter = 0; +static int inputs_num = -1; + +static int comparators_num = -1; + +static char *best_output_file = NULL; + +static int stats_interval = 0; + +static int max_population_size = 128; +static population_t *population; + +static int evolution_threads_num = 4; + +static int do_loop = 0; + +static void sigint_handler (int signal) +{ + do_loop++; +} /* void sigint_handler */ + +static void exit_usage (const char *name) +{ + printf ("Usage: %s [options]\n" + "\n" + "Valid options are:\n" + " -i Number of inputs\n" + " -c Number of comparators\n" + " -o Write the current best solution to \n" + " -p Size of the population (default: 128)\n" + " -P Send individuals to (may be repeated)\n" + " -t Number of threads (default: 4)\n" + "\n", + name); + exit (1); +} /* void exit_usage */ + +int read_options (int argc, char **argv) +{ + int option; + + while ((option = getopt (argc, argv, "i:c:o:p:P:s:t:h")) != -1) + { + switch (option) + { + case 'i': + { + int tmp; + tmp = atoi (optarg); + if (tmp > 0) + inputs_num = tmp; + break; + } + + case 'c': + { + int tmp; + tmp = atoi (optarg); + if (tmp > 0) + comparators_num = tmp; + break; + } + + case 'o': + { + if (best_output_file != NULL) + free (best_output_file); + best_output_file = strdup (optarg); + break; + } + + case 'p': + { + int tmp = atoi (optarg); + if (tmp > 0) + { + max_population_size = tmp; + population_set_size (population, (size_t) max_population_size); + } + break; + } + + case 'P': + { + int status; + + status = population_add_peer (population, optarg, /* port = */ NULL); + if (status != 0) + { + fprintf (stderr, "population_add_peer failed with status %i.\n", + status); + } + break; + } + + case 's': + { + int tmp = atoi (optarg); + if (tmp > 0) + stats_interval = tmp; + break; + } + + case 't': + { + int tmp = atoi (optarg); + if (tmp >= 1) + evolution_threads_num = tmp; + break; + } + + case 'h': + default: + exit_usage (argv[0]); + } + } + + return (0); +} /* int read_options */ + +static int rate_network (sn_network_t *n) /* {{{ */ +{ + int test_pattern[n->inputs_num]; + int values[n->inputs_num]; + + int patterns_sorted = 0; + int patterns_failed = 0; + + memset (test_pattern, 0, sizeof (test_pattern)); + while (42) + { + int previous; + int overflow; + int status; + int i; + + /* Copy the current pattern and let the network sort it */ + memcpy (values, test_pattern, sizeof (values)); + status = sn_network_sort (n, values); + if (status != 0) + return (status); + + /* Check if the array is now sorted. */ + previous = values[0]; + status = 0; + for (i = 1; i < n->inputs_num; i++) + { + if (previous > values[i]) + { + patterns_failed++; + status = -1; + break; + } + previous = values[i]; + } + + if (status == 0) + patterns_sorted++; + + /* Generate the next test pattern */ + overflow = 1; + for (i = 0; i < n->inputs_num; i++) + { + if (test_pattern[i] == 0) + { + test_pattern[i] = 1; + overflow = 0; + break; + } + else + { + test_pattern[i] = 0; + overflow = 1; + } + } + + /* Break out of the while loop if we tested all possible patterns */ + if (overflow == 1) + break; + } /* while (42) */ + + /* All tests successfull */ + return (SN_NETWORK_STAGE_NUM (n) + patterns_failed); +} /* }}} int rate_network */ + +static sn_comparator_t get_random_comparator (void) /* {{{ */ +{ + sn_comparator_t c; + + c.min = sn_bounded_random (0, inputs_num - 1); + c.max = c.min; + while (c.max == c.min) + c.max = sn_bounded_random (0, inputs_num - 1); + + return (c); +} /* }}} sn_comparator_t get_random_comparator */ + +static int mutate_network (sn_comparator_t *comparators, int comparators_num) +{ + int i; + + for (i = 0; i < comparators_num; i++) + if (sn_bounded_random (0, 1000) == 0) + comparators[i] = get_random_comparator (); + + return (0); +} /* int mutate_network */ + +static int create_offspring (void) +{ + sn_network_t *p0; + sn_comparator_t p0_comparators[comparators_num]; + int p0_comparators_num; + + sn_network_t *p1; + sn_comparator_t p1_comparators[comparators_num]; + int p1_comparators_num; + + sn_network_t *n; + sn_comparator_t n_comparators[comparators_num]; + int n_comparators_num; + + int i; + + p0 = population_get_random (population); + p1 = population_get_random (population); + + assert (p0 != NULL); + assert (p1 != NULL); + + p0_comparators_num = 0; + for (i = 0; i < SN_NETWORK_STAGE_NUM (p0); i++) + { + sn_stage_t *s; + int j; + + s = SN_NETWORK_STAGE_GET (p0, i); + + for (j = 0; j < SN_STAGE_COMP_NUM (s); j++) + { + sn_comparator_t *c; + + c = SN_STAGE_COMP_GET (s, j); + p0_comparators[p0_comparators_num] = *c; + p0_comparators_num++; + } + } + while (p0_comparators_num < comparators_num) + { + p0_comparators[p0_comparators_num] = get_random_comparator (); + p0_comparators_num++; + } + sn_network_destroy (p0); + p0 = NULL; + + p1_comparators_num = 0; + for (i = 0; i < SN_NETWORK_STAGE_NUM (p1); i++) + { + sn_stage_t *s; + int j; + + s = SN_NETWORK_STAGE_GET (p1, i); + + for (j = 0; j < SN_STAGE_COMP_NUM (s); j++) + { + sn_comparator_t *c; + + c = SN_STAGE_COMP_GET (s, j); + p1_comparators[p1_comparators_num] = *c; + p1_comparators_num++; + } + } + while (p1_comparators_num < comparators_num) + { + p1_comparators[p1_comparators_num] = get_random_comparator (); + p1_comparators_num++; + } + sn_network_destroy (p1); + p1 = NULL; + + n_comparators_num = sn_bounded_random (SNE_MIN (p0_comparators_num, p1_comparators_num), + SNE_MAX (p0_comparators_num, p1_comparators_num)); + + for (i = 0; i < n_comparators_num; i++) + { + if (i >= p0_comparators_num) + n_comparators[i] = p1_comparators[i]; + else if (i >= p1_comparators_num) + n_comparators[i] = p0_comparators[i]; + else if (sn_bounded_random (0, 1) == 0) + n_comparators[i] = p1_comparators[i]; + else + n_comparators[i] = p0_comparators[i]; + + } + + if (sn_bounded_random (0, 1000) == 0) + mutate_network (n_comparators, n_comparators_num); + + n = sn_network_create (inputs_num); + for (i = 0; i < n_comparators_num; i++) + sn_network_comparator_add (n, &n_comparators[i]); + + /* compress the network to get a compact representation */ + sn_network_compress (n); + + assert (SN_NETWORK_INPUT_NUM (n) == inputs_num); + + population_insert (population, n); + + sn_network_destroy (n); + + return (0); +} /* int create_offspring */ + +static void *evolution_thread (void *arg) +{ + while (do_loop == 0) + { + create_offspring (); + /* XXX: Not synchronized! */ + iteration_counter++; + } + + return ((void *) 0); +} /* int start_evolution */ + +static int evolution_start (int threads_num) +{ + pthread_t threads[threads_num]; /* C99 ftw! */ + int i; + + for (i = 0; i < threads_num; i++) + { + int status; + + status = pthread_create (&threads[i], /* attr = */ NULL, + evolution_thread, /* arg = */ NULL); + if (status != 0) + { + fprintf (stderr, "evolution_start: pthread_create[%i] failed " + "with status %i.\n", + i, status); + threads[i] = 0; + } + } + + while (do_loop == 0) + { + int status; + + status = sleep (1); + if (status == 0) + { + sn_network_t *n; + int stages_num; + int comparators_num; + int rating; + int iter; + + iter = iteration_counter; + + n = population_get_fittest (population); + + rating = rate_network (n); + + stages_num = SN_NETWORK_STAGE_NUM (n); + comparators_num = 0; + for (i = 0; i < stages_num; i++) + { + sn_stage_t *s; + + s = SN_NETWORK_STAGE_GET (n, i); + comparators_num += SN_STAGE_COMP_NUM (s); + } + + sn_network_destroy (n); + + printf ("Best after approximately %i iterations: " + "%i comparators in %i stages. Rating: %i (%i not sorted).\n", + iter, comparators_num, stages_num, rating, + rating - stages_num); + } + } + + for (i = 0; i < threads_num; i++) + { + if (threads[i] == 0) + continue; + pthread_join (threads[i], /* value_ptr = */ NULL); + } + + return (0); +} /* int evolution_start */ + +int main (int argc, char **argv) +{ + struct sigaction sigint_action; + struct sigaction sigterm_action; + + population = population_create ((pi_rate_f) rate_network, + (pi_copy_f) sn_network_clone, + (pi_free_f) sn_network_destroy); + if (population == NULL) + { + fprintf (stderr, "population_create failed.\n"); + return (1); + } + + population_set_serialization (population, + (pi_serialize_f) sn_network_serialize, + (pi_unserialize_f) sn_network_unserialize); + + read_options (argc, argv); + + if ((inputs_num <= 0) || (comparators_num <= 0)) + exit_usage (argv[0]); + + memset (&sigint_action, '\0', sizeof (sigint_action)); + sigint_action.sa_handler = sigint_handler; + sigaction (SIGINT, &sigint_action, NULL); + + memset (&sigterm_action, '\0', sizeof (sigterm_action)); + sigterm_action.sa_handler = sigint_handler; + sigaction (SIGTERM, &sigterm_action, NULL); + + population_start_listen_thread (population, NULL, NULL); + + { + sn_network_t *n; + int i; + + n = sn_network_create (inputs_num); + for (i = 0; i < comparators_num; i++) + { + sn_comparator_t c; + + c = get_random_comparator (); + sn_network_comparator_add (n, &c); + } + + population_insert (population, n); + sn_network_destroy (n); + } + + printf ("Current configuration:\n" + " Number of inputs: %3i\n" + " Number of comparators: %3i\n" + " Population size: %3i\n" + "=======================\n", + inputs_num, comparators_num, max_population_size); + + evolution_start (evolution_threads_num); + + printf ("Exiting after %llu iterations.\n", + (unsigned long long) iteration_counter); + + { + sn_network_t *n; + + n = population_get_fittest (population); + if (n != NULL) + { + if (best_output_file != NULL) + sn_network_write_file (n, best_output_file); + sn_network_show (n); + sn_network_destroy (n); + } + } + + population_destroy (population); + + return (0); +} /* int main */ + +/* vim: set shiftwidth=2 softtabstop=2 : */ diff --git a/src/sn_network.c b/src/sn_network.c index d8403c0..8462020 100644 --- a/src/sn_network.c +++ b/src/sn_network.c @@ -219,6 +219,47 @@ sn_network_t *sn_network_clone (const sn_network_t *n) /* {{{ */ return (n_copy); } /* }}} sn_network_t *sn_network_clone */ +int sn_network_comparator_add (sn_network_t *n, /* {{{ */ + const sn_comparator_t *c) +{ + sn_stage_t *s; + + if ((n == NULL) || (c == NULL)) + return (-1); + + if (n->stages_num > 0) + { + s = n->stages[n->stages_num - 1]; + + if (sn_stage_comparator_check_conflict (s, c) == 0) + { + sn_stage_comparator_add (s, c); + return (0); + } + } + + s = sn_stage_create (n->stages_num); + sn_stage_comparator_add (s, c); + sn_network_stage_add (n, s); + + return (0); +} /* }}} int sn_network_comparator_add */ + +int sn_network_get_comparator_num (const sn_network_t *n) /* {{{ */ +{ + int num; + int i; + + if (n == NULL) + return (-1); + + num = 0; + for (i = 0; i < n->stages_num; i++) + num += n->stages[i]->comparators_num; + + return (num); +} /* }}} int sn_network_get_comparator_num */ + int sn_network_show (sn_network_t *n) /* {{{ */ { int i; diff --git a/src/sn_network.h b/src/sn_network.h index ed96c3f..e3c4306 100644 --- a/src/sn_network.h +++ b/src/sn_network.h @@ -48,6 +48,10 @@ sn_network_t *sn_network_create_odd_even_mergesort (int inputs_num); int sn_network_stage_add (sn_network_t *n, sn_stage_t *s); int sn_network_stage_remove (sn_network_t *n, int s_num); +int sn_network_comparator_add (sn_network_t *n, const sn_comparator_t *c); + +int sn_network_get_comparator_num (const sn_network_t *n); + int sn_network_sort (sn_network_t *n, int *values); int sn_network_brute_force_check (sn_network_t *n); -- 2.11.0