src/sn_network.[ch]: Implement sn_network_network_add().
[sort-networks.git] / src / sn_network.c
index b490de4..15269c9 100644 (file)
@@ -135,6 +135,105 @@ sn_network_t *sn_network_create_odd_even_mergesort (int inputs_num) /* {{{ */
   }
 } /* }}} sn_network_t *sn_network_create_odd_even_mergesort */
 
+static int sn_network_create_pairwise_internal (sn_network_t *n, /* {{{ */
+    int *inputs, int inputs_num)
+{
+  int i;
+  int inputs_copy[inputs_num];
+  int m;
+
+  for (i = 1; i < inputs_num; i += 2)
+  {
+    sn_comparator_t *c = sn_comparator_create (inputs[i-1], inputs[i]);
+    sn_network_comparator_add (n, c);
+    sn_comparator_destroy (c);
+  }
+
+  if (inputs_num <= 2)
+    return (0);
+
+  /* Sort "pairs" recursively. Like with odd-even mergesort, odd and even lines
+   * are handled recursively and later reunited. */
+  for (i = 0; i < inputs_num; i += 2)
+    inputs_copy[(int) (i / 2)] = inputs[i];
+  /* Recursive call #1 with first set of lines */
+  sn_network_create_pairwise_internal (n, inputs_copy,
+      (int) ((inputs_num + 1) / 2));
+
+  for (i = 1; i < inputs_num; i += 2)
+    inputs_copy[(int) (i / 2)] = inputs[i];
+  /* Recursive call #2 with second set of lines */
+  sn_network_create_pairwise_internal (n, inputs_copy,
+      (int) (inputs_num/ 2));
+
+  /* m is the "amplitude" of the sorted pairs. This is a bit tricky to read due
+   * to different indices being used in the paper, unfortunately. */
+  m = inputs_num / 2;
+  while (m > 1)
+  {
+    for (i = 1; (i + (m - 1)) < inputs_num; i += 2)
+    {
+      int left = i;
+      int right = i + (m - 1);
+      sn_comparator_t *c;
+
+      assert (left < right);
+      c = sn_comparator_create (inputs[left], inputs[right]);
+      sn_network_comparator_add (n, c);
+      sn_comparator_destroy (c);
+    }
+
+    m = m / 2;
+  } /* while (m > 1) */
+
+  return (0);
+} /* }}} int sn_network_create_pairwise_internal */
+
+sn_network_t *sn_network_create_pairwise (int inputs_num) /* {{{ */
+{
+  sn_network_t *n = sn_network_create (inputs_num);
+  int inputs[inputs_num];
+  int i;
+
+  if (n == NULL)
+    return (NULL);
+
+  for (i = 0; i < inputs_num; i++)
+    inputs[i] = i;
+  
+  sn_network_create_pairwise_internal (n, inputs, inputs_num);
+  sn_network_compress (n);
+
+  return (n);
+} /* }}} sn_network_t *sn_network_create_pairwise */
+
+int sn_network_network_add (sn_network_t *n, sn_network_t *other) /* {{{ */
+{
+  int stages_num;
+  sn_stage_t **tmp;
+
+  if ((n == NULL) || (other == NULL))
+    return (EINVAL);
+
+  stages_num = n->stages_num + other->stages_num;
+  if (stages_num <= n->stages_num)
+    return (EINVAL);
+
+  tmp = realloc (n->stages, sizeof (*n->stages) * stages_num);
+  if (tmp == NULL)
+    return (ENOMEM);
+  n->stages = tmp;
+
+  memcpy (n->stages + n->stages_num, other->stages,
+      sizeof (*other->stages) * other->stages_num);
+  n->stages_num = stages_num;
+
+  free (other->stages);
+  free (other);
+
+  return (0);
+} /* }}} int sn_network_network_add */
+
 int sn_network_stage_add (sn_network_t *n, sn_stage_t *s) /* {{{ */
 {
   sn_stage_t **temp;
@@ -392,6 +491,21 @@ int sn_network_normalize (sn_network_t *n) /* {{{ */
   return (0);
 } /* }}} int sn_network_normalize */
 
+int sn_network_remove_input (sn_network_t *n, int input) /* {{{ */
+{
+  int i;
+
+  if ((n == NULL) || (input < 0) || (input >= n->inputs_num))
+    return (EINVAL);
+
+  for (i = 0; i < n->stages_num; i++)
+    sn_stage_remove_input (n->stages[i], input);
+
+  n->inputs_num--;
+
+  return (0);
+} /* }}} int sn_network_remove_input */
+
 int sn_network_cut_at (sn_network_t *n, int input, /* {{{ */
     enum sn_network_cut_dir_e dir)
 {
@@ -420,13 +534,36 @@ int sn_network_cut_at (sn_network_t *n, int input, /* {{{ */
   assert (((dir == DIR_MIN) && (position == 0))
       || ((dir == DIR_MAX) && (position == (n->inputs_num - 1))));
 
+  sn_network_remove_input (n, position);
+
+  return (0);
+} /* }}} int sn_network_cut_at */
+
+int sn_network_cut (sn_network_t *n, int *mask) /* {{{ */
+{
+  int inputs_num;
+  int i;
+
   for (i = 0; i < n->stages_num; i++)
-    sn_stage_remove_input (n->stages[i], position);
+  {
+    sn_stage_t *s = n->stages[i];
 
-  n->inputs_num--;
+    sn_stage_cut (s, mask, n->stages);
+  }
+
+  /* Use a copy of this member since it will be updated by
+   * sn_network_remove_input(). */
+  inputs_num = n->inputs_num;
+  for (i = 0; i < inputs_num; i++)
+  {
+    if (mask[i] < 0)
+      sn_network_remove_input (n, 0);
+    else if (mask[i] > 0)
+      sn_network_remove_input (n, n->inputs_num - 1);
+  }
 
   return (0);
-} /* }}} int sn_network_cut_at */
+} /* }}} int sn_network_cut */
 
 /* sn_network_concatenate
  *