src/sn-oddevenmerge.c: Create a OEM-network.
[sort-networks.git] / src / sn_network.c
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);