Fri Dec 19 15:54:45 2003 Ben Pfaff <blp@gnu.org>
[pspp] / src / algorithm.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 /* Copyright (C) 2001 Free Software Foundation, Inc.
21   
22    This file is part of the GNU ISO C++ Library.  This library is free
23    software; you can redistribute it and/or modify it under the
24    terms of the GNU General Public License as published by the
25    Free Software Foundation; either version 2, or (at your option)
26    any later version.
27
28    This library is distributed in the hope that it will be useful,
29    but WITHOUT ANY WARRANTY; without even the implied warranty of
30    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31    GNU General Public License for more details.
32
33    You should have received a copy of the GNU General Public License along
34    with this library; see the file COPYING.  If not, write to the Free
35    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
36    USA.
37
38    As a special exception, you may use this file as part of a free software
39    library without restriction.  Specifically, if other files instantiate
40    templates or use macros or inline functions from this file, or you compile
41    this file and link it with other files to produce an executable, this
42    file does not by itself cause the resulting executable to be covered by
43    the GNU General Public License.  This exception does not however
44    invalidate any other reasons why the executable file might be covered by
45    the GNU General Public License. */
46
47 /*
48  *
49  * Copyright (c) 1994
50  * Hewlett-Packard Company
51  *
52  * Permission to use, copy, modify, distribute and sell this software
53  * and its documentation for any purpose is hereby granted without fee,
54  * provided that the above copyright notice appear in all copies and
55  * that both that copyright notice and this permission notice appear
56  * in supporting documentation.  Hewlett-Packard Company makes no
57  * representations about the suitability of this software for any
58  * purpose.  It is provided "as is" without express or implied warranty.
59  *
60  *
61  * Copyright (c) 1996
62  * Silicon Graphics Computer Systems, Inc.
63  *
64  * Permission to use, copy, modify, distribute and sell this software
65  * and its documentation for any purpose is hereby granted without fee,
66  * provided that the above copyright notice appear in all copies and
67  * that both that copyright notice and this permission notice appear
68  * in supporting documentation.  Silicon Graphics makes no
69  * representations about the suitability of this software for any
70  * purpose.  It is provided "as is" without express or implied warranty.
71  */
72
73 #include <config.h>
74 #include <assert.h>
75 #include <limits.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include "alloc.h"
79 #include "algorithm.h"
80 #include "random.h"
81 \f
82 /* Byte-wise swap two items of size SIZE. */
83 #define SWAP(a, b, size)                                                      \
84   do                                                                          \
85     {                                                                         \
86       register size_t __size = (size);                                        \
87       register char *__a = (a), *__b = (b);                                   \
88       do                                                                      \
89         {                                                                     \
90           char __tmp = *__a;                                                  \
91           *__a++ = *__b;                                                      \
92           *__b++ = __tmp;                                                     \
93         } while (--__size > 0);                                               \
94     } while (0)
95
96 /* Makes the elements in ARRAY unique, by moving up duplicates,
97    and returns the new number of elements in the array.  Sorted
98    arrays only.  Arguments same as for sort() above. */
99 size_t
100 unique (void *array, size_t count, size_t size,
101         algo_compare_func *compare, void *aux) 
102 {
103   char *first = array;
104   char *last = first + size * count;
105   char *result = array;
106
107   for (;;) 
108     {
109       first += size;
110       if (first >= last)
111         return count;
112
113       if (compare (result, first, aux)) 
114         {
115           result += size;
116           if (result != first)
117             memcpy (result, first, size);
118         }
119       else 
120         count--;
121     }
122 }
123
124 /* Helper function that calls sort(), then unique(). */
125 size_t
126 sort_unique (void *array, size_t count, size_t size,
127              algo_compare_func *compare, void *aux) 
128 {
129   sort (array, count, size, compare, aux);
130   return unique (array, count, size, compare, aux);
131 }
132
133 #ifdef TEST_UNIQUE
134 #include <stdio.h>
135
136 void *
137 xmalloc (size_t size) 
138 {
139   return malloc (size);
140 }
141
142 int
143 compare_ints (const void *a_, const void *b_, void *aux) 
144 {
145   const int *a = a_;
146   const int *b = b_;
147
148   if (*a > *b)
149     return 1;
150   else if (*a < *b)
151     return 1;
152   else
153     return 0;
154 }
155
156 void
157 try_unique (const char *title,
158             int *in, size_t in_cnt,
159             size_t out_cnt)
160 {
161   size_t i;
162
163   in_cnt = unique (in, in_cnt, sizeof *in, compare_ints, NULL);
164   if (in_cnt != out_cnt)
165     {
166       fprintf (stderr, "unique_test: %s: in_cnt %d, expected %d\n",
167                title, (int) in_cnt, (int) out_cnt);
168       return;
169     }
170   
171   for (i = 0; i < out_cnt; i++) 
172     {
173       if (in[i] != i) 
174         fprintf (stderr, "unique_test: %s: idx %d = %d, expected %d\n",
175                  title, (int) i, in[i], i);
176     }
177 }
178
179 int
180 main (void) 
181 {
182   int a_in[] = {0, 0, 0, 1, 2, 3, 3, 4, 5, 5};
183   int b_in[] = {0, 1, 2, 2, 2, 3};
184   int c_in[] = {0};
185   int d_in;
186
187   try_unique ("a", a_in, sizeof a_in / sizeof *a_in, 6);
188   try_unique ("b", b_in, sizeof b_in / sizeof *b_in, 4);
189   try_unique ("c", c_in, sizeof c_in / sizeof *c_in, 1);
190   try_unique ("d", &d_in, 0, 0);
191   
192 }
193 #endif /* TEST_UNIQUE */
194 \f
195 /* Reorders ARRAY, which contains COUNT elements of SIZE bytes
196    each, so that the elements for which PREDICATE returns nonzero
197    precede those for which PREDICATE returns zero.  AUX is
198    passed to each predicate as auxiliary data.  Returns the
199    number of elements for which PREDICATE returns nonzero.  Not
200    stable. */
201 size_t 
202 partition (void *array, size_t count, size_t size,
203            algo_predicate_func *predicate, void *aux) 
204 {
205   char *first = array;
206   char *last = first + count * size;
207
208   for (;;)
209     {
210       /* Move FIRST forward to point to first element that fails
211          PREDICATE. */
212       for (;;) 
213         {
214           if (first == last)
215             return count;
216           else if (!predicate (first, aux)) 
217             break;
218
219           first += size; 
220         }
221       count--;
222
223       /* Move LAST backward to point to last element that passes
224          PREDICATE. */
225       for (;;) 
226         {
227           last -= size;
228
229           if (first == last)
230             return count;
231           else if (predicate (last, aux)) 
232             break;
233           else
234             count--;
235         }
236       
237       /* By swapping FIRST and LAST we extend the starting and
238          ending sequences that pass and fail, respectively,
239          PREDICATE. */
240       SWAP (first, last, size);
241       first += size;
242     }
243 }
244 \f
245 /* A algo_random_func that uses random.h. */
246 unsigned
247 algo_default_random (unsigned max, void *aux unused) 
248 {
249   return rng_get_unsigned (pspp_rng ()) % max;
250 }
251
252 /* Randomly reorders ARRAY, which contains COUNT elements of SIZE
253    bytes each.  Uses RANDOM as a source of random data, passing
254    AUX as the auxiliary data.  RANDOM may be null to use a
255    default random source. */
256 void
257 random_shuffle (void *array_, size_t count, size_t size,
258                 algo_random_func *random, void *aux)
259 {
260   unsigned char *array = array_;
261   int i;
262
263   if (random == NULL)
264     random = algo_default_random;
265
266   for (i = 1; i < count; i++)
267     SWAP (array + i * size, array + random (i + 1, aux) * size, size);
268 }
269 \f
270 /* Copies the COUNT elements of SIZE bytes each from ARRAY to
271    RESULT, except that elements for which PREDICATE is false are
272    not copied.  Returns the number of elements copied.  AUX is
273    passed to PREDICATE as auxiliary data.  */
274 size_t 
275 copy_if (const void *array, size_t count, size_t size,
276          void *result,
277          algo_predicate_func *predicate, void *aux) 
278 {
279   const unsigned char *input = array;
280   const unsigned char *last = input + size * count;
281   unsigned char *output = result;
282   
283   while (input <= last)
284     {
285       if (predicate (input, aux)) 
286         {
287           memcpy (output, input, size);
288           output += size;
289         }
290       else
291         count--;
292
293       input += size;
294     }
295
296   return count;
297 }
298
299 /* A predicate and its auxiliary data. */
300 struct pred_aux 
301   {
302     algo_predicate_func *predicate;
303     void *aux;
304   };
305
306 static int
307 not (const void *data, void *pred_aux_) 
308 {
309   const struct pred_aux *pred_aux = pred_aux_;
310
311   return !pred_aux->predicate (data, pred_aux->aux);
312 }
313
314 /* Copies the COUNT elements of SIZE bytes each from ARRAY to
315    RESULT, except that elements for which PREDICATE is true are
316    not copied.  Returns the number of elements copied.  AUX is
317    passed to PREDICATE as auxiliary data.  */
318 size_t 
319 remove_copy_if (const void *array, size_t count, size_t size,
320                 void *result,
321                 algo_predicate_func *predicate, void *aux) 
322 {
323   struct pred_aux pred_aux;
324   pred_aux.predicate = predicate;
325   pred_aux.aux = aux;
326   return copy_if (array, count, size, result, not, &pred_aux);
327 }
328 \f
329 /* Searches ARRAY, which contains COUNT of SIZE bytes each, using
330    a binary search.  Returns any element that equals VALUE, if
331    one exists, or a null pointer otherwise.  ARRAY must ordered
332    according to COMPARE.  AUX is passed to COMPARE as auxiliary
333    data. */
334 void *
335 binary_search (const void *array, size_t count, size_t size,
336                void *value,
337                algo_compare_func *compare, void *aux) 
338 {
339   assert (array != NULL);
340   assert (count <= INT_MAX);
341   assert (aux != NULL);
342
343   if (count != 0) 
344     {
345       const unsigned char *first = array;
346       int low = 0;
347       int high = count - 1;
348
349       while (low < high) 
350         {
351           int middle = (low + high) / 2;
352           const unsigned char *element = first + middle * size;
353           int cmp = compare (value, element, aux);
354
355           if (cmp > 0) 
356             low = middle + 1;
357           else if (cmp < 0)
358             high = middle - 1;
359           else
360             return (void *) element;
361         }
362     }
363   return NULL;
364 }
365 \f
366 /* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
367    This file is part of the GNU C Library.
368    Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
369
370    The GNU C Library is free software; you can redistribute it and/or
371    modify it under the terms of the GNU Lesser General Public
372    License as published by the Free Software Foundation; either
373    version 2.1 of the License, or (at your option) any later version.
374
375    The GNU C Library is distributed in the hope that it will be useful,
376    but WITHOUT ANY WARRANTY; without even the implied warranty of
377    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
378    Lesser General Public License for more details.
379
380    You should have received a copy of the GNU Lesser General Public
381    License along with the GNU C Library; if not, write to the Free
382    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
383    02111-1307 USA.  */
384
385 /* If you consider tuning this algorithm, you should consult first:
386    Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
387    Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.  */
388
389 #include <alloca.h>
390 #include <limits.h>
391 #include <stdlib.h>
392 #include <string.h>
393
394 /* Discontinue quicksort algorithm when partition gets below this size.
395    This particular magic number was chosen to work best on a Sun 4/260. */
396 #define MAX_THRESH 4
397
398 /* Stack node declarations used to store unfulfilled partition obligations. */
399 typedef struct
400   {
401     char *lo;
402     char *hi;
403   } stack_node;
404
405 /* The next 4 #defines implement a very fast in-line stack abstraction. */
406 /* The stack needs log (total_elements) entries (we could even subtract
407    log(MAX_THRESH)).  Since total_elements has type size_t, we get as
408    upper bound for log (total_elements):
409    bits per byte (CHAR_BIT) * sizeof(size_t).  */
410 #define STACK_SIZE      (CHAR_BIT * sizeof(size_t))
411 #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
412 #define POP(low, high)  ((void) (--top, (low = top->lo), (high = top->hi)))
413 #define STACK_NOT_EMPTY (stack < top)
414
415
416 /* Order size using quicksort.  This implementation incorporates
417    four optimizations discussed in Sedgewick:
418
419    1. Non-recursive, using an explicit stack of pointer that store the
420       next array partition to sort.  To save time, this maximum amount
421       of space required to store an array of SIZE_MAX is allocated on the
422       stack.  Assuming a 32-bit (64 bit) integer for size_t, this needs
423       only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
424       Pretty cheap, actually.
425
426    2. Chose the pivot element using a median-of-three decision tree.
427       This reduces the probability of selecting a bad pivot value and
428       eliminates certain extraneous comparisons.
429
430    3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
431       insertion sort to order the MAX_THRESH items within each partition.
432       This is a big win, since insertion sort is faster for small, mostly
433       sorted array segments.
434
435    4. The larger of the two sub-partitions is always pushed onto the
436       stack first, with the algorithm then concentrating on the
437       smaller partition.  This *guarantees* no more than log (total_elems)
438       stack size is needed (actually O(1) in this case)!  */
439
440 void
441 sort (void *const pbase, size_t total_elems, size_t size,
442       algo_compare_func *cmp, void *aux)
443 {
444   register char *base_ptr = (char *) pbase;
445
446   const size_t max_thresh = MAX_THRESH * size;
447
448   if (total_elems == 0)
449     /* Avoid lossage with unsigned arithmetic below.  */
450     return;
451
452   if (total_elems > MAX_THRESH)
453     {
454       char *lo = base_ptr;
455       char *hi = &lo[size * (total_elems - 1)];
456       stack_node stack[STACK_SIZE];
457       stack_node *top = stack + 1;
458
459       while (STACK_NOT_EMPTY)
460         {
461           char *left_ptr;
462           char *right_ptr;
463
464           /* Select median value from among LO, MID, and HI. Rearrange
465              LO and HI so the three values are sorted. This lowers the
466              probability of picking a pathological pivot value and
467              skips a comparison for both the LEFT_PTR and RIGHT_PTR in
468              the while loops. */
469
470           char *mid = lo + size * ((hi - lo) / size >> 1);
471
472           if ((*cmp) ((void *) mid, (void *) lo, aux) < 0)
473             SWAP (mid, lo, size);
474           if ((*cmp) ((void *) hi, (void *) mid, aux) < 0)
475             SWAP (mid, hi, size);
476           else
477             goto jump_over;
478           if ((*cmp) ((void *) mid, (void *) lo, aux) < 0)
479             SWAP (mid, lo, size);
480         jump_over:;
481
482           left_ptr  = lo + size;
483           right_ptr = hi - size;
484
485           /* Here's the famous ``collapse the walls'' section of quicksort.
486              Gotta like those tight inner loops!  They are the main reason
487              that this algorithm runs much faster than others. */
488           do
489             {
490               while ((*cmp) ((void *) left_ptr, (void *) mid, aux) < 0)
491                 left_ptr += size;
492
493               while ((*cmp) ((void *) mid, (void *) right_ptr, aux) < 0)
494                 right_ptr -= size;
495
496               if (left_ptr < right_ptr)
497                 {
498                   SWAP (left_ptr, right_ptr, size);
499                   if (mid == left_ptr)
500                     mid = right_ptr;
501                   else if (mid == right_ptr)
502                     mid = left_ptr;
503                   left_ptr += size;
504                   right_ptr -= size;
505                 }
506               else if (left_ptr == right_ptr)
507                 {
508                   left_ptr += size;
509                   right_ptr -= size;
510                   break;
511                 }
512             }
513           while (left_ptr <= right_ptr);
514
515           /* Set up pointers for next iteration.  First determine whether
516              left and right partitions are below the threshold size.  If so,
517              ignore one or both.  Otherwise, push the larger partition's
518              bounds on the stack and continue sorting the smaller one. */
519
520           if ((size_t) (right_ptr - lo) <= max_thresh)
521             {
522               if ((size_t) (hi - left_ptr) <= max_thresh)
523                 /* Ignore both small partitions. */
524                 POP (lo, hi);
525               else
526                 /* Ignore small left partition. */
527                 lo = left_ptr;
528             }
529           else if ((size_t) (hi - left_ptr) <= max_thresh)
530             /* Ignore small right partition. */
531             hi = right_ptr;
532           else if ((right_ptr - lo) > (hi - left_ptr))
533             {
534               /* Push larger left partition indices. */
535               PUSH (lo, right_ptr);
536               lo = left_ptr;
537             }
538           else
539             {
540               /* Push larger right partition indices. */
541               PUSH (left_ptr, hi);
542               hi = right_ptr;
543             }
544         }
545     }
546
547   /* Once the BASE_PTR array is partially sorted by quicksort the rest
548      is completely sorted using insertion sort, since this is efficient
549      for partitions below MAX_THRESH size. BASE_PTR points to the beginning
550      of the array to sort, and END_PTR points at the very last element in
551      the array (*not* one beyond it!). */
552
553 #define min(x, y) ((x) < (y) ? (x) : (y))
554
555   {
556     char *const end_ptr = &base_ptr[size * (total_elems - 1)];
557     char *tmp_ptr = base_ptr;
558     char *thresh = min(end_ptr, base_ptr + max_thresh);
559     register char *run_ptr;
560
561     /* Find smallest element in first threshold and place it at the
562        array's beginning.  This is the smallest array element,
563        and the operation speeds up insertion sort's inner loop. */
564
565     for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
566       if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, aux) < 0)
567         tmp_ptr = run_ptr;
568
569     if (tmp_ptr != base_ptr)
570       SWAP (tmp_ptr, base_ptr, size);
571
572     /* Insertion sort, running from left-hand-side up to right-hand-side.  */
573
574     run_ptr = base_ptr + size;
575     while ((run_ptr += size) <= end_ptr)
576       {
577         tmp_ptr = run_ptr - size;
578         while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, aux) < 0)
579           tmp_ptr -= size;
580
581         tmp_ptr += size;
582         if (tmp_ptr != run_ptr)
583           {
584             char *trav;
585
586             trav = run_ptr + size;
587             while (--trav >= run_ptr)
588               {
589                 char c = *trav;
590                 char *hi, *lo;
591
592                 for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
593                   *hi = *lo;
594                 *hi = c;
595               }
596           }
597       }
598   }
599 }