+sn_network_t *sn_network_create_bitonic_mergesort (int inputs_num) /* {{{ */
+{
+ sn_network_t *n;
+
+ assert (inputs_num > 0);
+ if (inputs_num == 1)
+ {
+ return (sn_network_create (inputs_num));
+ }
+ if (inputs_num == 2)
+ {
+ sn_comparator_t c;
+
+ n = sn_network_create (inputs_num);
+
+ memset (&c, 0, sizeof (c));
+ c.min = 0;
+ c.max = 1;
+
+ sn_network_comparator_add (n, &c);
+
+ 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_bitonic_mergesort (inputs_left);
+ if (n_left == NULL)
+ return (NULL);
+
+ if (inputs_left != inputs_right)
+ n_right = sn_network_create_bitonic_mergesort (inputs_right);
+ else
+ n_right = n_left;
+ if (n_right == NULL)
+ {
+ sn_network_destroy (n_left);
+ return (NULL);
+ }
+
+ n = sn_network_combine_bitonic_merge (n_left, n_right);
+
+ if (n_left != n_right)
+ sn_network_destroy (n_right);
+ sn_network_destroy (n_left);
+
+ if (n != NULL)
+ sn_network_compress (n);
+
+ return (n);
+ }
+} /* }}} sn_network_t *sn_network_create_bitonic_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 + 1) / 2;
+ while (m > 1)
+ {
+ int len;
+
+ /* len = ((int) ((m + 1) / 2)) * 2 - 1; */
+ if ((m % 2) == 0)
+ len = m - 1;
+ else
+ len = m;
+
+ for (i = 1; (i + len) < inputs_num; i += 2)
+ {
+ int left = i;
+ int right = i + len;
+ 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 + 1) / 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;
+ int i;
+
+ 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);
+ for (i = n->stages_num; i < stages_num; i++)
+ SN_STAGE_DEPTH(n->stages[i]) = i;
+
+ n->stages_num = stages_num;
+
+ free (other->stages);
+ free (other);
+
+ return (0);
+} /* }}} int sn_network_network_add */
+