src/sn-oddevenmerge.c: Create a OEM-network.
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Wed, 11 Mar 2009 08:10:26 +0000 (09:10 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Wed, 11 Mar 2009 08:10:26 +0000 (09:10 +0100)
The OEM code in sn_network.c has been improved to handle networks with
numbers of inputs that are *not* a power of two.

src/Makefile
src/sn-evolution.c
src/sn-merge.c
src/sn-oddevenmerge.c [new file with mode: 0644]
src/sn_network.c
src/sn_network.h

index 516313f..135e30e 100644 (file)
@@ -2,8 +2,9 @@ CC = gcc
 CFLAGS = -Wall -Werror -std=c99 -O3 -pthread
 #CFLAGS = -Wall -Werror -std=c99 -O0 -g -pthread
 
-APPLICATIONS = sn-apply sn-check-bf sn-cut sn-evolution sn-merge \
-              sn-normalize sn-show sn-tex
+APPLICATIONS = sn-apply sn-batcher sn-check-bf sn-cut sn-cut-loop \
+              sn-evolution sn-find-9 sn-merge \
+              sn-normalize sn-oddevenmerge sn-show sn-tex
 
 POPULATION_CFLAGS = -I/tmp/sifnfors/libpopulation/include
 
@@ -41,6 +42,8 @@ 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
 
+sn-oddevenmerge: sn-oddevenmerge.c sn_network.o sn_stage.o sn_comparator.o sn_random.o
+
 sn-show: sn-show.c sn_network.o sn_stage.o sn_comparator.o sn_random.o
 
 sn-tex: sn-tex.c sn_network.o sn_stage.o sn_comparator.o sn_random.o
index 62b01eb..86bdfba 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/sn-evolution.c
- * Copyright (C) 2008  Florian octo Forster
+ * 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
@@ -52,6 +52,7 @@ char *strdup (const char *s);
 
 static uint64_t iteration_counter = 0;
 static int inputs_num = 16;
+static int inputs_num_is_power_of_two = 1;
 
 static char *initial_input_file = NULL;
 static char *best_output_file = NULL;
@@ -224,7 +225,7 @@ static int create_offspring (void)
   assert (p1 != NULL);
 
   /* combine the two parents */
-  n = sn_network_combine (p0, p1);
+  n = sn_network_combine (p0, p1, inputs_num_is_power_of_two);
 
   sn_network_destroy (p0);
   sn_network_destroy (p1);
@@ -371,6 +372,7 @@ int main (int argc, char **argv)
 
   {
     sn_network_t *n;
+    int tmp;
 
     n = sn_network_read_file (initial_input_file);
     if (n == NULL)
@@ -381,6 +383,23 @@ int main (int argc, char **argv)
 
     inputs_num = SN_NETWORK_INPUT_NUM(n);
 
+    /* Determine if `inputs_num' is a power of two. If so, more merge
+     * algorithms can be used. */
+    tmp = inputs_num;
+    inputs_num_is_power_of_two = 1;
+    while (tmp > 0)
+    {
+      if ((tmp % 2) != 0)
+      {
+       if (tmp == 1)
+         inputs_num_is_power_of_two = 1;
+       else
+         inputs_num_is_power_of_two = 0;
+       break;
+      }
+      tmp = tmp >> 1;
+    }
+
     population_insert (population, n);
     sn_network_destroy (n);
   }
index 2c884a5..db0b4cd 100644 (file)
@@ -60,7 +60,7 @@ int main (int argc, char **argv)
     return (1);
   }
 
-  n = sn_network_combine (n0, n1);
+  n = sn_network_combine (n0, n1, /* is power of two = */ 0);
   sn_network_destroy (n0);
   sn_network_destroy (n1);
 
diff --git a/src/sn-oddevenmerge.c b/src/sn-oddevenmerge.c
new file mode 100644 (file)
index 0000000..8cb64f6
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * collectd - src/sn-oddevenmerge.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 <octo at verplant.org>
+ **/
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "sn_network.h"
+
+int main (int argc, char **argv)
+{
+  sn_network_t *n;
+  size_t inputs_num;
+
+  if (argc != 2)
+  {
+    printf ("Usage: %s <num inputs>\n", argv[0]);
+    return (0);
+  }
+
+  inputs_num = (size_t) atoi (argv[1]);
+  if (inputs_num < 2)
+  {
+    fprintf (stderr, "Invalid number of inputs: %zu\n", inputs_num);
+    return (1);
+  }
+
+  n = sn_network_create_odd_even_mergesort (inputs_num);
+  if (n == NULL)
+  {
+    printf ("n == NULL!\n");
+    return (1);
+  }
+
+  sn_network_write (n, stdout);
+
+  return (0);
+} /* int main */
+
+/* vim: set shiftwidth=2 softtabstop=2 : */
index 5576b86..6308b90 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/sn_network.c
- * Copyright (C) 2008  Florian octo Forster
+ * 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
@@ -76,6 +76,64 @@ void sn_network_destroy (sn_network_t *n) /* {{{ */
   free (n);
 } /* }}} void sn_network_destroy */
 
+sn_network_t *sn_network_create_odd_even_mergesort (int inputs_num) /* {{{ */
+{
+  sn_network_t *n;
+
+  n = sn_network_create (inputs_num);
+
+  assert (inputs_num > 0);
+  if (inputs_num == 1)
+  {
+    return (n);
+  }
+  if (inputs_num == 2)
+  {
+    sn_stage_t *s;
+    sn_comparator_t c;
+
+    c.min = 0;
+    c.max = 1;
+
+    s = sn_stage_create (/* depth = */ 0);
+    sn_stage_comparator_add (s, &c);
+    sn_network_stage_add (n, s);
+
+    return (n);
+  }
+  else
+  {
+    sn_network_t *n_left;
+    sn_network_t *n_right;
+    int inputs_left;
+    int inputs_right;
+
+    inputs_left = inputs_num / 2;
+    inputs_right = inputs_num - inputs_left;
+
+    n_left = sn_network_create_odd_even_mergesort (inputs_left);
+    if (n_left == NULL)
+      return (NULL);
+
+    n_right = sn_network_create_odd_even_mergesort (inputs_right);
+    if (n_right == NULL)
+    {
+      sn_network_destroy (n_left);
+      return (NULL);
+    }
+
+    n = sn_network_combine_odd_even_merge (n_left, n_right);
+
+    sn_network_destroy (n_left);
+    sn_network_destroy (n_right);
+
+    if (n != NULL)
+      sn_network_compress (n);
+
+    return (n);
+  }
+} /* }}} sn_network_t *sn_network_create_odd_even_mergesort */
+
 int sn_network_stage_add (sn_network_t *n, sn_stage_t *s) /* {{{ */
 {
   sn_stage_t **temp;
@@ -430,106 +488,99 @@ static int sn_network_add_bitonic_merger (sn_network_t *n) /* {{{ */
   return (0);
 } /* }}} int sn_network_add_bitonic_merger */
 
-static int sn_network_add_odd_even_merger_recursive (sn_network_t *n, /* {{{ */
-    int *indizes, int indizes_num)
+static int sn_network_add_odd_even_merger (sn_network_t *n, /* {{{ */
+    int *indizes_left, int indizes_left_num,
+    int *indizes_right, int indizes_right_num)
 {
-  if (indizes_num > 2)
+  int tmp_left[indizes_left_num];
+  int tmp_left_num;
+  int tmp_right[indizes_left_num];
+  int tmp_right_num;
+  int max_index;
+  sn_stage_t *s;
+  int i;
+
+  if ((indizes_left_num == 0) || (indizes_right_num == 0))
+  {
+    return (0);
+  }
+  else if ((indizes_left_num == 1) && (indizes_right_num == 1))
   {
     sn_comparator_t c;
     sn_stage_t *s;
-    int indizes_half_num;
-    int *indizes_half;
-    int status;
-    int i;
 
-    indizes_half_num = indizes_num / 2;
-    indizes_half = (int *) malloc (indizes_num * sizeof (int));
-    if (indizes_half == NULL)
+    c.min = *indizes_left;
+    c.max = *indizes_right;
+
+    s = sn_stage_create (n->stages_num);
+    if (s == NULL)
       return (-1);
 
-    for (i = 0; i < indizes_half_num; i++)
-    {
-      indizes_half[i] = indizes[2 * i];
-      indizes_half[indizes_half_num + i] = indizes[(2 * i) + 1];
-    }
+    sn_stage_comparator_add (s, &c);
+    sn_network_stage_add (n, s);
 
-    status = sn_network_add_odd_even_merger_recursive (n,
-       indizes_half, indizes_half_num);
-    if (status != 0)
-    {
-      free (indizes_half);
-      return (status);
-    }
+    return (0);
+  }
 
-    status = sn_network_add_odd_even_merger_recursive (n,
-       indizes_half + indizes_half_num, indizes_half_num);
-    if (status != 0)
-    {
-      free (indizes_half);
-      return (status);
-    }
+  /* Merge odd sequences */
+  tmp_left_num = (indizes_left_num + 1) / 2;
+  for (i = 0; i < tmp_left_num; i++)
+    tmp_left[i] = indizes_left[2 * i];
 
-    free (indizes_half);
+  tmp_right_num = (indizes_right_num + 1) / 2;
+  for (i = 0; i < tmp_right_num; i++)
+    tmp_right[i] = indizes_right[2 * i];
 
-    s = sn_stage_create (n->stages_num);
-    if (s == NULL)
-      return (-1);
+  sn_network_add_odd_even_merger (n,
+      tmp_left, tmp_left_num,
+      tmp_right, tmp_right_num);
 
-    for (i = 1; i < (indizes_num - 2); i += 2)
-    {
-      c.min = indizes[i];
-      c.max = indizes[i + 1];
+  /* Merge even sequences */
+  tmp_left_num = indizes_left_num / 2;
+  for (i = 0; i < tmp_left_num; i++)
+    tmp_left[i] = indizes_left[(2 * i) + 1];
 
-      sn_stage_comparator_add (s, &c);
-    }
+  tmp_right_num = indizes_right_num / 2;
+  for (i = 0; i < tmp_right_num; i++)
+    tmp_right[i] = indizes_right[(2 * i) + 1];
 
-    sn_network_stage_add (n, s);
-  }
+  sn_network_add_odd_even_merger (n,
+      tmp_left, tmp_left_num,
+      tmp_right, tmp_right_num);
+
+  /* Apply ``comparison-interchange'' operations. */
+  s = sn_stage_create (n->stages_num);
+
+  max_index = indizes_left_num + indizes_right_num;
+  if ((max_index % 2) == 0)
+    max_index -= 3;
   else
+    max_index -= 2;
+
+  for (i = 1; i <= max_index; i += 2)
   {
     sn_comparator_t c;
-    sn_stage_t *s;
-
-    assert (indizes_num == 2);
 
-    c.min = indizes[0];
-    c.max = indizes[1];
+    if (i < indizes_left_num)
+      c.min = indizes_left[i];
+    else
+      c.min = indizes_right[i - indizes_left_num];
 
-    s = sn_stage_create (n->stages_num);
-    if (s == NULL)
-      return (-1);
+    if ((i + 1) < indizes_left_num)
+      c.max = indizes_left[i + 1];
+    else
+      c.max = indizes_right[i + 1 - indizes_left_num];
 
     sn_stage_comparator_add (s, &c);
-    sn_network_stage_add (n, s);
   }
 
-  return (0);
-} /* }}} int sn_network_add_odd_even_merger_recursive */
-
-static int sn_network_add_odd_even_merger (sn_network_t *n) /* {{{ */
-{
-  int *indizes;
-  int indizes_num;
-  int status;
-  int i;
-
-  indizes_num = n->inputs_num;
-  indizes = (int *) malloc (indizes_num * sizeof (int));
-  if (indizes == NULL)
-    return (-1);
-
-  for (i = 0; i < indizes_num; i++)
-    indizes[i] = i;
+  sn_network_stage_add (n, s);
 
-  status = sn_network_add_odd_even_merger_recursive (n,
-      indizes, indizes_num);
-  
-  free (indizes);
-  return (status);
-} /* }}} int sn_network_add_bitonic_merger */
+  return (0);
+} /* }}} int sn_network_add_odd_even_merger */
 
-static sn_network_t *sn_network_combine_bitonic (sn_network_t *n0, /* {{{ */
-    sn_network_t *n1)
+static sn_network_t *sn_network_combine_bitonic_shift (sn_network_t *n0, /* {{{ */
+    sn_network_t *n1, int do_shift)
 {
   sn_network_t *n;
   sn_network_t *n1_clone;
@@ -547,35 +598,77 @@ static sn_network_t *sn_network_combine_bitonic (sn_network_t *n0, /* {{{ */
 
   sn_network_destroy (n1_clone);
 
-  shift = sn_bounded_random (0, SN_NETWORK_INPUT_NUM (n) - 1);
+  if (do_shift)
+    shift = sn_bounded_random (0, SN_NETWORK_INPUT_NUM (n) - 1);
+  else
+    shift = 0;
+
   if (shift > 0)
   {
-    DPRINTF ("sn_network_combine_bitonic: Shifting by %i.\n", shift);
+    DPRINTF ("sn_network_combine_bitonic_shift: Shifting by %i.\n", shift);
     sn_network_shift (n, shift);
   }
 
   sn_network_add_bitonic_merger (n);
 
   return (n);
+} /* }}} sn_network_t *sn_network_combine_bitonic_shift */
+
+sn_network_t *sn_network_combine_bitonic (sn_network_t *n0, /* {{{ */
+    sn_network_t *n1)
+{
+  return (sn_network_combine_bitonic_shift (n0, n1, /* do_shift = */ 0));
 } /* }}} sn_network_t *sn_network_combine_bitonic */
 
-sn_network_t *sn_network_combine (sn_network_t *n0, /* {{{ */
+sn_network_t *sn_network_combine_odd_even_merge (sn_network_t *n0, /* {{{ */
     sn_network_t *n1)
 {
   sn_network_t *n;
+  int indizes_left[n0->inputs_num];
+  int indizes_left_num;
+  int indizes_right[n1->inputs_num];
+  int indizes_right_num;
+  int status;
+  int i;
+
+  indizes_left_num = n0->inputs_num;
+  indizes_right_num = n1->inputs_num;
+  for (i = 0; i < indizes_left_num; i++)
+    indizes_left[i] = i;
+  for (i = 0; i < indizes_right_num; i++)
+    indizes_right[i] = indizes_left_num + i;
+
+  n = sn_network_concatenate (n0, n1);
+  if (n == NULL)
+    return (NULL);
+
+  status = sn_network_add_odd_even_merger (n,
+      indizes_left, indizes_left_num,
+      indizes_right, indizes_right_num);
+  if (status != 0)
+  {
+    sn_network_destroy (n);
+    return (NULL);
+  }
+
+  sn_network_compress (n);
+  return (n);
+} /* }}} sn_network_t *sn_network_combine */
+
+sn_network_t *sn_network_combine (sn_network_t *n0, /* {{{ */
+    sn_network_t *n1, int is_power_of_two)
+{
+  sn_network_t *n;
 
-  if (sn_bounded_random (0, 2) < 2)
+  if ((is_power_of_two != 0) && (sn_bounded_random (0, 9) == 0))
   {
     DPRINTF ("sn_network_combine: Using the bitonic merger.\n");
-    n = sn_network_combine_bitonic (n0, n1);
+    n = sn_network_combine_bitonic_shift (n0, n1, /* do_shift = */ 1);
   }
   else
   {
     DPRINTF ("sn_network_combine: Using the odd-even merger.\n");
-    n = sn_network_concatenate (n0, n1);
-    if (n == NULL)
-      return (NULL);
-    sn_network_add_odd_even_merger (n);
+    n = sn_network_combine_odd_even_merge (n0, n1);
   }
 
   sn_network_compress (n);
index 3af9c72..ed96c3f 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/sn_network.h
- * Copyright (C) 2008  Florian octo Forster
+ * 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
@@ -43,6 +43,8 @@ sn_network_t *sn_network_create (int inputs_num);
 sn_network_t *sn_network_clone (const sn_network_t *n);
 void sn_network_destroy (sn_network_t *n);
 
+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);
 
@@ -56,7 +58,10 @@ int sn_network_compress (sn_network_t *n);
 int sn_network_normalize (sn_network_t *n);
 
 int sn_network_cut_at (sn_network_t *n, int input, enum sn_network_cut_dir_e dir);
-sn_network_t *sn_network_combine (sn_network_t *n0, sn_network_t *n1);
+sn_network_t *sn_network_combine (sn_network_t *n0, sn_network_t *n1,
+    int is_power_of_two);
+sn_network_t *sn_network_combine_bitonic (sn_network_t *n0, sn_network_t *n1);
+sn_network_t *sn_network_combine_odd_even_merge (sn_network_t *n0, sn_network_t *n1);
 
 sn_network_t *sn_network_read (FILE *fh);
 sn_network_t *sn_network_read_file (const char *file);