sn_population.[ch]: Add the sn_population object.
authorFlorian Forster <octo@leeloo.home.verplant.org>
Fri, 25 Apr 2008 09:06:26 +0000 (11:06 +0200)
committerFlorian Forster <octo@leeloo.home.verplant.org>
Fri, 25 Apr 2008 09:06:26 +0000 (11:06 +0200)
This object capsulates population handling in a thread-safe manner.

src/sn_population.c [new file with mode: 0644]
src/sn_population.h [new file with mode: 0644]

diff --git a/src/sn_population.c b/src/sn_population.c
new file mode 100644 (file)
index 0000000..1147f06
--- /dev/null
@@ -0,0 +1,204 @@
+#define _ISOC99_SOURCE
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include "sn_population.h"
+#include "sn_network.h"
+#include "sn_random.h"
+
+struct sn_population_s
+{
+  uint32_t size;
+
+  sn_network_t **networks;
+  int *ratings;
+  uint32_t networks_num;
+
+  pthread_mutex_t lock;
+};
+
+static int rate_network (const sn_network_t *n)
+{
+  int rate;
+  int i;
+
+  rate = SN_NETWORK_STAGE_NUM (n) * SN_NETWORK_INPUT_NUM (n);
+  for (i = 0; i < SN_NETWORK_STAGE_NUM (n); i++)
+  {
+    sn_stage_t *s = SN_NETWORK_STAGE_GET (n, i);
+    rate += SN_STAGE_COMP_NUM (s);
+  }
+
+  return (rate);
+} /* int rate_network */
+
+sn_population_t *sn_population_create (uint32_t size)
+{
+  sn_population_t *p;
+  int status;
+
+  p = (sn_population_t *) malloc (sizeof (sn_population_t));
+  if (p == NULL)
+    return (NULL);
+  memset (p, 0, sizeof (sn_population_t));
+  p->size = size;
+
+  p->networks = (sn_network_t **) calloc ((size_t) size,
+      sizeof (sn_network_t *));
+  if (p->networks == NULL)
+  {
+    free (p);
+    return (NULL);
+  }
+
+  p->ratings = (int *) calloc ((size_t) size, sizeof (int));
+  if (p->ratings == NULL)
+  {
+    free (p->networks);
+    free (p);
+    return (NULL);
+  }
+
+  status = pthread_mutex_init (&p->lock, /* attr = */ NULL);
+  if (status != 0)
+  {
+    fprintf (stderr, "sn_population_create: pthread_mutex_init failed: %i\n",
+       status);
+    free (p->ratings);
+    free (p->networks);
+    free (p);
+    return (NULL);
+  }
+
+  return (p);
+} /* sn_population_t *sn_population_create */
+
+void sn_population_destroy (sn_population_t *p)
+{
+  uint32_t i;
+
+  if (p == NULL)
+    return;
+
+  for (i = 0; i < p->size; i++)
+    if (p->networks[i] != NULL)
+      sn_network_destroy (p->networks[i]);
+
+  pthread_mutex_destroy (&p->lock);
+
+  free (p->ratings);
+  free (p->networks);
+  free (p);
+} /* void sn_population_destroy */
+
+int sn_population_push (sn_population_t *p, sn_network_t *n)
+{
+  sn_network_t *n_copy;
+  int rating;
+
+  n_copy = sn_network_clone (n);
+  if (n_copy == NULL)
+  {
+    fprintf (stderr, "sn_population_push: sn_network_clone failed.\n");
+    return (-1);
+  }
+
+  rating = rate_network (n_copy);
+
+  pthread_mutex_lock (&p->lock);
+
+  if (p->networks_num < p->size)
+  {
+    p->networks[p->networks_num] = n_copy;
+    p->ratings[p->networks_num] = rating;
+    p->networks_num++;
+  }
+  else
+  {
+    int index;
+    sn_network_t *n_removed = n_copy;
+    int i;
+
+    for (i = 0; i < (1 + (p->networks_num / 16)); i++)
+    {
+      index = sn_bounded_random (0, p->networks_num - 1);
+      if (p->ratings[index] < rating)
+       continue;
+
+      n_removed = p->networks[index];
+      p->networks[index] = n_copy;
+      p->ratings[index] = rating;
+      break;
+    }
+
+    sn_network_destroy (n_removed);
+  }
+
+  pthread_mutex_unlock (&p->lock);
+
+  return (0);
+} /* int sn_population_push */
+
+sn_network_t *sn_population_pop (sn_population_t *p)
+{
+  int index;
+  sn_network_t *n_copy;
+
+  pthread_mutex_lock (&p->lock);
+
+  if (p->networks_num <= 0)
+  {
+    pthread_mutex_unlock (&p->lock);
+    return (NULL);
+  }
+
+  index = sn_bounded_random (0, p->networks_num - 1);
+  n_copy = sn_network_clone (p->networks[index]);
+
+  pthread_mutex_unlock (&p->lock);
+
+  return (n_copy);
+} /* sn_population_t *sn_population_pop */
+
+sn_network_t *sn_population_best (sn_population_t *p)
+{
+  uint32_t i;
+
+  uint32_t index = 0;
+  int rating = -1;
+  sn_network_t *n_copy;
+
+  if (p == NULL)
+    return (NULL);
+
+  pthread_mutex_lock (&p->lock);
+
+  if (p->networks_num <= 0)
+  {
+    pthread_mutex_unlock (&p->lock);
+    return (NULL);
+  }
+
+  for (i = 0; i < p->networks_num; i++)
+  {
+    if ((p->ratings[i] < rating) || (rating < 0))
+    {
+      rating = p->ratings[i];
+      index = i;
+    }
+  }
+
+  n_copy = sn_network_clone (p->networks[index]);
+
+  pthread_mutex_unlock (&p->lock);
+
+  return (n_copy);
+} /* sn_network_t *sn_population_best */
+
+/* vim: set shiftwidth=2 softtabstop=2 : */
diff --git a/src/sn_population.h b/src/sn_population.h
new file mode 100644 (file)
index 0000000..b444e55
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SN_POPULATION_H
+#define SN_POPULATION_H 1
+
+#include <stdint.h>
+#include "sn_network.h"
+
+/*
+ * sn_population_t
+ *
+ * Opaque data type for the population.
+ */
+struct sn_population_s;
+typedef struct sn_population_s sn_population_t;
+
+sn_population_t *sn_population_create (uint32_t size);
+void sn_population_destroy (sn_population_t *p);
+
+/*
+ * push
+ *
+ * Puts a new network into the population. The network is _copied_ and may be
+ * modified by the caller after inserting the network. This won'thave an effect
+ * on the copy in the population, though. Of course, the caller must free his
+ * own copy himself!
+ */
+int sn_population_push (sn_population_t *p, sn_network_t *n);
+
+/*
+ * pop
+ *
+ * Returns a _copy_ of an individuum in the population. The network is NOT
+ * removed from the population by this operation! The caller must free this
+ * copy himself. Returns NULL upon failure.
+ */
+sn_network_t *sn_population_pop (sn_population_t *p);
+
+sn_network_t *sn_population_best (sn_population_t *p);
+
+#endif /* SN_POPULATION_H */