casacore
Loading...
Searching...
No Matches
GenSort.h
Go to the documentation of this file.
1// # GenSort.h: General sort functions
2// # Copyright (C) 1993,1994,1995,1996,1997,1999
3// # Associated Universities, Inc. Washington DC, USA.
4// #
5// # This library is free software; you can redistribute it and/or modify it
6// # under the terms of the GNU Library General Public License as published by
7// # the Free Software Foundation; either version 2 of the License, or (at your
8// # option) any later version.
9// #
10// # This library is distributed in the hope that it will be useful, but WITHOUT
11// # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12// # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13// # License for more details.
14// #
15// # You should have received a copy of the GNU Library General Public License
16// # along with this library; if not, write to the Free Software Foundation,
17// # Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18// #
19// # Correspondence concerning AIPS++ should be addressed as follows:
20// # Internet email: casa-feedback@nrao.edu.
21// # Postal address: AIPS++ Project Office
22// # National Radio Astronomy Observatory
23// # 520 Edgemont Road
24// # Charlottesville, VA 22903-2475 USA
25
26#ifndef CASA_GENSORT_H
27#define CASA_GENSORT_H
28
29#include <casacore/casa/aips.h>
30#include <casacore/casa/Arrays/ArrayFwd.h>
31#include <casacore/casa/Utilities/Sort.h>
32
33namespace casacore { // # NAMESPACE CASACORE - BEGIN
34
35// # Forward declarations.
36template <class T>
37class Block;
38
39// <summary> General in-place sort functions </summary>
40// <use visibility=local>
41// <reviewed reviewer="Friso Olnon" date="1995/03/16" tests="tGenSort" demos="">
42
43// <synopsis>
44//
45// The static member functions of this templated class are highly optimized
46// sort functions. They do an in-place sort of an array of values. The
47// functions are templated, so they can in principle be used with any
48// data type. However, if used with non-builtin data types, their
49// class must provide certain functions (see <em>Template Type Argument
50// Requirements</em>).
51//
52// If it is impossible or too expensive to define these functions, the
53// <linkto class=Sort>Sort</linkto> class can be used instead. This sorts
54// indirectly using an index array. Instead of the functions mentioned
55// above it requires a comparison routine.
56//
57// The <src>GenSort</src> functions can sort:
58// <ul>
59// <li> C-arrays of values;
60// <li> <src>Array</src>s of values -- the array can have any shape
61// and the increment can be >1;
62// <li> <src>Block</src>s of values -- there is a special function to
63// sort less elements than the size of the <src>Block</src>.
64// </ul>
65//
66// The sort order can be specified in the order field:
67// <dl>
68// <dt> <src>Sort::Ascending</src> (default),
69// <dt> <src>Sort::Descending</src>.
70// </dl>
71//
72// Previously the sort algorithm to use could be given in the options field.
73// <dl>
74// <dt> <src>Sort::QuickSort</src> (default)
75// <dd> is the fastest. It is about 4-6 times faster
76// than the qsort function on the SUN. No worst case has been
77// found, even not for cases where qsort is terribly slow.
78// <dt> <src>Sort::HeapSort</src>
79// <dd> is about twice as slow as quicksort.
80// It has the advantage that the worst case is always o(n*log(n)),
81// while quicksort can have hypothetical inputs with o(n*n).
82// <dt> <src>Sort::InsSort</src>
83// <dd> is o(n*n) for random inputs. It is, however, the
84// only stable sort (i.e. equal values remain in the original order).
85// </dl>
86// However, these options are not used anymore because the sort now always
87// uses a merge sort that is equally fast for random input and much faster for
88// degenerated cases like an already ordered or reversely ordered array.
89// Furthermore, merge sort is always stable and will be parallelized if OpenMP
90// support is enabled giving a 6-fold speedup on 8 cores.
91// <br><src>Sort::NoDuplicates</src> in the options field indicates that
92// duplicate values will be removed (only the first occurrance is kept).
93// <br>The previous sort functionality is still available through the functions
94// quickSort, heapSort, and insSort.
95// <p>
96// All the sort functions return the number of values sorted as their
97// function value; when duplicate values have been removed, the number of
98// unique valuess will be returned.
99// <p>
100// The class also provides a function to find the k-th largest value
101// in an array of values. This uses a stripped-down version of quicksort
102// and is at least 6 times faster than a full quicksort.
103// </synopsis>
104
105// <templating arg=T>
106// <li> <src>operator=</src> to assign when swapping elements
107// <li> <src>operator<</src>, <src>operator></src> and
108// <src>operator==</src> to compare elements
109// <li> default constructor to allocate a temporary
110// </templating>
111
112template <class T>
113class GenSort {
114 public:
115 // Sort a C-array containing <src>nr</src> <src>T</src>-type objects.
116 // The sort is done in place and is always stable (thus equal keys keep
117 // their original order). It returns the number of values, which
118 // can be different if a NoDuplicates sort is done.
119 // <br>Insertion sort is used for short arrays (<50 elements). Otherwise,
120 // a merge sort is used which will be parallelized if casacore is built
121 // with OpenMP support.
122 // <group>
123 static uInt sort(T*, uInt nr, Sort::Order = Sort::Ascending, int options = 0);
124
125 static uInt sort(Array<T>&, Sort::Order = Sort::Ascending, int options = 0);
126
127 static uInt sort(Block<T>&, uInt nr, Sort::Order = Sort::Ascending, int options = 0);
128 // <group>
129
130 // Find the k-th largest value.
131 // <br>Note: it does a partial quicksort, thus the data array gets changed.
132 static T kthLargest(T* data, uInt nr, uInt k);
133
134 // Sort C-array using quicksort.
135 static uInt quickSort(T*, uInt nr, Sort::Order = Sort::Ascending, int options = 0);
136 // Sort C-array using heapsort.
137 static uInt heapSort(T*, uInt nr, Sort::Order = Sort::Ascending, int options = 0);
138 // Sort C-array using insertion sort.
139 static uInt insSort(T*, uInt nr, Sort::Order = Sort::Ascending, int options = 0);
140 // Sort C-array using parallel merge sort (using OpenMP).
141 // By default OpenMP determines the number of threads that can be used.
142 static uInt parSort(T*, uInt nr, Sort::Order = Sort::Ascending, int options = 0, int nthread = 0);
143
144 // Swap 2 elements in array.
145 static inline void swap(T&, T&);
146
147 // Reverse the elements in <src>res</src> and put them into <src>data</src>.
148 // Care is taken if both pointers reference the same data.
149 static void reverse(T* data, const T* res, uInt nrrec);
150
151 private:
152 // The<src>data</src> buffer is divided in <src>nparts</src> parts.
153 // In each part the values are in ascending order.
154 // The index tells the nr of elements in each part.
155 // Recursively each two subsequent parts are merged until only part is left
156 // (giving the sorted array). Alternately <src>data</src> and <src>tmp</src>
157 // are used for the merge result. The pointer containing the final result
158 // is returned.
159 // <br>If possible, merging the parts is done in parallel (using OpenMP).
160 static T* merge(T* data, T* tmp, uInt nrrec, uInt* index, uInt nparts);
161
162 // Quicksort in ascending order.
163 static void quickSortAsc(T*, Int, Bool multiThread = False, Int rec_lim = 128);
164
165 // Heapsort in ascending order.
166 static void heapSortAsc(T*, Int);
167 // Helper function for ascending heapsort.
168 static void heapAscSiftDown(Int, Int, T*);
169
170 // Insertion sort in ascending order.
171 static uInt insSortAsc(T*, Int, int option);
172 // Insertion sort in ascending order allowing duplicates.
173 // This is also used by quicksort for its last steps.
174 static uInt insSortAscDup(T*, Int);
175 // Insertion sort in ascending order allowing no duplicates.
176 // This is also used by the other sort algorithms to skip duplicates.
178};
179
180// <summary> General indirect sort functions </summary>
181// <use visibility=local>
182// <reviewed reviewer="" date="" tests="" demos="">
183
184// <synopsis>
185// This class is similar to <linkto class=GenSort>GenSort</linkto>.
186// The only difference is that the functions in this class sort
187// indirectly instead of in-place.
188// They return the result of the sort as an sorted vector of indices
189// This is slower, because an extra indirection is involved in each
190// comparison. However, this sort allows to sort const data.
191// Another advantage is that this sort is always stable (i.e. equal
192// values are kept in their original order).
193//
194// The class is templated on the type T of the sort key and the type
195// INX of the index vector. In principle INX can be any type, but
196// it should be a sufficiently large integer type (say uInt or uInt64).
197template <class T, class INX = uInt>
199 public:
200 // Sort a C-array containing <src>nr</src> <src>T</src>-type objects.
201 // The resulting index vector gives the sorted indices.
202 static INX sort(Vector<INX>& indexVector, const T* data, INX nr, Sort::Order = Sort::Ascending,
203 int options = Sort::QuickSort);
204
205 // Sort a C-array containing <src>nr</src> <src>T</src>-type objects.
206 // The resulting index vector gives the sorted indices.
207 static INX sort(Vector<INX>& indexVector, const Array<T>& data, Sort::Order = Sort::Ascending,
208 int options = Sort::QuickSort);
209
210 // Sort a C-array containing <src>nr</src> <src>T</src>-type objects.
211 // The resulting index vector gives the sorted indices.
212 static INX sort(Vector<INX>& indexVector, const Block<T>& data, INX nr,
214
215 // Find the index of the k-th largest value.
216 static INX kthLargest(T* data, INX nr, INX k);
217
218 // Sort container using quicksort.
219 // The argument <src>inx</src> gives the index defining the order of the
220 // values in the data array. Its length must be at least <src>nr</src>
221 // and it must be filled with the index values of the data.
222 // Usually this is 0..nr, but it could contain a selection of the data.
223 static INX quickSort(INX* inx, const T* data, INX nr, Sort::Order, int options);
224 // Sort container using heapsort.
225 static INX heapSort(INX* inx, const T* data, INX nr, Sort::Order, int options);
226 // Sort container using insertion sort.
227 static INX insSort(INX* inx, const T* data, INX nr, Sort::Order, int options);
228 // Sort container using parallel merge sort (using OpenMP).
229 // By default the maximum number of threads is used.
230 static INX parSort(INX* inx, const T* data, INX nr, Sort::Order, int options, int nthreads = 0);
231
232 private:
233 // Swap 2 indices.
234 static inline void swapInx(INX& index1, INX& index2);
235
236 // The<src>data</src> buffer is divided in <src>nparts</src> parts.
237 // In each part the values are in ascending order.
238 // The index tells the nr of elements in each part.
239 // Recursively each two subsequent parts are merged until only part is left
240 // (giving the sorted array). Alternately <src>data</src> and <src>tmp</src>
241 // are used for the merge result. The pointer containing the final result
242 // is returned.
243 // <br>If possible, merging the parts is done in parallel (using OpenMP).
244 static INX* merge(const T* data, INX* inx, INX* tmp, INX nrrec, INX* index, INX nparts);
245
246 // Check if 2 values are in ascending order.
247 // When equal, the order is correct if index1<index2.
248 static inline int isAscending(const T* data, INX index1, INX index2);
249
250 // Quicksort in ascending order.
251 static void quickSortAsc(INX* inx, const T*, INX nr, Bool multiThread = False, Int rec_lim = 128);
252
253 // Heapsort in ascending order.
254 static void heapSortAsc(INX* inx, const T*, INX nr);
255 // Helper function for ascending heapsort.
256 static void heapAscSiftDown(INX* inx, INX, INX, const T*);
257
258 // Insertion sort in ascending order.
259 static INX insSortAsc(INX* inx, const T*, INX nr, int option);
260 // Insertion sort in ascending order allowing duplicates.
261 // This is also used by quicksort for its last steps.
262 static INX insSortAscDup(INX* inx, const T*, INX nr);
263 // Insertion sort in ascending order allowing no duplicates.
264 // This is also used by the other sort algorithms to skip duplicates.
265 static INX insSortAscNoDup(INX* inx, const T*, INX nr);
266};
267
268// <summary> Global in-place sort functions </summary>
269
270// The following global functions are easier to use than the static
271// <linkto class=GenSort>GenSort</linkto> member functions.
272// They do an in-place sort of data, thus the data themselves are moved
273// ending up in the requested order.
274// <p>
275// The default sorting method is QuickSort, which is the fastest.
276// However, there are pathological cases where it can be slow.
277// HeapSort is about twice a slow, but its speed is guaranteed.
278// InsSort (insertion sort) can be very, very slow, but it is the only
279// stable sort method (i.e. equal values are kept in their original order).
280// However, <linkto name=genSortIndirect> indirect sorting methods </linkto>
281// are available to make QuickSort and HeapSort stable.
282// <p>
283// All sort methods have an option to skip duplicate values. This is the
284// only case where the returned number of values can be less than the
285// original number of values.
286
287// <group name=genSortInPlace>
288
289template <class T>
290inline uInt genSort(T* data, uInt nr, Sort::Order order = Sort::Ascending, int options = 0) {
291 return GenSort<T>::sort(data, nr, order, options);
292}
293
294template <class T>
295inline uInt genSort(Array<T>& data, Sort::Order order = Sort::Ascending, int options = 0) {
296 return GenSort<T>::sort(data, order, options);
297}
298
299template <class T>
300inline uInt genSort(Block<T>& data, Sort::Order order = Sort::Ascending, int options = 0) {
301 return GenSort<T>::sort(data, data.nelements(), order, options);
302}
303
304template <class T>
305inline uInt genSort(Block<T>& data, uInt nr, Sort::Order order = Sort::Ascending, int options = 0) {
306 return GenSort<T>::sort(data, nr, order, options);
307}
308// </group>
309
310// <summary> Global indirect sort functions </summary>
311
312// The following global functions easier to use than the static
313// <linkto class=GenSortIndirect>GenSortIndirect</linkto> member functions.
314// They do an indirect sort of data, thus the data themselves are not moved.
315// Rather an index vector is returned giving the sorted data indices.
316// <p>
317// The sorting method used is merge sort, which is always stable.
318// It is the fastest, especially if it can use multiple threads.
319// <p>
320// Unlike the <linkto name=genSortInPlace> in-place sorting methods
321// </linkto>, all indirect sorting methods are stable (i.e. equal
322// values are left in their original order).
323// <p>
324// All sort methods have an option to skip duplicate values. This is the
325// only case where the returned number of values can be less than the
326// original number of values.
327
328// <group name=genSortIndirect>
329
330template <class T, class INX = uInt>
331inline uInt genSort(Vector<INX>& indexVector, const T* data, INX nr,
332 Sort::Order order = Sort::Ascending, int options = 0) {
333 return GenSortIndirect<T, INX>::sort(indexVector, data, nr, order, options);
334}
335
336template <class T, class INX = uInt>
337inline uInt genSort(Vector<INX>& indexVector, const Array<T>& data,
338 Sort::Order order = Sort::Ascending, int options = 0) {
339 return GenSortIndirect<T, INX>::sort(indexVector, data, order, options);
340}
341
342template <class T, class INX = uInt>
343inline uInt genSort(Vector<INX>& indexVector, const Block<T>& data,
344 Sort::Order order = Sort::Ascending, int options = 0) {
345 return GenSortIndirect<T, INX>::sort(indexVector, data, data.nelements(), order, options);
346}
347
348template <class T, class INX = uInt>
349inline uInt genSort(Vector<INX>& indexVector, const Block<T>& data, INX nr,
350 Sort::Order order = Sort::Ascending, int options = 0) {
351 return GenSortIndirect<T, INX>::sort(indexVector, data, nr, order, options);
352}
353// </group>
354
355// Implement inline member functions.
356
357template <class T>
358inline void GenSort<T>::swap(T& l, T& r) {
359 T t = l;
360 l = r;
361 r = t;
362}
363
364template <class T, class INX>
365inline void GenSortIndirect<T, INX>::swapInx(INX& i, INX& j) {
366 INX t = i;
367 i = j;
368 j = t;
369}
370template <class T, class INX>
371inline int GenSortIndirect<T, INX>::isAscending(const T* data, INX i, INX j) {
372 return (data[i] > data[j] || (data[i] == data[j] && i > j));
373}
374
375} // namespace casacore
376
377#ifndef CASACORE_NO_AUTO_TEMPLATES
378#include <casacore/casa/Utilities/GenSort.tcc>
379#endif // # CASACORE_NO_AUTO_TEMPLATES
380#endif
General indirect sort functions.
Definition GenSort.h:198
static INX insSortAscNoDup(INX *inx, const T *, INX nr)
Insertion sort in ascending order allowing no duplicates.
static INX quickSort(INX *inx, const T *data, INX nr, Sort::Order, int options)
Sort container using quicksort.
static INX * merge(const T *data, INX *inx, INX *tmp, INX nrrec, INX *index, INX nparts)
Thedata buffer is divided in nparts parts.
static INX sort(Vector< INX > &indexVector, const Array< T > &data, Sort::Order=Sort::Ascending, int options=Sort::QuickSort)
Sort a C-array containing nr T-type objects.
static void heapSortAsc(INX *inx, const T *, INX nr)
Heapsort in ascending order.
static void swapInx(INX &index1, INX &index2)
Swap 2 indices.
Definition GenSort.h:365
static INX insSort(INX *inx, const T *data, INX nr, Sort::Order, int options)
Sort container using insertion sort.
static INX insSortAsc(INX *inx, const T *, INX nr, int option)
Insertion sort in ascending order.
static INX sort(Vector< INX > &indexVector, const Block< T > &data, INX nr, Sort::Order=Sort::Ascending, int options=Sort::QuickSort)
Sort a C-array containing nr T-type objects.
static INX heapSort(INX *inx, const T *data, INX nr, Sort::Order, int options)
Sort container using heapsort.
static void heapAscSiftDown(INX *inx, INX, INX, const T *)
Helper function for ascending heapsort.
static INX insSortAscDup(INX *inx, const T *, INX nr)
Insertion sort in ascending order allowing duplicates.
static INX parSort(INX *inx, const T *data, INX nr, Sort::Order, int options, int nthreads=0)
Sort container using parallel merge sort (using OpenMP).
static INX kthLargest(T *data, INX nr, INX k)
Find the index of the k-th largest value.
static int isAscending(const T *data, INX index1, INX index2)
Check if 2 values are in ascending order.
Definition GenSort.h:371
static void quickSortAsc(INX *inx, const T *, INX nr, Bool multiThread=False, Int rec_lim=128)
Quicksort in ascending order.
static INX sort(Vector< INX > &indexVector, const T *data, INX nr, Sort::Order=Sort::Ascending, int options=Sort::QuickSort)
Sort a C-array containing nr T-type objects.
static uInt insSortAscDup(T *, Int)
Insertion sort in ascending order allowing duplicates.
static uInt sort(T *, uInt nr, Sort::Order=Sort::Ascending, int options=0)
Sort a C-array containing nr T-type objects.
static uInt quickSort(T *, uInt nr, Sort::Order=Sort::Ascending, int options=0)
Sort C-array using quicksort.
static uInt sort(Block< T > &, uInt nr, Sort::Order=Sort::Ascending, int options=0)
static void reverse(T *data, const T *res, uInt nrrec)
Reverse the elements in res and put them into data.
static void heapAscSiftDown(Int, Int, T *)
Helper function for ascending heapsort.
static uInt sort(Array< T > &, Sort::Order=Sort::Ascending, int options=0)
static void swap(T &, T &)
Swap 2 elements in array.
Definition GenSort.h:358
static T * merge(T *data, T *tmp, uInt nrrec, uInt *index, uInt nparts)
Thedata buffer is divided in nparts parts.
static uInt insSort(T *, uInt nr, Sort::Order=Sort::Ascending, int options=0)
Sort C-array using insertion sort.
static uInt heapSort(T *, uInt nr, Sort::Order=Sort::Ascending, int options=0)
Sort C-array using heapsort.
static void quickSortAsc(T *, Int, Bool multiThread=False, Int rec_lim=128)
Quicksort in ascending order.
static uInt parSort(T *, uInt nr, Sort::Order=Sort::Ascending, int options=0, int nthread=0)
Sort C-array using parallel merge sort (using OpenMP).
static void heapSortAsc(T *, Int)
Heapsort in ascending order.
static uInt insSortAsc(T *, Int, int option)
Insertion sort in ascending order.
static uInt insSortAscNoDup(T *, Int)
Insertion sort in ascending order allowing no duplicates.
static T kthLargest(T *data, uInt nr, uInt k)
Find the k-th largest value.
Order
Enumerate the sort order:
Definition Sort.h:252
uInt genSort(T *data, uInt nr, Sort::Order order=Sort::Ascending, int options=0)
Global in-place sort functions The following global functions are easier to use than the static GenSo...
Definition GenSort.h:290
For temporary backward namespace compatibility, use casa as alias for casacore.
Definition mainpage.dox:28
const Bool False
Definition aipstype.h:42
unsigned int uInt
Definition aipstype.h:49
uInt order() const
What is the order of the polynomial, i.e.
int Int
Definition aipstype.h:48
bool Bool
Define the standard types used by Casacore.
Definition aipstype.h:40