GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
idx-vector.cc
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 (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cinttypes>
31 #include <cstdlib>
32 
33 #include <ostream>
34 
35 #include "idx-vector.h"
36 #include "Array.h"
37 #include "Array-util.h"
38 #include "Sparse.h"
39 #include "Range.h"
40 
41 #include "oct-locbuf.h"
42 #include "lo-error.h"
43 #include "lo-mappers.h"
44 
46 
47 OCTAVE_NORETURN static void err_invalid_range ()
48 {
49  (*current_liboctave_error_handler) ("invalid range used as index");
50 }
51 
52 OCTAVE_NORETURN static void
53 err_index_out_of_range ()
54 {
55  (*current_liboctave_error_handler)
56  ("internal error: idx_vector index out of range");
57 }
58 
59 idx_vector::idx_vector_rep *
60 idx_vector::nil_rep ()
61 {
62  static idx_vector_rep ivr;
63  return &ivr;
64 }
65 
67 idx_vector::idx_base_rep::as_array ()
68 {
69  (*current_liboctave_error_handler)
70  ("internal error: as_array not allowed for this index class");
71 
72  // Never actually executed, but required to silence compiler warning
73  return Array<octave_idx_type> ();
74 }
75 
76 idx_vector::idx_colon_rep::idx_colon_rep (char c)
77  : idx_base_rep ()
78 {
79  if (c != ':')
80  (*current_liboctave_error_handler)
81  ("internal error: invalid character converted to idx_vector; must be ':'");
82 }
83 
85 idx_vector::idx_colon_rep::checkelem (octave_idx_type i) const
86 {
87  if (i < 0)
88  err_index_out_of_range ();
89 
90  return i;
91 }
92 
93 idx_vector::idx_base_rep *
94 idx_vector::idx_colon_rep::sort_idx (Array<octave_idx_type>&)
95 {
96  (*current_liboctave_error_handler)
97  ("internal error: idx_colon_rep::sort_idx");
98 }
99 
100 std::ostream&
101 idx_vector::idx_colon_rep::print (std::ostream& os) const
102 {
103  return os << ':';
104 }
105 
106 idx_vector::idx_range_rep::idx_range_rep (octave_idx_type start,
107  octave_idx_type limit,
108  octave_idx_type step)
109  : idx_base_rep (), m_start(start),
110  // Round length away from zero to catch incomplete intervals
111  m_len (step
112  ? std::max ((limit - start + step - (step > 0 ? 1 : -1)) / step,
113  static_cast<octave_idx_type> (0))
114  : -1),
115  m_step (step)
116 {
117  if (m_len < 0)
118  err_invalid_range ();
119  if (m_start < 0)
120  err_invalid_index (m_start);
121  if (m_step < 0 && m_start + (m_len-1)*m_step < 0)
122  err_invalid_index (m_start + (m_len-1)*m_step);
123 }
124 
125 idx_vector::idx_range_rep::idx_range_rep (const range<double>& r)
126  : idx_base_rep (), m_start (0), m_len (r.numel ()), m_step (1)
127 {
128  if (m_len < 0)
129  err_invalid_range ();
130 
131  if (m_len > 0)
132  {
133  if (r.all_elements_are_ints ())
134  {
135  m_start = static_cast<octave_idx_type> (r.base ()) - 1;
136  m_step = static_cast<octave_idx_type> (r.increment ());
137  if (m_start < 0)
138  err_invalid_index (m_start);
139  if (m_step < 0 && m_start + (m_len - 1)*m_step < 0)
140  err_invalid_index (m_start + (m_len - 1)*m_step);
141  }
142  else
143  {
144  // find first non-integer, then gripe about it
145  double b = r.base ();
146  double inc = r.increment ();
147  err_invalid_index (b != std::trunc (b) ? b : b + inc);
148  }
149  }
150 }
151 
153 idx_vector::idx_range_rep::checkelem (octave_idx_type i) const
154 {
155  if (i < 0 || i >= m_len)
156  err_index_out_of_range ();
157 
158  return m_start + i*m_step;
159 }
160 
161 idx_vector::idx_base_rep *
162 idx_vector::idx_range_rep::sort_uniq_clone (bool)
163 {
164  if (m_step < 0)
165  return new idx_range_rep (m_start + (m_len - 1)*m_step, m_len, -m_step, DIRECT);
166  else
167  {
168  m_count++;
169  return this;
170  }
171 }
172 
173 idx_vector::idx_base_rep *
174 idx_vector::idx_range_rep::sort_idx (Array<octave_idx_type>& idx)
175 {
176  if (m_step < 0 && m_len > 0)
177  {
178  idx.clear (1, m_len);
179  for (octave_idx_type i = 0; i < m_len; i++)
180  idx.xelem (i) = m_len - 1 - i;
181  return new idx_range_rep (m_start + (m_len - 1)*m_step, m_len, -m_step, DIRECT);
182  }
183  else
184  {
185  idx.clear (1, m_len);
186  for (octave_idx_type i = 0; i < m_len; i++)
187  idx.xelem (i) = i;
188  m_count++;
189  return this;
190  }
191 }
192 
193 std::ostream&
194 idx_vector::idx_range_rep::print (std::ostream& os) const
195 {
196  os << m_start << ':' << m_step << ':' << m_start + m_len *m_step;
197  return os;
198 }
199 
201 idx_vector::idx_range_rep::unconvert () const
202 {
204  (static_cast<double> (m_start+1), static_cast<double> (m_step), m_len);
205 }
206 
208 idx_vector::idx_range_rep::as_array ()
209 {
210  Array<octave_idx_type> retval (dim_vector (1, m_len));
211  for (octave_idx_type i = 0; i < m_len; i++)
212  retval.xelem (i) = m_start + i*m_step;
213 
214  return retval;
215 }
216 
217 inline octave_idx_type
219 {
220  if (i <= 0)
221  err_invalid_index (i-1);
222 
223  if (ext < i)
224  ext = i;
225 
226  return i - 1;
227 }
228 
229 inline octave_idx_type
231 {
232  octave_idx_type i = static_cast<octave_idx_type> (x);
233 
234  if (static_cast<double> (i) != x)
235  err_invalid_index (x-1);
236 
237  return convert_index (i, ext);
238 }
239 
240 inline octave_idx_type
242 {
243  return convert_index (static_cast<double> (x), ext);
244 }
245 
246 template <typename T>
247 inline octave_idx_type
249 {
251 
252  return convert_index (i, ext);
253 }
254 
255 template <typename T>
256 idx_vector::idx_scalar_rep::idx_scalar_rep (T x)
257  : idx_base_rep (), m_data (0)
258 {
259  octave_idx_type dummy = 0;
260 
261  m_data = convert_index (x, dummy);
262 }
263 
264 idx_vector::idx_scalar_rep::idx_scalar_rep (octave_idx_type i)
265  : idx_base_rep (), m_data (i)
266 {
267  if (m_data < 0)
268  err_invalid_index (m_data);
269 }
270 
272 idx_vector::idx_scalar_rep::checkelem (octave_idx_type i) const
273 {
274  if (i != 0)
275  err_index_out_of_range ();
276 
277  return m_data;
278 }
279 
280 idx_vector::idx_base_rep *
281 idx_vector::idx_scalar_rep::sort_idx (Array<octave_idx_type>& idx)
282 {
283  idx.clear (1, 1);
284  idx.fill (0);
285  m_count++;
286  return this;
287 }
288 
289 std::ostream&
290 idx_vector::idx_scalar_rep::print (std::ostream& os) const
291 {
292  return os << m_data;
293 }
294 
295 double
296 idx_vector::idx_scalar_rep::unconvert () const
297 {
298  return m_data + 1;
299 }
300 
302 idx_vector::idx_scalar_rep::as_array ()
303 {
304  return Array<octave_idx_type> (dim_vector (1, 1), m_data);
305 }
306 
307 template <typename T>
308 idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>& nda)
309  : idx_base_rep (), m_data (nullptr), m_len (nda.numel ()), m_ext (0),
310  m_aowner (nullptr), m_orig_dims (nda.dims ())
311 {
312  if (m_len != 0)
313  {
314  std::unique_ptr<octave_idx_type []> d (new octave_idx_type [m_len]);
315 
316  for (octave_idx_type i = 0; i < m_len; i++)
317  d[i] = convert_index (nda.xelem (i), m_ext);
318 
319  m_data = d.release ();
320  }
321 }
322 
323 // Note that this makes a shallow copy of the index array.
324 
325 idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda)
326  : idx_base_rep (), m_data (inda.data ()), m_len (inda.numel ()), m_ext (0),
327  m_aowner (new Array<octave_idx_type> (inda)), m_orig_dims (inda.dims ())
328 {
329  if (m_len != 0)
330  {
331  octave_idx_type max = -1;
332  for (octave_idx_type i = 0; i < m_len; i++)
333  {
334  octave_idx_type k = inda.xelem (i);
335  if (k < 0)
336  err_invalid_index (k);
337  else if (k > max)
338  max = k;
339  }
340 
341  m_ext = max + 1;
342  }
343 }
344 
345 idx_vector::idx_vector_rep::idx_vector_rep (const Array<octave_idx_type>& inda,
346  octave_idx_type ext, direct)
347  : idx_base_rep (), m_data (inda.data ()), m_len (inda.numel ()),
348  m_ext (ext), m_aowner (new Array<octave_idx_type> (inda)),
349  m_orig_dims (inda.dims ())
350 {
351  // No checking.
352  if (m_ext < 0)
353  {
354  octave_idx_type max = -1;
355  for (octave_idx_type i = 0; i < m_len; i++)
356  if (m_data[i] > max)
357  max = m_data[i];
358 
359  m_ext = max + 1;
360  }
361 }
362 
363 idx_vector::idx_vector_rep::idx_vector_rep (bool b)
364  : idx_base_rep (), m_data (nullptr), m_len (b ? 1 : 0), m_ext (0),
365  m_aowner (nullptr), m_orig_dims (m_len, m_len)
366 {
367  if (m_len != 0)
368  {
369  octave_idx_type *d = new octave_idx_type [1];
370  d[0] = 0;
371  m_data = d;
372  m_ext = 1;
373  }
374 }
375 
376 idx_vector::idx_vector_rep::idx_vector_rep (const Array<bool>& bnda,
377  octave_idx_type nnz)
378  : idx_base_rep (), m_data (nullptr), m_len (nnz), m_ext (0),
379  m_aowner (nullptr), m_orig_dims ()
380 {
381  if (nnz < 0)
382  m_len = bnda.nnz ();
383 
384  const dim_vector dv = bnda.dims ();
385 
386  m_orig_dims = dv.make_nd_vector (m_len);
387 
388  if (m_len != 0)
389  {
390  octave_idx_type *d = new octave_idx_type [m_len];
391 
392  octave_idx_type ntot = bnda.numel ();
393 
394  octave_idx_type k = 0;
395  for (octave_idx_type i = 0; i < ntot; i++)
396  if (bnda.xelem (i))
397  d[k++] = i;
398 
399  m_data = d;
400 
401  m_ext = d[k-1] + 1;
402  }
403 }
404 
405 idx_vector::idx_vector_rep::idx_vector_rep (const Sparse<bool>& bnda)
406  : idx_base_rep (), m_data (nullptr), m_len (bnda.nnz ()), m_ext (0),
407  m_aowner (nullptr), m_orig_dims ()
408 {
409  const dim_vector dv = bnda.dims ();
410 
411  m_orig_dims = dv.make_nd_vector (m_len);
412 
413  if (m_len != 0)
414  {
415  octave_idx_type *d = new octave_idx_type [m_len];
416 
417  octave_idx_type k = 0;
418  octave_idx_type nc = bnda.cols ();
419  octave_idx_type nr = bnda.rows ();
420 
421  for (octave_idx_type j = 0; j < nc; j++)
422  for (octave_idx_type i = bnda.cidx (j); i < bnda.cidx (j+1); i++)
423  if (bnda.data (i))
424  d[k++] = j * nr + bnda.ridx (i);
425 
426  m_data = d;
427 
428  m_ext = d[k-1] + 1;
429  }
430 }
431 
432 idx_vector::idx_vector_rep::~idx_vector_rep ()
433 {
434  if (m_aowner)
435  delete m_aowner;
436  else
437  delete [] m_data;
438 }
439 
441 idx_vector::idx_vector_rep::checkelem (octave_idx_type n) const
442 {
443  if (n < 0 || n >= m_len)
445 
446  return xelem (n);
447 }
448 
449 idx_vector::idx_base_rep *
450 idx_vector::idx_vector_rep::sort_uniq_clone (bool uniq)
451 {
452  if (m_len == 0)
453  {
454  m_count++;
455  return this;
456  }
457 
458  // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
459  std::unique_ptr<idx_vector_rep> new_rep
460  (new idx_vector_rep (nullptr, m_len, m_ext, m_orig_dims, DIRECT));
461 
462  if (m_ext > m_len*math::log2 (1.0 + m_len))
463  {
464  // Use standard sort via octave_sort.
465  octave_idx_type *new_data = new octave_idx_type [m_len];
466  new_rep->m_data = new_data;
467 
468  std::copy_n (m_data, m_len, new_data);
470  lsort.set_compare (ASCENDING);
471  lsort.sort (new_data, m_len);
472 
473  if (uniq)
474  {
475  octave_idx_type new_len = std::unique (new_data, new_data + m_len)
476  - new_data;
477  new_rep->m_len = new_len;
478  if (new_rep->m_orig_dims.ndims () == 2 && new_rep->m_orig_dims(0) == 1)
479  new_rep->m_orig_dims = dim_vector (1, new_len);
480  else
481  new_rep->m_orig_dims = dim_vector (new_len, 1);
482  }
483  }
484  else if (uniq)
485  {
486  // Use two-pass bucket sort (only a mask array needed).
487  OCTAVE_LOCAL_BUFFER_INIT (bool, has, m_ext, false);
488  for (octave_idx_type i = 0; i < m_len; i++)
489  has[m_data[i]] = true;
490 
491  octave_idx_type new_len = 0;
492  for (octave_idx_type i = 0; i < m_ext; i++)
493  new_len += has[i];
494 
495  new_rep->m_len = new_len;
496  if (new_rep->m_orig_dims.ndims () == 2 && new_rep->m_orig_dims(0) == 1)
497  new_rep->m_orig_dims = dim_vector (1, new_len);
498  else
499  new_rep->m_orig_dims = dim_vector (new_len, 1);
500 
501  octave_idx_type *new_data = new octave_idx_type [new_len];
502  new_rep->m_data = new_data;
503 
504  for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
505  if (has[i])
506  new_data[j++] = i;
507  }
508  else
509  {
510  // Use two-pass bucket sort.
511  OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, cnt, m_ext, 0);
512  for (octave_idx_type i = 0; i < m_len; i++)
513  cnt[m_data[i]]++;
514 
515  octave_idx_type *new_data = new octave_idx_type [m_len];
516  new_rep->m_data = new_data;
517 
518  for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
519  {
520  for (octave_idx_type k = 0; k < cnt[i]; k++)
521  new_data[j++] = i;
522  }
523  }
524 
525  return new_rep.release ();
526 }
527 
528 idx_vector::idx_base_rep *
529 idx_vector::idx_vector_rep::sort_idx (Array<octave_idx_type>& idx)
530 {
531  // This is wrapped in unique_ptr so that we don't leak on out-of-memory.
532  std::unique_ptr<idx_vector_rep> new_rep
533  (new idx_vector_rep (nullptr, m_len, m_ext, m_orig_dims, DIRECT));
534 
535  if (m_ext > m_len*math::log2 (1.0 + m_len))
536  {
537  // Use standard sort via octave_sort.
538  idx.clear (m_orig_dims);
539  octave_idx_type *idx_data = idx.fortran_vec ();
540  for (octave_idx_type i = 0; i < m_len; i++)
541  idx_data[i] = i;
542 
543  octave_idx_type *new_data = new octave_idx_type [m_len];
544  new_rep->m_data = new_data;
545  std::copy_n (m_data, m_len, new_data);
546 
548  lsort.set_compare (ASCENDING);
549  lsort.sort (new_data, idx_data, m_len);
550  }
551  else
552  {
553  // Use two-pass bucket sort.
554  OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, cnt, m_ext, 0);
555 
556  for (octave_idx_type i = 0; i < m_len; i++)
557  cnt[m_data[i]]++;
558 
559  idx.clear (m_orig_dims);
560  octave_idx_type *idx_data = idx.fortran_vec ();
561 
562  octave_idx_type *new_data = new octave_idx_type [m_len];
563  new_rep->m_data = new_data;
564 
565  for (octave_idx_type i = 0, k = 0; i < m_ext; i++)
566  {
567  octave_idx_type j = cnt[i];
568  cnt[i] = k;
569  k += j;
570  }
571 
572  for (octave_idx_type i = 0; i < m_len; i++)
573  {
574  octave_idx_type j = m_data[i];
575  octave_idx_type k = cnt[j]++;
576  new_data[k] = j;
577  idx_data[k] = i;
578  }
579  }
580 
581  return new_rep.release ();
582 }
583 
584 std::ostream&
585 idx_vector::idx_vector_rep::print (std::ostream& os) const
586 {
587  os << '[';
588 
589  for (octave_idx_type i = 0; i < m_len - 1; i++)
590  os << m_data[i] << ',' << ' ';
591 
592  if (m_len > 0)
593  os << m_data[m_len-1];
594 
595  os << ']';
596 
597  return os;
598 }
599 
601 idx_vector::idx_vector_rep::unconvert () const
602 {
603  Array<double> retval (m_orig_dims);
604  for (octave_idx_type i = 0; i < m_len; i++)
605  retval.xelem (i) = m_data[i] + 1;
606  return retval;
607 }
608 
610 idx_vector::idx_vector_rep::as_array ()
611 {
612  if (m_aowner)
613  return *m_aowner;
614  else
615  {
616  Array<octave_idx_type> retval (m_orig_dims);
617 
618  if (m_data)
619  {
620  std::memcpy (retval.fortran_vec (), m_data, m_len* sizeof (octave_idx_type));
621  // Delete the old copy and share the m_data instead to save memory.
622  delete [] m_data;
623  }
624 
625  m_data = retval.fortran_vec ();
626  m_aowner = new Array<octave_idx_type> (retval);
627 
628  return retval;
629  }
630 }
631 
632 idx_vector::idx_mask_rep::idx_mask_rep (bool b)
633  : idx_base_rep (), m_data (nullptr), m_len (b ? 1 : 0), m_ext (0),
634  m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims (m_len, m_len)
635 {
636  if (m_len != 0)
637  {
638  bool *d = new bool [1];
639  d[0] = true;
640  m_data = d;
641  m_ext = 1;
642  }
643 }
644 
645 idx_vector::idx_mask_rep::idx_mask_rep (const Array<bool>& bnda,
646  octave_idx_type nnz)
647  : idx_base_rep (), m_data (nullptr), m_len (nnz), m_ext (bnda.numel ()),
648  m_lsti (-1), m_lste (-1), m_aowner (nullptr), m_orig_dims ()
649 {
650  if (nnz < 0)
651  m_len = bnda.nnz ();
652 
653  // We truncate the extent as much as possible. For Matlab
654  // compatibility, but maybe it's not a bad idea anyway.
655  while (m_ext > 0 && ! bnda(m_ext-1))
656  m_ext--;
657 
658  const dim_vector dv = bnda.dims ();
659 
660  m_orig_dims = dv.make_nd_vector (m_len);
661 
662  m_aowner = new Array<bool> (bnda);
663  m_data = bnda.data ();
664 }
665 
666 idx_vector::idx_mask_rep::~idx_mask_rep ()
667 {
668  if (m_aowner)
669  delete m_aowner;
670  else
671  delete [] m_data;
672 }
673 
675 idx_vector::idx_mask_rep::xelem (octave_idx_type n) const
676 {
677  if (n == m_lsti + 1)
678  {
679  m_lsti = n;
680  while (! m_data[++m_lste]) ;
681  }
682  else
683  {
684  m_lsti = n++;
685  m_lste = -1;
686  while (n > 0)
687  if (m_data[++m_lste]) --n;
688  }
689  return m_lste;
690 }
691 
693 idx_vector::idx_mask_rep::checkelem (octave_idx_type n) const
694 {
695  if (n < 0 || n >= m_len)
697 
698  return xelem (n);
699 }
700 
701 std::ostream&
702 idx_vector::idx_mask_rep::print (std::ostream& os) const
703 {
704  os << '[';
705 
706  for (octave_idx_type i = 0; i < m_ext - 1; i++)
707  os << m_data[i] << ',' << ' ';
708 
709  if (m_ext > 0)
710  os << m_data[m_ext-1];
711 
712  os << ']';
713 
714  return os;
715 }
716 
718 idx_vector::idx_mask_rep::unconvert () const
719 {
720  if (m_aowner)
721  return *m_aowner;
722  else
723  {
724  Array<bool> retval (dim_vector (m_ext, 1));
725  for (octave_idx_type i = 0; i < m_ext; i++)
726  retval.xelem (i) = m_data[i];
727  return retval;
728  }
729 }
730 
732 idx_vector::idx_mask_rep::as_array ()
733 {
734  if (m_aowner)
735  return m_aowner->find ().reshape (m_orig_dims);
736  else
737  {
738  Array<bool> retval (m_orig_dims);
739  for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
740  if (m_data[i])
741  retval.xelem (j++) = i;
742 
743  return retval;
744  }
745 }
746 
747 idx_vector::idx_base_rep *
748 idx_vector::idx_mask_rep::sort_idx (Array<octave_idx_type>& idx)
749 {
750  idx.clear (m_len, 1);
751  for (octave_idx_type i = 0; i < m_len; i++)
752  idx.xelem (i) = i;
753 
754  m_count++;
755  return this;
756 }
757 
758 const idx_vector idx_vector::colon (new idx_vector::idx_colon_rep ());
759 
761  : m_rep (nullptr)
762 {
763  // Convert only if it means saving at least half the memory.
764  static const int factor = (2 * sizeof (octave_idx_type));
765  octave_idx_type nnz = bnda.nnz ();
766  if (nnz <= bnda.numel () / factor)
767  m_rep = new idx_vector_rep (bnda, nnz);
768  else
769  m_rep = new idx_mask_rep (bnda, nnz);
770 }
771 
772 bool
774  octave_idx_type nj)
775 {
776  bool reduced = false;
777 
778  // Empty index always reduces.
779  if (m_rep->length (n) == 0)
780  {
781  *this = idx_vector ();
782  return true;
783  }
784 
785  // Possibly skip singleton dims.
786  if (n == 1 && m_rep->is_colon_equiv (n))
787  {
788  *this = j;
789  return true;
790  }
791 
792  if (nj == 1 && j.is_colon_equiv (nj))
793  return true;
794 
795  switch (j.idx_class ())
796  {
797  case class_colon:
798  switch (m_rep->idx_class ())
799  {
800  case class_colon:
801  // (:,:) reduces to (:)
802  reduced = true;
803  break;
804 
805  case class_scalar:
806  {
807  // (i,:) reduces to a range.
808  idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
809  octave_idx_type k = r->get_data ();
810  *this = new idx_range_rep (k, nj, n, DIRECT);
811  reduced = true;
812  }
813  break;
814 
815  case class_range:
816  {
817  // (i:k:end,:) reduces to a range if i <= k and k divides n.
818  idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
819  octave_idx_type s = r->get_start ();
820  octave_idx_type l = r->length (n);
821  octave_idx_type t = r->get_step ();
822  if (l*t == n)
823  {
824  *this = new idx_range_rep (s, l * nj, t, DIRECT);
825  reduced = true;
826  }
827  }
828  break;
829 
830  default:
831  break;
832  }
833  break;
834 
835  case class_range:
836  switch (m_rep->idx_class ())
837  {
838  case class_colon:
839  {
840  // (:,i:j) reduces to a range (the m_step must be 1)
841  idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
842  if (rj->get_step () == 1)
843  {
844  octave_idx_type sj = rj->get_start ();
845  octave_idx_type lj = rj->length (nj);
846  *this = new idx_range_rep (sj * n, lj * n, 1, DIRECT);
847  reduced = true;
848  }
849  }
850  break;
851 
852  case class_scalar:
853  {
854  // (k,i:d:j) reduces to a range.
855  idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
856  idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
857  octave_idx_type k = r->get_data ();
858  octave_idx_type sj = rj->get_start ();
859  octave_idx_type lj = rj->length (nj);
860  octave_idx_type tj = rj->get_step ();
861  *this = new idx_range_rep (n * sj + k, lj, n * tj, DIRECT);
862  reduced = true;
863  }
864  break;
865 
866  case class_range:
867  {
868  // (i:k:end,p:q) reduces to a range if i <= k and k divides n.
869  // (ones (1, m), ones (1, n)) reduces to (ones (1, m*n))
870  idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
871  octave_idx_type s = r->get_start ();
872  octave_idx_type l = r->length (n);
873  octave_idx_type t = r->get_step ();
874  idx_range_rep *rj = dynamic_cast<idx_range_rep *> (j.m_rep);
875  octave_idx_type sj = rj->get_start ();
876  octave_idx_type lj = rj->length (nj);
877  octave_idx_type tj = rj->get_step ();
878  if ((l*t == n && tj == 1) || (t == 0 && tj == 0))
879  {
880  *this = new idx_range_rep (s + n * sj, l * lj, t, DIRECT);
881  reduced = true;
882  }
883  }
884  break;
885 
886  default:
887  break;
888  }
889  break;
890 
891  case class_scalar:
892  switch (m_rep->idx_class ())
893  {
894  case class_scalar:
895  {
896  // (i,j) reduces to a single index.
897  idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
898  idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
899  octave_idx_type k = r->get_data () + n * rj->get_data ();
900  *this = new idx_scalar_rep (k, DIRECT);
901  reduced = true;
902  }
903  break;
904 
905  case class_range:
906  {
907  // (i:d:j,k) reduces to a range.
908  idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
909  idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
910  octave_idx_type s = r->get_start ();
911  octave_idx_type l = r->length (nj);
912  octave_idx_type t = r->get_step ();
913  octave_idx_type k = rj->get_data ();
914  *this = new idx_range_rep (n * k + s, l, t, DIRECT);
915  reduced = true;
916  }
917  break;
918 
919  case class_colon:
920  {
921  // (:,k) reduces to a range.
922  idx_scalar_rep *rj = dynamic_cast<idx_scalar_rep *> (j.m_rep);
923  octave_idx_type k = rj->get_data ();
924  *this = new idx_range_rep (n * k, n, 1, DIRECT);
925  reduced = true;
926  }
927  break;
928 
929  default:
930  break;
931  }
932  break;
933 
934  default:
935  break;
936  }
937 
938  return reduced;
939 }
940 
941 bool
943  octave_idx_type& u) const
944 {
945  bool res = false;
946 
947  switch (m_rep->idx_class ())
948  {
949  case class_colon:
950  l = 0; u = n;
951  res = true;
952  break;
953 
954  case class_range:
955  {
956  idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
957  if (r->get_step () == 1)
958  {
959  l = r->get_start ();
960  u = l + r->length (n);
961  res = true;
962  }
963  }
964  break;
965 
966  case class_scalar:
967  {
968  idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
969  l = r->get_data ();
970  u = l + 1;
971  res = true;
972  }
973  break;
974 
975  case class_mask:
976  {
977  idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
978  octave_idx_type m_ext = r->extent (0);
979  octave_idx_type m_len = r->length (0);
980  if (m_ext == m_len)
981  {
982  l = 0;
983  u = m_len;
984  res = true;
985  }
986  }
987 
988  default:
989  break;
990  }
991 
992  return res;
993 }
994 
997 {
998  octave_idx_type retval = 0;
999 
1000  switch (m_rep->idx_class ())
1001  {
1002  case class_colon:
1003  retval = 1;
1004  break;
1005 
1006  case class_range:
1007  retval = dynamic_cast<idx_range_rep *> (m_rep) -> get_step ();
1008  break;
1009 
1010  case class_vector:
1011  case class_mask:
1012  {
1013  if (length (0) > 1)
1014  retval = elem (1) - elem (0);
1015  }
1016  break;
1017 
1018  default:
1019  break;
1020  }
1021 
1022  return retval;
1023 }
1024 
1025 const octave_idx_type *
1027 {
1028  if (m_rep->idx_class () != class_vector)
1029  *this = idx_vector (as_array (), extent (0));
1030 
1031  idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1032 
1033  assert (r != nullptr);
1034 
1035  return r->get_data ();
1036 }
1037 
1038 void
1040 {
1041  octave_idx_type m_len = m_rep->length (0);
1042 
1043  switch (m_rep->idx_class ())
1044  {
1045  case class_colon:
1046  (*current_liboctave_error_handler) ("colon not allowed");
1047  break;
1048 
1049  case class_range:
1050  {
1051  idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
1052  octave_idx_type m_start = r->get_start ();
1053  octave_idx_type m_step = r->get_step ();
1054  octave_idx_type i, j;
1055  if (m_step == 1)
1056  for (i = m_start, j = m_start + m_len; i < j; i++) *m_data++ = i;
1057  else if (m_step == -1)
1058  for (i = m_start, j = m_start - m_len; i > j; i--) *m_data++ = i;
1059  else
1060  for (i = 0, j = m_start; i < m_len; i++, j += m_step) *m_data++ = j;
1061  }
1062  break;
1063 
1064  case class_scalar:
1065  {
1066  idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
1067  *m_data = r->get_data ();
1068  }
1069  break;
1070 
1071  case class_vector:
1072  {
1073  idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1074  const octave_idx_type *rdata = r->get_data ();
1075  std::copy_n (rdata, m_len, m_data);
1076  }
1077  break;
1078 
1079  case class_mask:
1080  {
1081  idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1082  const bool *mask = r->get_data ();
1083  octave_idx_type m_ext = r->extent (0);
1084  for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
1085  if (mask[i])
1086  m_data[j++] = i;
1087  }
1088  break;
1089 
1090  default:
1091  assert (false);
1092  break;
1093  }
1094 }
1095 
1096 idx_vector
1098 {
1099  idx_vector retval;
1100  if (extent (n) > n)
1101  (*current_liboctave_error_handler)
1102  ("internal error: out of range complement index requested");
1103 
1104  if (idx_class () == class_mask)
1105  {
1106  idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1107  octave_idx_type nz = r->length (0);
1108  octave_idx_type m_ext = r->extent (0);
1109  Array<bool> mask (dim_vector (n, 1));
1110  const bool *m_data = r->get_data ();
1111  bool *ndata = mask.fortran_vec ();
1112  for (octave_idx_type i = 0; i < m_ext; i++)
1113  ndata[i] = ! m_data[i];
1114  std::fill_n (ndata + m_ext, n - m_ext, true);
1115  retval = new idx_mask_rep (mask, n - nz);
1116  }
1117  else
1118  {
1119  Array<bool> mask (dim_vector (n, 1), true);
1120  fill (false, length (n), mask.fortran_vec ());
1121  retval = idx_vector (mask);
1122  }
1123 
1124  return retval;
1125 }
1126 
1127 bool
1129 {
1130  bool retval = false;
1131 
1132  if (is_colon_equiv (n))
1133  retval = true;
1134  else if (length(n) == n && extent(n) == n)
1135  {
1136  OCTAVE_LOCAL_BUFFER_INIT (bool, left, n, true);
1137 
1138  retval = true;
1139 
1140  for (octave_idx_type i = 0, m_len = length (); i < m_len; i++)
1141  {
1142  octave_idx_type k = xelem (i);
1143  if (left[k])
1144  left[k] = false;
1145  else
1146  {
1147  retval = false;
1148  break;
1149  }
1150  }
1151  }
1152 
1153  return retval;
1154 }
1155 
1156 idx_vector
1158 {
1159  assert (n == length (n));
1160 
1161  idx_vector retval;
1162 
1163  switch (idx_class ())
1164  {
1165  case class_range:
1166  {
1167  if (increment () == -1)
1168  retval = sorted ();
1169  else
1170  retval = *this;
1171  break;
1172  }
1173  case class_vector:
1174  {
1175  idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1176  const octave_idx_type *ri = r->get_data ();
1178  for (octave_idx_type i = 0; i < n; i++)
1179  idx.xelem (ri[i]) = i;
1180  retval = new idx_vector_rep (idx, r->extent (0), DIRECT);
1181  break;
1182  }
1183  default:
1184  retval = *this;
1185  break;
1186  }
1187 
1188  return retval;
1189 }
1190 
1191 idx_vector
1193 {
1194  if (idx_class () == class_mask)
1195  {
1196  idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1197  const bool *m_data = r->get_data ();
1198  octave_idx_type m_ext = r->extent (0);
1199  octave_idx_type m_len = r->length (0);
1200  octave_idx_type *idata = new octave_idx_type [m_len];
1201 
1202  for (octave_idx_type i = 0, j = 0; i < m_ext; i++)
1203  if (m_data[i])
1204  idata[j++] = i;
1205 
1206  m_ext = (m_len > 0 ? idata[m_len - 1] + 1 : 0);
1207 
1208  return new idx_vector_rep (idata, m_len, m_ext, r->orig_dimensions (),
1209  DIRECT);
1210  }
1211  else
1212  return *this;
1213 }
1214 
1215 void
1217  double& scalar, range<double>& range,
1218  Array<double>& array, Array<bool>& mask) const
1219 {
1220  iclass = idx_class ();
1221  switch (iclass)
1222  {
1223  case class_colon:
1224  break;
1225 
1226  case class_range:
1227  {
1228  idx_range_rep *r = dynamic_cast<idx_range_rep *> (m_rep);
1229  range = r->unconvert ();
1230  }
1231  break;
1232 
1233  case class_scalar:
1234  {
1235  idx_scalar_rep *r = dynamic_cast<idx_scalar_rep *> (m_rep);
1236  scalar = r->unconvert ();
1237  }
1238  break;
1239 
1240  case class_vector:
1241  {
1242  idx_vector_rep *r = dynamic_cast<idx_vector_rep *> (m_rep);
1243  array = r->unconvert ();
1244  }
1245  break;
1246 
1247  case class_mask:
1248  {
1249  idx_mask_rep *r = dynamic_cast<idx_mask_rep *> (m_rep);
1250  mask = r->unconvert ();
1251  }
1252  break;
1253 
1254  default:
1255  assert (false);
1256  break;
1257  }
1258 }
1259 
1262 {
1263  return m_rep->as_array ();
1264 }
1265 
1266 bool
1268 {
1269  return idx_class () != class_vector || orig_dimensions ().isvector ();
1270 }
1271 
1273 idx_vector::freeze (octave_idx_type z_len, const char *, bool resize_ok)
1274 {
1275  if (! resize_ok && extent (z_len) > z_len)
1276  (*current_liboctave_error_handler)
1277  ("invalid matrix index = %" OCTAVE_IDX_TYPE_FORMAT, extent (z_len));
1278 
1279  return length (z_len);
1280 }
1281 
1284 {
1285  octave_idx_type n = 0;
1286 
1287  if (is_colon ())
1288  n = 1;
1289  else
1290  {
1291  for (octave_idx_type i = 0; i < length (1); i++)
1292  if (xelem (i) == 0)
1293  n++;
1294  }
1295 
1296  return n;
1297 }
1298 
1299 // Instantiate the octave_int constructors we want.
1300 #define INSTANTIATE_SCALAR_VECTOR_REP_CONST(T) \
1301  template OCTAVE_API idx_vector::idx_scalar_rep::idx_scalar_rep (T); \
1302  template OCTAVE_API idx_vector::idx_vector_rep::idx_vector_rep (const Array<T>&);
1303 
1314 
1315 OCTAVE_END_NAMESPACE(octave)
1316 
1317 /*
1318 
1319 %!error id=Octave:index-out-of-bounds 1(find ([1,1] != 0))
1320 %!assert ((1:3)(find ([1,0,1] != 0)), [1,3])
1321 
1322 */
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
void clear()
Definition: Array-base.cc:109
octave_idx_type nnz() const
Count nonzero elements.
Definition: Array-base.cc:2223
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
Array< octave_idx_type > find(octave_idx_type n=-1, bool backward=false) const
Find indices of (at most n) nonzero elements.
Definition: Array-base.cc:2238
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
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
void fill(const T &val)
Definition: Array-base.cc:95
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
octave_idx_type cols() const
Definition: Sparse.h:352
octave_idx_type * cidx()
Definition: Sparse.h:596
T * data()
Definition: Sparse.h:574
octave_idx_type * ridx()
Definition: Sparse.h:583
octave_idx_type rows() const
Definition: Sparse.h:351
dim_vector dims() const
Definition: Sparse.h:371
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
bool isvector() const
Definition: dim-vector.h:395
dim_vector make_nd_vector(octave_idx_type n) const
Definition: dim-vector.h:421
idx_vector unmask() const
Definition: idx-vector.cc:1192
octave_idx_type xelem(octave_idx_type n) const
Definition: idx-vector.h:526
idx_class_type idx_class() const
Definition: idx-vector.h:518
octave_idx_type ones_count() const
Definition: idx-vector.cc:1283
idx_vector sorted(bool uniq=false) const
Definition: idx-vector.h:552
octave_idx_type fill(const T &val, octave_idx_type n, T *dest) const
Definition: idx-vector.h:732
static const idx_vector colon
Definition: idx-vector.h:466
dim_vector orig_dimensions() const
Definition: idx-vector.h:558
bool maybe_reduce(octave_idx_type n, const idx_vector &j, octave_idx_type nj)
Definition: idx-vector.cc:773
void copy_data(octave_idx_type *data) const
Definition: idx-vector.cc:1039
void unconvert(idx_class_type &iclass, double &scalar, range< double > &range, Array< double > &array, Array< bool > &mask) const
Definition: idx-vector.cc:1216
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:520
octave_idx_type elem(octave_idx_type n) const
Definition: idx-vector.h:995
octave_idx_type freeze(octave_idx_type z_len, const char *tag, bool resize_ok=false)
Definition: idx-vector.cc:1273
bool is_cont_range(octave_idx_type n, octave_idx_type &l, octave_idx_type &u) const
Definition: idx-vector.cc:942
idx_vector complement(octave_idx_type n) const
Definition: idx-vector.cc:1097
Array< octave_idx_type > as_array() const
Definition: idx-vector.cc:1261
bool is_permutation(octave_idx_type n) const
Definition: idx-vector.cc:1128
bool isvector() const
Definition: idx-vector.cc:1267
idx_vector inverse_permutation(octave_idx_type n) const
Definition: idx-vector.cc:1157
bool is_colon() const
Definition: idx-vector.h:540
octave_idx_type increment() const
Definition: idx-vector.cc:996
octave_idx_type extent(octave_idx_type n) const
Definition: idx-vector.h:523
const octave_idx_type * raw()
Definition: idx-vector.cc:1026
@ class_vector
Definition: idx-vector.h:69
@ class_scalar
Definition: idx-vector.h:68
bool is_colon_equiv(octave_idx_type n) const
Definition: idx-vector.h:549
T value() const
Definition: oct-inttypes.h:832
void set_compare(const compare_fcn_type &comp)
Definition: oct-sort.h:117
void sort(T *data, octave_idx_type nel)
Definition: oct-sort.cc:1522
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define INSTANTIATE_SCALAR_VECTOR_REP_CONST(T)
Definition: idx-vector.cc:1300
octave_idx_type convert_index(octave_idx_type i, octave_idx_type &ext)
Definition: idx-vector.cc:218
void err_invalid_index(const std::string &idx, octave_idx_type nd, octave_idx_type dim, const std::string &)
Complex log2(const Complex &x)
Definition: lo-mappers.cc:141
std::complex< T > trunc(const std::complex< T > &x)
Definition: lo-mappers.h:111
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value)
Definition: oct-locbuf.h:50
@ ASCENDING
Definition: oct-sort.h:97
T::size_type numel(const T &str)
Definition: oct-string.cc:74