GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-sort.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2003-2023 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 // Code stolen in large part from Python's, listobject.c, which itself had
25 // no license header. However, thanks to Tim Peters for the parts of the
26 // code I ripped-off.
27 //
28 // As required in the Python license the short description of the changes
29 // made are
30 //
31 // * convert the sorting code in listobject.cc into a generic class,
32 // replacing PyObject* with the type of the class T.
33 //
34 // The Python license is
35 //
36 // PSF LICENSE AGREEMENT FOR PYTHON 2.3
37 // --------------------------------------
38 //
39 // 1. This LICENSE AGREEMENT is between the Python Software Foundation
40 // ("PSF"), and the Individual or Organization ("Licensee") accessing and
41 // otherwise using Python 2.3 software in source or binary form and its
42 // associated documentation.
43 //
44 // 2. Subject to the terms and conditions of this License Agreement, PSF
45 // hereby grants Licensee a nonexclusive, royalty-free, world-wide
46 // license to reproduce, analyze, test, perform and/or display publicly,
47 // prepare derivative works, distribute, and otherwise use Python 2.3
48 // alone or in any derivative version, provided, however, that PSF's
49 // License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
50 // 2001, 2002, 2003 Python Software Foundation; All Rights Reserved" are
51 // retained in Python 2.3 alone or in any derivative version prepared by
52 // Licensee.
53 //
54 // 3. In the event Licensee prepares a derivative work that is based on
55 // or incorporates Python 2.3 or any part thereof, and wants to make
56 // the derivative work available to others as provided herein, then
57 // Licensee hereby agrees to include in any such work a brief summary of
58 // the changes made to Python 2.3.
59 //
60 // 4. PSF is making Python 2.3 available to Licensee on an "AS IS"
61 // basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
62 // IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
63 // DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
64 // FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT
65 // INFRINGE ANY THIRD PARTY RIGHTS.
66 //
67 // 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
68 // 2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
69 // A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3,
70 // OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
71 //
72 // 6. This License Agreement will automatically terminate upon a material
73 // breach of its terms and conditions.
74 //
75 // 7. Nothing in this License Agreement shall be deemed to create any
76 // relationship of agency, partnership, or joint venture between PSF and
77 // Licensee. This License Agreement does not grant permission to use PSF
78 // trademarks or trade name in a trademark sense to endorse or promote
79 // products or services of Licensee, or any third party.
80 //
81 // 8. By copying, installing or otherwise using Python 2.3, Licensee
82 // agrees to be bound by the terms and conditions of this License
83 // Agreement.
84 //
85 ////////////////////////////////////////////////////////////////////////
86 
87 #if ! defined (octave_oct_sort_h)
88 #define octave_oct_sort_h 1
89 
90 #include "octave-config.h"
91 
92 #include <functional>
93 
94 #include "lo-traits.h"
95 
96 // Enum for type of sort function
98 
99 template <typename T>
100 class
101 OCTAVE_TEMPLATE_API
103 {
104 public:
105 
106  typedef std::function<bool (typename ref_param<T>::type,
108 
109  octave_sort (void);
110 
111  octave_sort (const compare_fcn_type&);
112 
113  // No copying!
114 
115  octave_sort (const octave_sort&) = delete;
116 
117  octave_sort& operator = (const octave_sort&) = delete;
118 
119  ~octave_sort (void);
120 
121  void set_compare (const compare_fcn_type& comp) { m_compare = comp; }
122 
123  void set_compare (sortmode mode);
124 
125  // Sort an array in-place.
126  void sort (T *data, octave_idx_type nel);
127 
128  // Ditto, but also permute the passed indices (may not be valid indices).
129  void sort (T *data, octave_idx_type *idx, octave_idx_type nel);
130 
131  // Check whether an array is sorted.
132  bool issorted (const T *data, octave_idx_type nel);
133 
134  // Sort a matrix by rows, return a permutation
135  // vector.
136  void sort_rows (const T *data, octave_idx_type *idx,
137  octave_idx_type rows, octave_idx_type cols);
138 
139  // Determine whether a matrix (as a contiguous block) is sorted by rows.
140  bool is_sorted_rows (const T *data,
141  octave_idx_type rows, octave_idx_type cols);
142 
143  // Do a binary lookup in a sorted array.
144  octave_idx_type lookup (const T *data, octave_idx_type nel,
145  const T& value);
146 
147  // Ditto, but for an array.
148  void lookup (const T *data, octave_idx_type nel,
149  const T *values, octave_idx_type nvalues,
150  octave_idx_type *idx);
151 
152  // A linear merge of two sorted tables. rev indicates the second table is
153  // in reverse order.
154  void lookup_sorted (const T *data, octave_idx_type nel,
155  const T *values, octave_idx_type nvalues,
156  octave_idx_type *idx, bool rev = false);
157 
158  // Rearranges the array so that the elements with indices
159  // lo..up-1 are in their correct place.
160  void nth_element (T *data, octave_idx_type nel,
161  octave_idx_type lo, octave_idx_type up = -1);
162 
163  static bool ascending_compare (typename ref_param<T>::type,
164  typename ref_param<T>::type);
165 
166  static bool descending_compare (typename ref_param<T>::type,
167  typename ref_param<T>::type);
168 
169 private:
170 
171  // The maximum number of entries in a MergeState's pending-runs stack.
172  // This is enough to sort arrays of size up to about
173  // 32 * phi ** MAX_MERGE_PENDING
174  // where phi ~= 1.618. 85 is ridiculously large enough, good for an array
175  // with 2^64 elements.
176  static const int MAX_MERGE_PENDING = 85;
177 
178  // When we get into galloping mode, we stay there until both runs win less
179  // often than MIN_GALLOP consecutive times. See listsort.txt for more info.
180  static const int MIN_GALLOP = 7;
181 
182  // Avoid malloc for small temp arrays.
183  static const int MERGESTATE_TEMP_SIZE = 1024;
184 
185  // One MergeState exists on the stack per invocation of mergesort.
186  // It's just a convenient way to pass state around among the helper
187  // functions.
188  //
189  // DGB: This isn't needed with mergesort in a class, but it doesn't
190  // slow things up, and it is likely to make my life easier for any
191  // potential backporting of changes in the Python code.
192 
193  struct s_slice
194  {
196  };
197 
198  struct MergeState
199  {
200  public:
201 
202  MergeState (void)
203  : m_min_gallop (), m_a (nullptr), m_ia (nullptr), m_alloced (0), m_n (0)
204  { reset (); }
205 
206  // No copying!
207 
208  MergeState (const MergeState&) = delete;
209 
210  MergeState& operator = (const MergeState&) = delete;
211 
212  ~MergeState (void)
213  { delete [] m_a; delete [] m_ia; }
214 
215  void reset (void)
216  { m_min_gallop = MIN_GALLOP; m_n = 0; }
217 
218  void getmem (octave_idx_type need);
219 
220  void getmemi (octave_idx_type need);
221 
222  //--------
223 
224  // This controls when we get *into* galloping mode. It's initialized to
225  // MIN_GALLOP. merge_lo and merge_hi tend to nudge it higher for random
226  // data, and lower for highly structured data.
228 
229  // 'a' is temp storage to help with merges. It contains room for
230  // alloced entries.
231  T *m_a; // may point to temparray below
234 
235  // A stack of n pending runs yet to be merged. Run #i starts at address
236  // base[i] and extends for len[i] elements. It's always true (so long as
237  // the indices are in bounds) that
238  //
239  // pending[i].base + pending[i].len == pending[i+1].base
240  //
241  // so we could cut the storage for this, but it's a minor amount,
242  // and keeping all the info explicit simplifies the code.
244  struct s_slice m_pending[MAX_MERGE_PENDING];
245  };
246 
248 
250 
251  template <typename Comp>
252  void binarysort (T *data, octave_idx_type nel,
253  octave_idx_type start, Comp comp);
254 
255  template <typename Comp>
256  void binarysort (T *data, octave_idx_type *idx, octave_idx_type nel,
257  octave_idx_type start, Comp comp);
258 
259  template <typename Comp>
260  octave_idx_type count_run (T *lo, octave_idx_type n, bool& descending,
261  Comp comp);
262 
263  template <typename Comp>
264  octave_idx_type gallop_left (T key, T *a, octave_idx_type n,
265  octave_idx_type hint, Comp comp);
266 
267  template <typename Comp>
268  octave_idx_type gallop_right (T key, T *a, octave_idx_type n,
269  octave_idx_type hint, Comp comp);
270 
271  template <typename Comp>
272  int merge_lo (T *pa, octave_idx_type na,
273  T *pb, octave_idx_type nb,
274  Comp comp);
275 
276  template <typename Comp>
277  int merge_lo (T *pa, octave_idx_type *ipa, octave_idx_type na,
278  T *pb, octave_idx_type *ipb, octave_idx_type nb,
279  Comp comp);
280 
281  template <typename Comp>
282  int merge_hi (T *pa, octave_idx_type na,
283  T *pb, octave_idx_type nb,
284  Comp comp);
285 
286  template <typename Comp>
287  int merge_hi (T *pa, octave_idx_type *ipa, octave_idx_type na,
288  T *pb, octave_idx_type *ipb, octave_idx_type nb,
289  Comp comp);
290 
291  template <typename Comp>
292  int merge_at (octave_idx_type i, T *data, Comp comp);
293 
294  template <typename Comp>
295  int merge_at (octave_idx_type i, T *data, octave_idx_type *idx, Comp comp);
296 
297  template <typename Comp>
298  int merge_collapse (T *data, Comp comp);
299 
300  template <typename Comp>
301  int merge_collapse (T *data, octave_idx_type *idx, Comp comp);
302 
303  template <typename Comp>
304  int merge_force_collapse (T *data, Comp comp);
305 
306  template <typename Comp>
307  int merge_force_collapse (T *data, octave_idx_type *idx, Comp comp);
308 
309  octave_idx_type merge_compute_minrun (octave_idx_type n);
310 
311  template <typename Comp>
312  void sort (T *data, octave_idx_type nel, Comp comp);
313 
314  template <typename Comp>
315  void sort (T *data, octave_idx_type *idx, octave_idx_type nel, Comp comp);
316 
317  template <typename Comp>
318  bool issorted (const T *data, octave_idx_type nel, Comp comp);
319 
320  template <typename Comp>
321  void sort_rows (const T *data, octave_idx_type *idx,
322  octave_idx_type rows, octave_idx_type cols,
323  Comp comp);
324 
325  template <typename Comp>
326  bool is_sorted_rows (const T *data, octave_idx_type rows,
327  octave_idx_type cols, Comp comp);
328 
329  template <typename Comp>
330  octave_idx_type lookup (const T *data, octave_idx_type nel,
331  const T& value, Comp comp);
332 
333  template <typename Comp>
334  void lookup (const T *data, octave_idx_type nel,
335  const T *values, octave_idx_type nvalues,
336  octave_idx_type *idx, Comp comp);
337 
338  template <typename Comp>
339  void lookup_sorted (const T *data, octave_idx_type nel,
340  const T *values, octave_idx_type nvalues,
341  octave_idx_type *idx, bool rev, Comp comp);
342 
343  template <typename Comp>
344  void nth_element (T *data, octave_idx_type nel,
346  Comp comp);
347 };
348 
349 template <typename T>
350 class
351 OCTAVE_TEMPLATE_API
352 vec_index
353 {
354 public:
355  T m_vec;
357 };
358 
359 #endif
octave_idx_type lookup(const T *x, octave_idx_type n, T y)
void set_compare(const compare_fcn_type &comp)
Definition: oct-sort.h:121
octave_sort(const octave_sort &)=delete
compare_fcn_type m_compare
Definition: oct-sort.h:247
std::function< bool(typename ref_param< T >::type, typename ref_param< T >::type)> compare_fcn_type
Definition: oct-sort.h:107
MergeState * m_ms
Definition: oct-sort.h:249
if_then_else< is_class_type< T >::no, T, T const & >::result type
Definition: lo-traits.h:121
octave_idx_type m_indx
Definition: oct-sort.h:356
octave_idx_type n
Definition: mx-inlines.cc:753
sortmode
Definition: oct-sort.h:97
@ UNSORTED
Definition: oct-sort.h:97
@ ASCENDING
Definition: oct-sort.h:97
@ DESCENDING
Definition: oct-sort.h:97
octave_idx_type m_n
Definition: oct-sort.h:243
MergeState(const MergeState &)=delete
octave_idx_type m_alloced
Definition: oct-sort.h:233
octave_idx_type * m_ia
Definition: oct-sort.h:232
octave_idx_type m_min_gallop
Definition: oct-sort.h:227
octave_idx_type m_base
Definition: oct-sort.h:195