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