QUICK CLUSTER: Use fixed format for cluster centers.
[pspp.git] / tests / libpspp / abt-test.c
blob177e8f9108c3027b9085445642ac3c0843518f63
1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* This is a test program for the abt_* routines defined in
18 abt.c. This test program aims to be as comprehensive as
19 possible. "gcov -b" should report 100% coverage of lines and
20 branches in the abt_* routines. "valgrind --leak-check=yes
21 --show-reachable=yes" should give a clean report. */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <libpspp/abt.h>
29 #include <stdbool.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include <libpspp/compiler.h>
37 /* Exit with a failure code.
38 (Place a breakpoint on this function while debugging.) */
39 static void
40 check_die (void)
42 exit (EXIT_FAILURE);
45 /* If OK is not true, prints a message about failure on the
46 current source file and the given LINE and terminates. */
47 static void
48 check_func (bool ok, int line)
50 if (!ok)
52 fprintf (stderr, "%s:%d: check failed\n", __FILE__, line);
53 check_die ();
57 /* Verifies that EXPR evaluates to true.
58 If not, prints a message citing the calling line number and
59 terminates. */
60 #define check(EXPR) check_func ((EXPR), __LINE__)
62 /* Prints a message about memory exhaustion and exits with a
63 failure code. */
64 static void
65 xalloc_die (void)
67 printf ("virtual memory exhausted\n");
68 exit (EXIT_FAILURE);
71 /* Allocates and returns N bytes of memory. */
72 static void *
73 xmalloc (size_t n)
75 if (n != 0)
77 void *p = malloc (n);
78 if (p == NULL)
79 xalloc_die ();
81 return p;
83 else
84 return NULL;
87 static void *
88 xmemdup (const void *p, size_t n)
90 void *q = xmalloc (n);
91 memcpy (q, p, n);
92 return q;
95 /* Allocates and returns N * M bytes of memory. */
96 static void *
97 xnmalloc (size_t n, size_t m)
99 if ((size_t) -1 / m <= n)
100 xalloc_die ();
101 return xmalloc (n * m);
104 /* Node type and support routines. */
106 /* Test data element. */
107 struct element
109 struct abt_node node; /* Embedded binary tree element. */
110 int data; /* Primary value. */
111 int count; /* Number of nodes in subtree,
112 including this node. */
115 static int aux_data;
117 /* Returns the `struct element' that NODE is embedded within. */
118 static struct element *
119 abt_node_to_element (const struct abt_node *node)
121 return ABT_DATA (node, struct element, node);
124 /* Compares the `x' values in A and B and returns a strcmp-type
125 return value. Verifies that AUX points to aux_data. */
126 static int
127 compare_elements (const struct abt_node *a_, const struct abt_node *b_,
128 const void *aux)
130 const struct element *a = abt_node_to_element (a_);
131 const struct element *b = abt_node_to_element (b_);
133 check (aux == &aux_data);
134 return a->data < b->data ? -1 : a->data > b->data;
137 /* Recalculates the count for NODE's subtree by adding up the
138 counts for its LEFT and RIGHT child subtrees. */
139 static void
140 reaugment_elements (struct abt_node *node_, const void *aux)
142 struct element *node = abt_node_to_element (node_);
144 check (aux == &aux_data);
146 node->count = 1;
147 if (node->node.down[0] != NULL)
148 node->count += abt_node_to_element (node->node.down[0])->count;
149 if (node->node.down[1] != NULL)
150 node->count += abt_node_to_element (node->node.down[1])->count;
153 /* Compares A and B and returns a strcmp-type return value. */
154 static int
155 compare_ints_noaux (const void *a_, const void *b_)
157 const int *a = a_;
158 const int *b = b_;
160 return *a < *b ? -1 : *a > *b;
163 /* Swaps *A and *B. */
164 static void
165 swap (int *a, int *b)
167 int t = *a;
168 *a = *b;
169 *b = t;
172 /* Reverses the order of the N integers starting at VALUES. */
173 static void
174 reverse (int *values, size_t n)
176 size_t i = 0;
177 size_t j = n;
179 while (j > i)
180 swap (&values[i++], &values[--j]);
183 /* Arranges the N elements in VALUES into the lexicographically
184 next greater permutation. Returns true if successful.
185 If VALUES is already the lexicographically greatest
186 permutation of its elements (i.e. ordered from greatest to
187 smallest), arranges them into the lexicographically least
188 permutation (i.e. ordered from smallest to largest) and
189 returns false. */
190 static bool
191 next_permutation (int *values, size_t n)
193 if (n > 0)
195 size_t i = n - 1;
196 while (i != 0)
198 i--;
199 if (values[i] < values[i + 1])
201 size_t j;
202 for (j = n - 1; values[i] >= values[j]; j--)
203 continue;
204 swap (values + i, values + j);
205 reverse (values + (i + 1), n - (i + 1));
206 return true;
210 reverse (values, n);
213 return false;
216 /* Returns N!. */
217 static unsigned int
218 factorial (unsigned int n)
220 unsigned int value = 1;
221 while (n > 1)
222 value *= n--;
223 return value;
226 /* Randomly shuffles the N elements in ARRAY, each of which is
227 SIZE bytes in size. */
228 static void
229 random_shuffle (void *array_, size_t n, size_t size)
231 char *array = array_;
232 char *tmp = xmalloc (size);
233 size_t i;
235 for (i = 0; i < n; i++)
237 size_t j = rand () % (n - i) + i;
238 if (i != j)
240 memcpy (tmp, array + j * size, size);
241 memcpy (array + j * size, array + i * size, size);
242 memcpy (array + i * size, tmp, size);
246 free (tmp);
249 /* Finds and returns the element in ABT that is in the given
250 0-based POSITION in in-order. */
251 static struct element *
252 find_by_position (struct abt *abt, int position)
254 struct abt_node *p;
255 for (p = abt->root; p != NULL;)
257 int p_pos = p->down[0] ? abt_node_to_element (p->down[0])->count : 0;
258 if (position == p_pos)
259 return abt_node_to_element (p);
260 else if (position < p_pos)
261 p = p->down[0];
262 else
264 p = p->down[1];
265 position -= p_pos + 1;
268 return NULL;
271 /* Checks that all the augmentations are correct in the subtree
272 rooted at P. Returns the number of nodes in the subtree. */
273 static int
274 check_augmentations (struct abt_node *p_)
276 if (p_ == NULL)
277 return 0;
278 else
280 struct element *p = abt_node_to_element (p_);
281 int left_count = check_augmentations (p->node.down[0]);
282 int right_count = check_augmentations (p->node.down[1]);
283 int total = left_count + right_count + 1;
284 check (p->count == total);
285 return total;
289 /* Check that the levels are correct in the subtree rooted at P. */
290 static void
291 check_levels (struct abt_node *p)
293 if (p != NULL)
295 int i, j;
297 check_levels (p->down[0]);
298 check_levels (p->down[1]);
300 check (p->level >= 1);
301 if (p->level > 1)
303 struct abt_node *q = p->down[1];
304 check (q != NULL);
305 check (q->level == p->level || q->level == p->level - 1);
308 for (i = 0; i < 2; i++)
309 if (p->down[i] != NULL)
310 for (j = 0; j < 2; j++)
311 if (p->down[i]->down[j] != NULL)
312 check (p->down[i]->down[j]->level < p->level);
316 /* Checks that ABT contains the N ints in DATA, that its
317 structure is correct, and that certain operations on ABT
318 produce the expected results. */
319 static void
320 check_abt (struct abt *abt, const int data[], size_t n)
322 struct element e;
323 size_t i;
324 int *order;
326 order = xmemdup (data, n * sizeof *data);
327 qsort (order, n, sizeof *order, compare_ints_noaux);
329 if (abt->compare != NULL)
331 for (i = 0; i < n; i++)
333 struct abt_node *p;
335 e.data = data[i];
336 if (rand () % 2)
337 p = abt_find (abt, &e.node);
338 else
339 p = abt_insert (abt, &e.node);
340 check (p != NULL);
341 check (p != &e.node);
342 check (abt_node_to_element (p)->data == data[i]);
345 e.data = -1;
346 check (abt_find (abt, &e.node) == NULL);
349 check_levels (abt->root);
350 check_augmentations (abt->root);
351 for (i = 0; i < n; i++)
352 check (find_by_position (abt, i)->data == order[i]);
354 if (n == 0)
356 check (abt_first (abt) == NULL);
357 check (abt_last (abt) == NULL);
358 check (abt_next (abt, NULL) == NULL);
359 check (abt_prev (abt, NULL) == NULL);
361 else
363 struct abt_node *p;
365 for (p = abt_first (abt), i = 0; i < n; p = abt_next (abt, p), i++)
366 check (abt_node_to_element (p)->data == order[i]);
367 check (p == NULL);
369 for (p = abt_last (abt), i = 0; i < n; p = abt_prev (abt, p), i++)
370 check (abt_node_to_element (p)->data == order[n - i - 1]);
371 check (p == NULL);
373 check (abt_is_empty (abt) == (n == 0));
375 free (order);
378 /* Ways that nodes can be inserted. */
379 enum insertion_method
381 INSERT, /* With abt_insert. */
382 INSERT_AFTER, /* With abt_insert_after. */
383 INSERT_BEFORE /* With abt_insert_before. */
386 /* Inserts INSERT into ABT with the given METHOD. */
387 static void
388 insert_node (struct abt *abt, struct element *insert,
389 enum insertion_method method)
391 if (method == INSERT)
392 check (abt_insert (abt, &insert->node) == NULL);
393 else
395 struct abt_node *p = abt->root;
396 int dir = 0;
397 if (p != NULL)
398 for (;;)
400 dir = insert->data > abt_node_to_element (p)->data;
401 if (p->down[dir] == NULL)
402 break;
403 p = p->down[dir];
405 if (method == INSERT_AFTER)
407 if (p != NULL && (dir != 1 || p->down[1] != NULL))
408 p = abt_prev (abt, p);
409 abt_insert_after (abt, p, &insert->node);
411 else
413 if (p != NULL && (dir != 0 || p->down[0] != NULL))
414 p = abt_next (abt, p);
415 abt_insert_before (abt, p, &insert->node);
421 /* Inserts the N values from 0 to N - 1 (inclusive) into an
422 ABT in the order specified by INSERTIONS using the given
423 METHOD, then deletes them in the order specified by DELETIONS,
424 checking the ABT's contents for correctness after each
425 operation. */
426 static void
427 do_test_insert_delete (enum insertion_method method,
428 const int insertions[],
429 const int deletions[],
430 size_t n)
432 struct element *elements;
433 struct abt abt;
434 size_t i;
436 elements = xnmalloc (n, sizeof *elements);
437 for (i = 0; i < n; i++)
438 elements[i].data = i;
440 abt_init (&abt, method == INSERT ? compare_elements : NULL,
441 reaugment_elements, &aux_data);
442 check_abt (&abt, NULL, 0);
443 for (i = 0; i < n; i++)
445 insert_node (&abt, &elements[insertions[i]], method);
446 check_abt (&abt, insertions, i + 1);
448 for (i = 0; i < n; i++)
450 abt_delete (&abt, &elements[deletions[i]].node);
451 check_abt (&abt, deletions + i + 1, n - i - 1);
454 free (elements);
457 /* Inserts the N values from 0 to N - 1 (inclusive) into an
458 ABT in the order specified by INSERTIONS, then deletes them in
459 the order specified by DELETIONS, checking the ABT's contents
460 for correctness after each operation. */
461 static void
462 test_insert_delete (const int insertions[],
463 const int deletions[],
464 size_t n)
466 do_test_insert_delete (INSERT, insertions, deletions, n);
467 do_test_insert_delete (INSERT_AFTER, insertions, deletions, n);
468 do_test_insert_delete (INSERT_BEFORE, insertions, deletions, n);
471 /* Inserts values into an ABT in each possible order, then
472 removes them in each possible order, up to a specified maximum
473 size. */
474 static void
475 test_insert_any_remove_any (void)
477 const int max_elems = 5;
478 int n;
480 for (n = 0; n <= max_elems; n++)
482 int *insertions, *deletions;
483 unsigned int ins_n_perms;
484 int i;
486 insertions = xnmalloc (n, sizeof *insertions);
487 deletions = xnmalloc (n, sizeof *deletions);
488 for (i = 0; i < n; i++)
489 insertions[i] = i;
491 for (ins_n_perms = 0;
492 ins_n_perms == 0 || next_permutation (insertions, n);
493 ins_n_perms++)
495 unsigned int del_n_perms;
496 int i;
498 for (i = 0; i < n; i++)
499 deletions[i] = i;
501 for (del_n_perms = 0;
502 del_n_perms == 0 || next_permutation (deletions, n);
503 del_n_perms++)
504 test_insert_delete (insertions, deletions, n);
506 check (del_n_perms == factorial (n));
508 check (ins_n_perms == factorial (n));
510 free (insertions);
511 free (deletions);
515 /* Inserts values into an ABT in each possible order, then
516 removes them in the same order, up to a specified maximum
517 size. */
518 static void
519 test_insert_any_remove_same (void)
521 const int max_elems = 7;
522 int n;
524 for (n = 0; n <= max_elems; n++)
526 int *values;
527 unsigned int n_permutations;
528 int i;
530 values = xnmalloc (n, sizeof *values);
531 for (i = 0; i < n; i++)
532 values[i] = i;
534 for (n_permutations = 0;
535 n_permutations == 0 || next_permutation (values, n);
536 n_permutations++)
537 test_insert_delete (values, values, n);
538 check (n_permutations == factorial (n));
540 free (values);
544 /* Inserts values into an ABT in each possible order, then
545 removes them in reverse order, up to a specified maximum
546 size. */
547 static void
548 test_insert_any_remove_reverse (void)
550 const int max_elems = 7;
551 int n;
553 for (n = 0; n <= max_elems; n++)
555 int *insertions, *deletions;
556 unsigned int n_permutations;
557 int i;
559 insertions = xnmalloc (n, sizeof *insertions);
560 deletions = xnmalloc (n, sizeof *deletions);
561 for (i = 0; i < n; i++)
562 insertions[i] = i;
564 for (n_permutations = 0;
565 n_permutations == 0 || next_permutation (insertions, n);
566 n_permutations++)
568 memcpy (deletions, insertions, sizeof *insertions * n);
569 reverse (deletions, n);
571 test_insert_delete (insertions, deletions, n);
573 check (n_permutations == factorial (n));
575 free (insertions);
576 free (deletions);
580 /* Inserts and removes values in an ABT in random orders. */
581 static void
582 test_random_sequence (void)
584 const int max_elems = 128;
585 const int max_trials = 8;
586 int n;
588 for (n = 0; n <= max_elems; n += 2)
590 int *insertions, *deletions;
591 int trial;
592 int i;
594 insertions = xnmalloc (n, sizeof *insertions);
595 deletions = xnmalloc (n, sizeof *deletions);
596 for (i = 0; i < n; i++)
597 insertions[i] = i;
598 for (i = 0; i < n; i++)
599 deletions[i] = i;
601 for (trial = 0; trial < max_trials; trial++)
603 random_shuffle (insertions, n, sizeof *insertions);
604 random_shuffle (deletions, n, sizeof *deletions);
606 test_insert_delete (insertions, deletions, n);
609 free (insertions);
610 free (deletions);
614 /* Inserts elements into an ABT in ascending order. */
615 static void
616 test_insert_ordered (void)
618 const int max_elems = 1024;
619 struct element *elements;
620 int *values;
621 struct abt abt;
622 int i;
624 abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
625 elements = xnmalloc (max_elems, sizeof *elements);
626 values = xnmalloc (max_elems, sizeof *values);
627 for (i = 0; i < max_elems; i++)
629 values[i] = elements[i].data = i;
630 check (abt_insert (&abt, &elements[i].node) == NULL);
631 check_abt (&abt, values, i + 1);
633 free (elements);
634 free (values);
637 /* Inserts elements into an ABT, then moves the nodes around in
638 memory. */
639 static void
640 test_moved (void)
642 const int max_elems = 128;
643 struct element *e[2];
644 int cur;
645 int *values;
646 struct abt abt;
647 int i, j;
649 abt_init (&abt, compare_elements, reaugment_elements, &aux_data);
650 e[0] = xnmalloc (max_elems, sizeof *e[0]);
651 e[1] = xnmalloc (max_elems, sizeof *e[1]);
652 values = xnmalloc (max_elems, sizeof *values);
653 cur = 0;
654 for (i = 0; i < max_elems; i++)
656 values[i] = e[cur][i].data = i;
657 check (abt_insert (&abt, &e[cur][i].node) == NULL);
658 check_abt (&abt, values, i + 1);
660 for (j = 0; j <= i; j++)
662 e[!cur][j] = e[cur][j];
663 abt_moved (&abt, &e[!cur][j].node);
664 check_abt (&abt, values, i + 1);
666 cur = !cur;
668 free (e[0]);
669 free (e[1]);
670 free (values);
673 /* Inserts values into an ABT, then changes their values. */
674 static void
675 test_changed (void)
677 const int max_elems = 6;
678 int n;
680 for (n = 0; n <= max_elems; n++)
682 int *values, *changed_values;
683 struct element *elements;
684 unsigned int n_permutations;
685 int i;
687 values = xnmalloc (n, sizeof *values);
688 changed_values = xnmalloc (n, sizeof *changed_values);
689 elements = xnmalloc (n, sizeof *elements);
690 for (i = 0; i < n; i++)
691 values[i] = i;
693 for (n_permutations = 0;
694 n_permutations == 0 || next_permutation (values, n);
695 n_permutations++)
697 for (i = 0; i < n; i++)
699 int j, k;
700 for (j = 0; j <= n; j++)
702 struct abt abt;
703 struct abt_node *changed_retval;
705 abt_init (&abt, compare_elements, reaugment_elements,
706 &aux_data);
708 /* Add to ABT in order. */
709 for (k = 0; k < n; k++)
711 int n = values[k];
712 elements[n].data = n;
713 check (abt_insert (&abt, &elements[n].node) == NULL);
715 check_abt (&abt, values, n);
717 /* Change value i to j. */
718 elements[i].data = j;
719 for (k = 0; k < n; k++)
720 changed_values[k] = k;
721 changed_retval = abt_changed (&abt, &elements[i].node);
722 if (i != j && j < n)
724 /* Will cause duplicate. */
725 check (changed_retval == &elements[j].node);
726 changed_values[i] = changed_values[n - 1];
727 check_abt (&abt, changed_values, n - 1);
729 else
731 /* Succeeds. */
732 check (changed_retval == NULL);
733 changed_values[i] = j;
734 check_abt (&abt, changed_values, n);
739 check (n_permutations == factorial (n));
741 free (values);
742 free (changed_values);
743 free (elements);
747 /* Main program. */
749 struct test
751 const char *name;
752 const char *description;
753 void (*function) (void);
756 static const struct test tests[] =
759 "insert-any-remove-any",
760 "insert any order, delete any order",
761 test_insert_any_remove_any
764 "insert-any-remove-same",
765 "insert any order, delete same order",
766 test_insert_any_remove_same
769 "insert-any-remove-reverse",
770 "insert any order, delete reverse order",
771 test_insert_any_remove_reverse
774 "random-sequence",
775 "insert and delete in random sequence",
776 test_random_sequence
779 "insert-ordered",
780 "insert in ascending order",
781 test_insert_ordered
784 "moved",
785 "move elements around in memory",
786 test_moved
789 "changed",
790 "change key data in nodes",
791 test_changed
795 enum { N_TESTS = sizeof tests / sizeof *tests };
798 main (int argc, char *argv[])
800 int i;
802 if (argc != 2)
804 fprintf (stderr, "exactly one argument required; use --help for help\n");
805 return EXIT_FAILURE;
807 else if (!strcmp (argv[1], "--help"))
809 printf ("%s: test augmented binary tree\n"
810 "usage: %s TEST-NAME\n"
811 "where TEST-NAME is one of the following:\n",
812 argv[0], argv[0]);
813 for (i = 0; i < N_TESTS; i++)
814 printf (" %s\n %s\n", tests[i].name, tests[i].description);
815 return 0;
817 else
819 for (i = 0; i < N_TESTS; i++)
820 if (!strcmp (argv[1], tests[i].name))
822 tests[i].function ();
823 return 0;
826 fprintf (stderr, "unknown test %s; use --help for help\n", argv[1]);
827 return EXIT_FAILURE;