GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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