casacore
Loading...
Searching...
No Matches
Sort.h
Go to the documentation of this file.
1// # Sort.h: Sort objects on one or more keys
2// # Copyright (C) 1995,1996,1997,1998,1999,2000,2001
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_SORT_H
27#define CASA_SORT_H
28
29// # Includes
30#include <casacore/casa/aips.h>
31#include <casacore/casa/Arrays/ArrayFwd.h>
32#include <casacore/casa/Containers/Block.h>
33#include <casacore/casa/Utilities/ValType.h>
34#include <casacore/casa/Utilities/Compare.h>
35#include <memory>
36
37namespace casacore { // # NAMESPACE CASACORE - BEGIN
38
39// <summary> Define a Sort key </summary>
40// <use visibility=local>
41// <reviewed reviewer="Friso Olnon" date="1995/03/01" tests="tSort, tSort_1">
42// </reviewed>
43
44// <synopsis>
45// SortKey is a helper class for the <linkto class=Sort>Sort</linkto> class.
46// It holds the following information about a sort key:
47// <ul>
48// <li> Address of the data array containing the sort key;
49// <li> A std::shared_ptr to a comparison object to be used
50// (of a class derived from the abstract base class BaseCompare).
51// <li> Increment for the next data point -- this lets you specify a
52// stride for keys embedded in a struct;
53// <li> Sort order -- ascending or descending;
54// </ul>
55// </synopsis>
56
57class SortKey {
58 public:
59 friend class Sort;
60
61 // Define a sort key in a given data array using the indicated
62 // comparison object, stride and sort order.
63 SortKey(const void* data, const std::shared_ptr<BaseCompare>&, uInt increment, int order);
64
65 // Copy constructor (copy semantics).
67
69
70 // Assignment (copy semantics).
72
73 // Try if GenSort can be used for this single key.
74 // If it succeeds, it returns the resulting number of elements.
75 // Otherwise it returns 0.
76 uInt tryGenSort(Vector<uInt>& indexVector, uInt nrrec, int opt) const;
77 uInt64 tryGenSort(Vector<uInt64>& indexVector, uInt64 nrrec, int opt) const;
78
79 // Get the sort order.
80 int order() const { return order_p; }
81
82 protected:
83 // sort order; -1 = ascending, 1 = descending
85 // address of first data point
86 const void* data_p;
87 // increment for next data point
89 // comparison object; use std::shared_ptr for memory management
90 std::shared_ptr<BaseCompare> ccmpObj_p;
91 // comparison object; use raw pointer for performance
93};
94
95// <summary> Sort on one or more keys, ascending and/or descending </summary>
96// <use visibility=export>
97// <reviewed reviewer="Friso Olnon" date="1995/03/01" tests="tSort, tSort_1">
98// </reviewed>
99
100// <synopsis>
101// <src>Sort</src> lets you sort data on one or more keys in a mix of
102// <src>Sort::ascending</src> and <src>Sort::descending</src> order.
103// Duplicates can be skipped by giving the option
104// <src>Sort::NoDuplicates</src>. Only in this case the number of output
105// elements can be different from the number of input elements.
106// <br>The <src>unique</src> function offers another way of getting
107// unique values.
108// <p>
109// Class <src>Sort</src> does not sort the data themselves, but
110// returns an index to them. This gives more flexibility and
111// allows the sort to be stable; but it is slower.
112// <br>Very fast sorting of the data themselves can be done with the
113// functions in class <linkto class=GenSort>GenSort</linkto>.
114// If sorting on a single key with a standard data type is done,
115// Sort will use GenSortIndirect to speed up the sort.
116// <br>
117// Four sort algorithms are provided:
118// <DL>
119// <DT> <src>Sort::ParSort</src>
120// <DD> The parallel merge sort is the fastest if it can use multiple threads.
121// For a single thread it has O(n*log(n)) behaviour, but is slower
122// than quicksort.
123// A drawback is that it needs an extra index array to do the merge.
124// <DT> <src>Sort::InsSort</src>
125// <DD> Insertion sort has O(n*n) behaviour, thus is very slow for large
126// arrays. However, it is the fastest method for small arrays
127// (< 50 elements) and for arrays already (almost) in the right order.
128// <DT> <src>Sort::QuickSort</src>
129// <DD> Care has been taken to solve the well-known quicksort problems
130// like "array already in order" or "many equal elements". The
131// behaviour is O(n*log(n)) in all the cases tested, even in
132// degenerated cases where the SUN Solaris qsort algorithm is O(n*n).
133// <DT> <src>Sort::HeapSort</src>
134// <DD> Heapsort has O(n*log(n)) behaviour. Its speed is lower than
135// that of QuickSort, so QuickSort is the default algorithm.
136// </DL>
137// The default is to use QuickSort for small arrays or if only a single
138// thread can be used. Otherwise ParSort is the default.
139//
140// All sort algorithms are <em>stable</em>, which means that the original
141// order is kept when keys are equal.
142//
143// The sort is a four step process:
144// <ol>
145// <li> Construct the <src>Sort</src> object.
146// <li> Define the sort keys. The function <src>sortKey</src> must be
147// called for each sort key (the most significant one first).
148// The comparison object can be passed in directly, or a
149// <linkto group="DataType.h#DataType">basic data type</linkto>
150// can be given. In the latter case the appropriate ObjCompare
151// comparison object will be created.
152// <li> Sort the data. The function <src>sort</src> returns an index
153// array, which is allocated when needed.
154// <li> Destruct the <src>Sort</src> object (usually done automatically)
155// and delete the index array.
156// </ol>
157// The data can be in a single array of structs, in separate arrays, or
158// in a mix of those. Of course, all arrays must have the same length.
159// The data can be passed to the <src>Sort</src> constructor and/or to the
160// <src>sortKey</src> function. If passed to the <src>Sort</src> constructor,
161// the offset of the data item in the data array must be given to
162// <src>sortKey</src>.
163// </synopsis>
164
165// <example>
166// In the first example we sort the data contained in two "parallel"
167// arrays, <src>idata</src> and <src>ddata</src>, both of length
168// <src>nrdata</src>.
169// <srcblock>
170// Sort sort;
171// sort.sortKey (idata, TpInt); // define 1st sort key
172// sort.sortKey (ddata, TpDouble,0,Sort::Descending); // define 2nd sort key
173// Vector<uInt> inx;
174// sort.sort (inx, nrdata);
175// for (uInt i=0; i<nrdata; i++) { // show sorted data
176// cout << idata[inx[i]] << " " << ddata[inx[i]] << endl;
177// }
178// </srcblock>
179// Now <src>nr</src> contains the nr of records (=<src>nrdata</src>)
180// and <src>inx</src> an array of (sorted) indices.
181//
182// In the second example we sort the data stored in an array of structs
183// on the double (ascending) and the string (descending). We can pass
184// the data to the <src>Sort</src> constructor, and the offsets of the
185// struct elements to the <src>sortKey</src> function.
186// <srcblock>
187// struct Ts {
188// String as;
189// double ad;
190// }
191// Vector<uInt> inx;
192// Sort sort (tsarr, sizeof(Ts));
193// sort.sortKey ((char*)&tsarr[0].ad - (char*)tsarr, TpDouble);
194// sort.sortKey ((char*)&tsarr[0].as - (char*)tsarr, TpString,
195// Sort::Descending);
196// sort.sort (inx, nrts);
197// </srcblock>
198// Note that the first argument in function <src>sortKey</src> gives
199// the offset of the variable in the struct.
200//
201// Alternatively, and probably slightly easier, we could pass the data
202// to the <src>sortKey</src> function and use an increment:
203// <srcblock>
204// struct Ts {
205// String as;
206// double ad;
207// }
208// Vector<uInt> inx;
209// Sort sort;
210// sort.sortKey (&tsarr[0].ad, TpDouble, sizeof(Ts));
211// sort.sortKey (&tsarr[0].as, TpString, sizeof(Ts), Sort::Descending);
212// sort.sort (inx, nrts);
213// </srcblock>
214//
215// Finally, we could provide a comparison object for the struct.
216// <srcblock>
217// struct Ts {
218// String as;
219// double ad;
220// }
221// class MyCompare: public BaseCompare {
222// virtual int comp (const void* val1, const void* val2) const
223// {
224// const Ts& t1 = *(Ts*)val1;
225// const Ts& t2 = *(Ts*)val2;
226// if (t1.ad < t2.ad) return -1;
227// if (t1.ad > t2.ad) return 1;
228// if (t1.as < t2.as) return 1; // string must be descending
229// if (t1.as > t2.as) return -1;
230// return 0;
231// }
232// };
233// Vector<uInt> inx;
234// Sort sort;
235// sort.sortKey (tsarr, compareTs, sizeof(Ts));
236// sort.sort (inx, nrts);
237// </srcblock>
238
239class Sort {
240 public:
241 // Enumerate the sort options:
242 enum Option {
243 DefaultSort = 0, // ParSort, but QuickSort for small array
244 HeapSort = 1, // use Heapsort algorithm
245 InsSort = 2, // use insertion sort algorithm
246 QuickSort = 4, // use Quicksort algorithm
247 ParSort = 8, // use parallel merge sort algorithm
249 }; // skip data with equal sort keys
250
251 // Enumerate the sort order:
252 enum Order { Ascending = -1, Descending = 1 };
253
254 // The default constructor can be used when the data is only passed
255 // in via function <src>sortKey</src>.
257
258 // Construct a Sort object for the given data array with elements
259 // of <src>elementSize</src> bytes. This data array will be used
260 // when an offset is given to the <src>sortKey</src> functions.
261 // You can still pass additional data arrays to the
262 // <src>sortKey</src> functions.
263 Sort(const void* data, uInt elementSize);
264
265 // Copy constructor (copy semantics).
266 Sort(const Sort&);
267
269
270 // Assignment (copy semantics).
272
273 // Define a sort key (the most significant key should be defined first).
274 // The key contains:
275 // <ul>
276 // <li> A pointer to the start of the data array. --- When structs are
277 // sorted on an element in the struct, the pointer must point to
278 // that element in the first struct.
279 // <li> A pointer to the comparison object to be used. --- The
280 // comparison object can be specified in two ways:
281 // <ul>
282 // <li> by giving a
283 // <linkto group="DataType.h#DataType">basic data type</linkto>,
284 // in which case the appropriate comparison object will be
285 // created automatically, or
286 // <li> by a std::shared_ptr of a comparison object.
287 // You may want to use the templated comparison classes
288 // <linkto class=ObjCompare>ObjCompare</linkto>(),
289 // but you are free to use any other class derived from BaseCompare
290 // that implements the <src>comp</src> function.
291 // </ul>
292 // <li> The increment from one data element to the next. --- When
293 // structs are sorted on an element in the struct, the increment
294 // should be the size of the struct. If the comparison object is
295 // automatically created using the data type specified, the default
296 // increment is the size of the data type.
297 // <li> The sort order. --- <src>Ascending</src> (default) or
298 // <src>Descending</src>;
299 // </ul>
300 //
301 // When the data array has been passed to the Sort constructor,
302 // the data pointer and the increment arguments can be replaced by a
303 // single argument: the offset of the key in each element of the array.
304 //
305 // <group>
306 void sortKey(const void* data, DataType, uInt increment = 0, Order = Ascending);
307 void sortKey(const void* data, const std::shared_ptr<BaseCompare>&, uInt increment,
308 Order = Ascending);
309 void sortKey(uInt offset, DataType, Order = Ascending);
310 void sortKey(uInt offset, const std::shared_ptr<BaseCompare>&, Order = Ascending);
311 // </group>
312
313 // Sort the data array of <src>nrrec</src> records.
314 // The result is an array of indices giving the requested order.
315 // It returns the number of resulting records. The indices array
316 // is resized to that number.
317 // <br> By default it'll try if the faster GenSortIndirect can be used
318 // if a sort on a single key is used.
319 uInt sort(Vector<uInt>& indexVector, uInt nrrec, int options = DefaultSort,
320 Bool tryGenSort = True) const;
321 uInt64 sort(Vector<uInt64>& indexVector, uInt64 nrrec, int options = DefaultSort,
322 Bool tryGenSort = True) const;
323
324 // Get all unique records in a sorted array. The array order is
325 // given in the indexVector (as possibly returned by the sort function).
326 // The default indexVector is 0..nrrec-1.
327 // The index of each first unique record is returned in the uniqueVector.
328 // They are indices in the supplied indexVector, so
329 // <src>data[indexVector(uniqueVector(i))]</src>
330 // is giving the i-th unique record.
331 // Note that the records indexed by <src>indexVector(uniqueVector(i))</src>
332 // till <src>indexVector(uniqueVector(i+1))</src> are all the same.
333 // <br>
334 // It returns the number of unique records. The unique array
335 // is resized to that number.
336 // The third version also gives back a vector with the keys that
337 // change in each sorting group. The size of changeKey is the same as
338 // uniqueVector, and for each unique sorting group indicates the index
339 // of the keyword that will change at the end of the group.
340 // <group>
341 uInt unique(Vector<uInt>& uniqueVector, uInt nrrec) const;
342 uInt unique(Vector<uInt>& uniqueVector, const Vector<uInt>& indexVector) const;
343 uInt unique(Vector<uInt>& uniqueVector, Vector<size_t>& changeKey,
344 const Vector<uInt>& indexVector) const;
345 uInt64 unique(Vector<uInt64>& uniqueVector, uInt64 nrrec) const;
346 uInt64 unique(Vector<uInt64>& uniqueVector, const Vector<uInt64>& indexVector) const;
347 uInt64 unique(Vector<uInt64>& uniqueVector, Vector<size_t>& changeKey,
348 const Vector<uInt64>& indexVector) const;
349 // </group>
350
351 private:
352 template <typename T>
353 T doSort(Vector<T>& indexVector, T nrrec, int options = DefaultSort,
354 Bool tryGenSort = True) const;
355
356 template <typename T>
357 T doUnique(Vector<T>& uniqueVector, T nrrec) const;
358 template <typename T>
359 T doUnique(Vector<T>& uniqueVector, const Vector<T>& indexVector) const;
360 template <typename T>
361 T doUnique(Vector<T>& uniqueVector, Vector<size_t>& changeKey,
362 const Vector<T>& indexVector) const;
363
364 // Copy that Sort object to this.
365 void copy(const Sort& that);
366
367 // Add a sort key giving a data type and stride or the sort key.
368 // <group>
369 void addKey(const void* data, DataType, uInt increment, int options);
371 // </group>
372
373 // Do an insertion sort, optionally skipping duplicates.
374 // <group>
375 template <typename T>
376 T insSort(T nr, T* indices) const;
377 template <typename T>
378 T insSortNoDup(T nr, T* indices) const;
379 // </group>
380
381 // Do a merge sort, if possible in parallel using OpenMP.
382 // Note that the env.var. OMP_NUM_TRHEADS sets the maximum nr of threads
383 // to use. It defaults to the number of cores.
384 template <typename T>
385 T parSort(int nthr, T nrrec, T* inx) const;
386 template <typename T>
387 void merge(T* inx, T* tmp, T size, T* index, T nparts) const;
388
389 // Do a quicksort, optionally skipping duplicates
390 // (qkSort is the actual quicksort function).
391 // <group>
392 template <typename T>
393 T quickSort(T nr, T* indices) const;
394 template <typename T>
395 T quickSortNoDup(T nr, T* indices) const;
396 template <typename T>
397 void qkSort(T nr, T* indices) const;
398 // </group>
399
400 // Do a heapsort, optionally skipping duplicates.
401 // <group>
402 template <typename T>
403 T heapSort(T nr, T* indices) const;
404 template <typename T>
405 T heapSortNoDup(T nr, T* indices) const;
406 // </group>
407
408 // Siftdown algorithm for heapsort.
409 template <typename T>
410 void siftDown(T low, T up, T* indices) const;
411
412 // Compare 2 records based on the comparison functions
413 template <typename T>
414 int compare(T index1, T index2) const;
415
416 // As compare() but it also gives back the index of the first comparison
417 // function that didn't match.
418 template <typename T>
419 int compareChangeIdx(T i1, T i2, size_t& idxComp) const;
420
421 // Swap 2 indices.
422 template <typename T>
423 inline void swap(T index1, T index2, T* indices) const {
424 T t = indices[index1];
425 indices[index1] = indices[index2];
426 indices[index2] = t;
427 }
428
429 // # Data memebers
430 Block<SortKey*> keys_p; // # keys to sort on
431 size_t nrkey_p; // # #sort-keys
432 const void* data_p; // # pointer to data records
433 uInt size_p; // # size of data record
434 int order_p; // # -1=asc 0=mixed 1=desc
435};
436
437} // namespace casacore
438
439#endif
abstract base class for comparing two objects
Definition Compare.h:61
friend class Sort
Definition Sort.h:59
int order() const
Get the sort order.
Definition Sort.h:80
uInt tryGenSort(Vector< uInt > &indexVector, uInt nrrec, int opt) const
Try if GenSort can be used for this single key.
BaseCompare * cmpObj_p
comparison object; use raw pointer for performance
Definition Sort.h:92
uInt64 tryGenSort(Vector< uInt64 > &indexVector, uInt64 nrrec, int opt) const
SortKey & operator=(const SortKey &)
Assignment (copy semantics).
SortKey(const SortKey &)
Copy constructor (copy semantics).
const void * data_p
address of first data point
Definition Sort.h:86
int order_p
sort order; -1 = ascending, 1 = descending
Definition Sort.h:84
std::shared_ptr< BaseCompare > ccmpObj_p
comparison object; use std::shared_ptr for memory management
Definition Sort.h:90
uInt incr_p
increment for next data point
Definition Sort.h:88
SortKey(const void *data, const std::shared_ptr< BaseCompare > &, uInt increment, int order)
Define a sort key in a given data array using the indicated comparison object, stride and sort order.
uInt64 unique(Vector< uInt64 > &uniqueVector, const Vector< uInt64 > &indexVector) const
Option
Enumerate the sort options:
Definition Sort.h:242
T heapSortNoDup(T nr, T *indices) const
const void * data_p
Definition Sort.h:432
void addKey(const void *data, DataType, uInt increment, int options)
Add a sort key giving a data type and stride or the sort key.
uInt64 sort(Vector< uInt64 > &indexVector, uInt64 nrrec, int options=DefaultSort, Bool tryGenSort=True) const
int compareChangeIdx(T i1, T i2, size_t &idxComp) const
As compare() but it also gives back the index of the first comparison function that didn't match.
T parSort(int nthr, T nrrec, T *inx) const
Do a merge sort, if possible in parallel using OpenMP.
uInt size_p
Definition Sort.h:433
void sortKey(const void *data, const std::shared_ptr< BaseCompare > &, uInt increment, Order=Ascending)
T doUnique(Vector< T > &uniqueVector, Vector< size_t > &changeKey, const Vector< T > &indexVector) const
void sortKey(uInt offset, const std::shared_ptr< BaseCompare > &, Order=Ascending)
size_t nrkey_p
Definition Sort.h:431
void copy(const Sort &that)
Copy that Sort object to this.
uInt unique(Vector< uInt > &uniqueVector, uInt nrrec) const
Get all unique records in a sorted array.
T insSort(T nr, T *indices) const
Do an insertion sort, optionally skipping duplicates.
uInt unique(Vector< uInt > &uniqueVector, const Vector< uInt > &indexVector) const
T doSort(Vector< T > &indexVector, T nrrec, int options=DefaultSort, Bool tryGenSort=True) const
uInt unique(Vector< uInt > &uniqueVector, Vector< size_t > &changeKey, const Vector< uInt > &indexVector) const
T quickSort(T nr, T *indices) const
Do a quicksort, optionally skipping duplicates (qkSort is the actual quicksort function).
Sort & operator=(const Sort &)
Assignment (copy semantics).
void merge(T *inx, T *tmp, T size, T *index, T nparts) const
int compare(T index1, T index2) const
Compare 2 records based on the comparison functions.
T heapSort(T nr, T *indices) const
Do a heapsort, optionally skipping duplicates.
void sortKey(uInt offset, DataType, Order=Ascending)
void sortKey(const void *data, DataType, uInt increment=0, Order=Ascending)
Define a sort key (the most significant key should be defined first).
uInt64 unique(Vector< uInt64 > &uniqueVector, uInt64 nrrec) const
Order
Enumerate the sort order:
Definition Sort.h:252
T quickSortNoDup(T nr, T *indices) const
void swap(T index1, T index2, T *indices) const
Swap 2 indices.
Definition Sort.h:423
T doUnique(Vector< T > &uniqueVector, const Vector< T > &indexVector) const
Sort(const void *data, uInt elementSize)
Construct a Sort object for the given data array with elements of elementSize bytes.
T doUnique(Vector< T > &uniqueVector, T nrrec) const
uInt sort(Vector< uInt > &indexVector, uInt nrrec, int options=DefaultSort, Bool tryGenSort=True) const
Sort the data array of nrrec records.
Block< SortKey * > keys_p
Definition Sort.h:430
uInt64 unique(Vector< uInt64 > &uniqueVector, Vector< size_t > &changeKey, const Vector< uInt64 > &indexVector) const
T insSortNoDup(T nr, T *indices) const
void addKey(SortKey *)
Sort()
The default constructor can be used when the data is only passed in via function sortKey.
Sort(const Sort &)
Copy constructor (copy semantics).
void qkSort(T nr, T *indices) const
int order_p
Definition Sort.h:434
void siftDown(T low, T up, T *indices) const
Siftdown algorithm for heapsort.
For temporary backward namespace compatibility, use casa as alias for casacore.
Definition mainpage.dox:28
int offset(int, int) const
compute a linear offset from array indicies
unsigned int uInt
Definition aipstype.h:49
bool Bool
Define the standard types used by Casacore.
Definition aipstype.h:40
size_t size() const
Definition Block.h:566
const Bool True
Definition aipstype.h:41
unsigned long long uInt64
Definition aipsxtype.h:37