GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Range.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 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 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_Range_h)
27 #define octave_Range_h 1
28 
29 #include "octave-config.h"
30 
31 #include <iosfwd>
32 #include <type_traits>
33 
34 #include "Array-fwd.h"
35 #include "dMatrix.h"
36 #include "dim-vector.h"
37 #include "lo-error.h"
38 #include "oct-sort.h"
39 #include "range-fwd.h"
40 
42 
43 // For now, only define for floating point types. However, we only
44 // need range<float> as a temporary local variable in make_float_range
45 // in ov.cc.
46 
47 template <typename T>
48 class
50 {
51 public:
52 
53  range ()
54  : m_base (0), m_increment (0), m_limit (0), m_final (0), m_numel (0),
55  m_reverse (false)
56  { }
57 
58  // LIMIT is an upper limit and may be outside the range of actual
59  // values. For floating point ranges, we perform a tolerant check
60  // to attempt to capture limit in the set of values if it is "close"
61  // to the value of base + a multiple of the increment.
62 
63  range (const T& base, const T& increment, const T& limit,
64  bool reverse = false)
65  : m_base (base), m_increment (increment), m_limit (limit),
66  m_final (), m_numel (), m_reverse (reverse)
67  {
68  init ();
69  }
70 
71  range (const T& base, const T& limit)
72  : m_base (base), m_increment (1), m_limit (limit), m_final (), m_numel (),
73  m_reverse (false)
74  {
75  init ();
76  }
77 
78  // Allow conversion from (presumably) properly constructed Range
79  // objects. The values of base, limit, increment, and numel must be
80  // consistent.
81 
82  // FIXME: Actually check that base, limit, increment, and numel are
83  // consistent?
84 
85  range (const T& base, const T& increment, const T& limit,
86  octave_idx_type numel, bool reverse = false)
87  : m_base (base), m_increment (increment), m_limit (limit),
88  m_final (limit), m_numel (numel), m_reverse (reverse)
89  { }
90 
91  // We don't use a constructor for this because it will conflict with
92  // range<T> (base, limit, increment) when T is octave_idx_type.
93 
94  static range<T> make_n_element_range (const T& base, const T& increment,
96  bool reverse = false)
97  {
98  // We could just make this constructor public, but it allows
99  // inconsistent ranges to be constructed. And it is probably much
100  // clearer to see "make_n_element_range" instead of puzzling over the
101  // purpose of this strange constructor form.
102 
103  T final_val = (reverse ? base - (numel - 1) * increment
104  : base + (numel - 1) * increment);
105 
106  return range<T> (base, increment, final_val, numel, reverse);
107  }
108 
109  OCTAVE_DEFAULT_COPY_MOVE_DELETE (range)
110 
111  T base () const { return m_base; }
112  T increment () const { return m_increment; }
113  T limit () const { return m_limit; }
114  bool reverse () const { return m_reverse; }
115 
116  T final_value () const { return m_final; }
117 
118  T min () const
119  {
120  return (m_numel > 0
121  ? ((m_reverse ? m_increment > T (0)
122  : m_increment > T (0)) ? base () : final_value ())
123  : T (0));
124  }
125 
126  T max () const
127  {
128  return (m_numel > 0
129  ? ((m_reverse ? m_increment < T (0)
130  : m_increment > T (0)) ? final_value () : base ())
131  : T (0));
132  }
133 
134  octave_idx_type numel () const { return m_numel; }
135 
136  // To support things like "for i = 1:Inf; ...; end" that are
137  // required for Matlab compatibility, creation of a range object
138  // like 1:Inf is allowed with m_numel set to
139  // numeric_limits<octave_idx_type>::max(). However, it is not
140  // possible to store these ranges. The following function allows
141  // us to easily distinguish ranges with an infinite number of
142  // elements. There are specializations for double and float.
143 
144  bool is_storable () const { return true; }
145 
146  dim_vector dims () const { return dim_vector (1, m_numel); }
147 
148  octave_idx_type rows () const { return 1; }
149 
150  octave_idx_type cols () const { return numel (); }
151  octave_idx_type columns () const { return numel (); }
152 
153  bool isempty () const { return numel () == 0; }
154 
155  bool all_elements_are_ints () const { return true; }
156 
158  {
159  if (m_numel > 1 && (m_reverse ? m_increment < T (0)
160  : m_increment > T (0)))
161  mode = ((mode == DESCENDING) ? UNSORTED : ASCENDING);
162  else if (m_numel > 1 && (m_reverse ? m_increment > T (0)
163  : m_increment < T (0)))
164  mode = ((mode == ASCENDING) ? UNSORTED : DESCENDING);
165  else
166  mode = ((mode == UNSORTED) ? ASCENDING : mode);
167 
168  return mode;
169  }
170 
172 
173  // Support for single-index subscripting, without generating matrix cache.
174 
176  {
177  if (i < 0 || i >= m_numel)
178  err_index_out_of_range (2, 2, i+1, m_numel, dims ());
179 
180  if (i == 0)
181  // Required for proper NaN handling.
182  return (m_numel == 1 ? final_value () : m_base);
183  else if (i < m_numel - 1)
184  return (m_reverse ? m_base + T (i) * m_increment
185  : m_base + T (i) * m_increment);
186  else
187  return final_value ();
188  }
189 
191  {
192  // Ranges are *always* row vectors.
193  if (i != 0)
194  err_index_out_of_range (1, 1, i+1, m_numel, dims ());
195 
196  return checkelem (j);
197  }
198 
199  T elem (octave_idx_type i) const
200  {
201  if (i == 0)
202  // Required for proper NaN handling.
203  return (m_numel == 1 ? final_value () : m_base);
204  else if (i < m_numel - 1)
205  return (m_reverse ? m_base - T (i) * m_increment
206  : m_base + T (i) * m_increment);
207  else
208  return final_value ();
209  }
210 
211  T elem (octave_idx_type /* i */, octave_idx_type j) const
212  {
213  return elem (j);
214  }
215 
216  T operator () (octave_idx_type i) const
217  {
218  return elem (i);
219  }
220 
221  T operator () (octave_idx_type i, octave_idx_type j) const
222  {
223  return elem (i, j);
224  }
225 
226  Array<T> index (const idx_vector& idx) const
227  {
228  Array<T> retval;
229 
230  octave_idx_type n = m_numel;
231 
232  if (idx.is_colon ())
233  {
234  retval = array_value ().reshape (dim_vector (m_numel, 1));
235  }
236  else
237  {
238  if (idx.extent (n) != n)
239  err_index_out_of_range (1, 1, idx.extent (n), n, dims ());
240 
241  dim_vector idx_dims = idx.orig_dimensions ();
242  octave_idx_type idx_len = idx.length (n);
243 
244  // taken from Array.cc.
245  if (n != 1 && idx_dims.isvector ())
246  idx_dims = dim_vector (1, idx_len);
247 
248  retval.clear (idx_dims);
249 
250  // Loop over all values in IDX, executing the lambda
251  // expression for each index value.
252 
253  T *array = retval.fortran_vec ();
254 
255  idx.loop (n, [=, &array] (octave_idx_type i)
256  {
257  if (i == 0)
258  // Required for proper NaN handling.
259  *array++ = (m_numel == 0 ? m_final : m_base);
260  else if (i < m_numel - 1)
261  *array++ = (m_reverse ? m_base - T (i) * m_increment
262  : m_base + T (i) * m_increment);
263  else
264  *array++ = m_final;
265  });
266  }
267 
268  return retval;
269  }
270 
272  {
273  return array_value ().diag (k);
274  }
275 
277  {
278  octave_idx_type nel = numel ();
279 
280  Array<T> retval (dim_vector (1, nel));
281 
282  if (nel == 1)
283  // Required for proper NaN handling.
284  retval(0) = final_value ();
285  else if (nel > 1)
286  {
287  // The first element must always be *exactly* the base.
288  // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
289  retval(0) = m_base;
290 
291  if (m_reverse)
292  for (octave_idx_type i = 1; i < nel - 1; i++)
293  retval.xelem (i) = m_base - i * m_increment;
294  else
295  for (octave_idx_type i = 1; i < nel - 1; i++)
296  retval.xelem (i) = m_base + i * m_increment;
297 
298  retval.xelem (nel - 1) = final_value ();
299  }
300 
301  return retval;
302  }
303 
304 private:
305 
306  T m_base;
307  T m_increment;
308  T m_limit;
309  T m_final;
310  octave_idx_type m_numel;
311  bool m_reverse;
312 
313  // Setting the number of elements to zero when the increment is zero
314  // is intentional and matches the behavior of Matlab's colon
315  // operator.
316 
317  // These calculations are appropriate for integer ranges. There are
318  // specializations for double and float.
319 
320  void init ()
321  {
322  if (m_reverse)
323  {
324  m_numel = ((m_increment == T (0)
325  || (m_limit > m_base && m_increment > T (0))
326  || (m_limit < m_base && m_increment < T (0)))
327  ? T (0)
328  : (m_base - m_limit - m_increment) / m_increment);
329 
330  m_final = m_base - (m_numel - 1) * m_increment;
331  }
332  else
333  {
334  m_numel = ((m_increment == T (0)
335  || (m_limit > m_base && m_increment < T (0))
336  || (m_limit < m_base && m_increment > T (0)))
337  ? T (0)
338  : (m_limit - m_base + m_increment) / m_increment);
339 
340  m_final = m_base + (m_numel - 1) * m_increment;
341  }
342  }
343 };
344 
345 // Specializations defined externally.
346 
349 
350 template <> OCTAVE_API void range<double>::init ();
351 template <> OCTAVE_API void range<float>::init ();
352 
353 // For now, only define for floating point types. However, we only
354 // need range<float> as a temporary local variable in make_float_range
355 // in ov.cc.
356 
357 template <> OCTAVE_API bool range<double>::is_storable () const;
358 template <> OCTAVE_API bool range<float>::is_storable () const;
359 
362 
363 OCTAVE_END_NAMESPACE(octave)
364 
365 #endif
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
void clear()
Definition: Array-base.cc:109
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:524
Array< T, Alloc > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:635
Array< T, Alloc > diag(octave_idx_type k=0) const
Get the kth super or subdiagonal.
Definition: Array-base.cc:2541
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
bool isvector() const
Definition: dim-vector.h:395
dim_vector orig_dimensions() const
Definition: idx-vector.h:558
void loop(octave_idx_type n, Functor body) const
Definition: idx-vector.h:802
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:520
bool is_colon() const
Definition: idx-vector.h:540
octave_idx_type extent(octave_idx_type n) const
Definition: idx-vector.h:523
range(const T &base, const T &increment, const T &limit, bool reverse=false)
Definition: Range.h:63
static range< T > make_n_element_range(const T &base, const T &increment, octave_idx_type numel, bool reverse=false)
Definition: Range.h:94
range(const T &base, const T &increment, const T &limit, octave_idx_type numel, bool reverse=false)
Definition: Range.h:85
bool is_storable() const
Definition: Range.cc:338
octave_idx_type nnz() const
Definition: Range.cc:386
void init()
Definition: Range.cc:322
bool all_elements_are_ints() const
Definition: Range.cc:308
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void err_index_out_of_range(int nd, int dim, octave_idx_type idx, octave_idx_type ext, const dim_vector &dv)
#define OCTAVE_API
Definition: main.cc:55
octave_idx_type n
Definition: mx-inlines.cc:761
sortmode
Definition: oct-sort.h:97
@ UNSORTED
Definition: oct-sort.h:97
@ ASCENDING
Definition: oct-sort.h:97
@ DESCENDING
Definition: oct-sort.h:97
T::size_type numel(const T &str)
Definition: oct-string.cc:74