GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Array.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2021 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 // This file should not include config.h. It is only included in other
27 // C++ source files that should have included config.h before including
28 // this file.
29 
30 #include <ostream>
31 
32 #include "Array-util.h"
33 #include "Array.h"
34 #include "lo-mappers.h"
35 #include "oct-locbuf.h"
36 
37 // One dimensional array class. Handles the reference counting for
38 // all the derived classes.
39 
40 template <typename T>
41 typename Array<T>::ArrayRep *
43 {
44  static ArrayRep nr;
45  return &nr;
46 }
47 
48 // This is similar to the template for containers but specialized for Array.
49 // Note we can't specialize a member without also specializing the class.
50 template <typename T>
51 Array<T>::Array (const Array<T>& a, const dim_vector& dv)
52  : dimensions (dv), rep (a.rep),
53  slice_data (a.slice_data), slice_len (a.slice_len)
54 {
55  if (dimensions.safe_numel () != a.numel ())
56  {
57  std::string dimensions_str = a.dimensions.str ();
58  std::string new_dims_str = dimensions.str ();
59 
60  (*current_liboctave_error_handler)
61  ("reshape: can't reshape %s array to %s array",
62  dimensions_str.c_str (), new_dims_str.c_str ());
63  }
64 
65  // This goes here because if an exception is thrown by the above,
66  // destructor will be never called.
67  rep->count++;
69 }
70 
71 template <typename T>
72 void
73 Array<T>::fill (const T& val)
74 {
75  if (rep->count > 1)
76  {
77  --rep->count;
78  rep = new ArrayRep (numel (), val);
79  slice_data = rep->data;
80  }
81  else
82  std::fill_n (slice_data, slice_len, val);
83 }
84 
85 template <typename T>
86 void
88 {
89  if (--rep->count == 0)
90  delete rep;
91 
92  rep = nil_rep ();
93  rep->count++;
94  slice_data = rep->data;
95  slice_len = rep->len;
96 
97  dimensions = dim_vector ();
98 }
99 
100 template <typename T>
101 void
103 {
104  if (--rep->count == 0)
105  delete rep;
106 
107  rep = new ArrayRep (dv.safe_numel ());
108  slice_data = rep->data;
109  slice_len = rep->len;
110 
111  dimensions = dv;
112  dimensions.chop_trailing_singletons ();
113 }
114 
115 template <typename T>
116 Array<T>
117 Array<T>::squeeze (void) const
118 {
119  Array<T> retval = *this;
120 
121  if (ndims () > 2)
122  {
123  bool dims_changed = false;
124 
125  dim_vector new_dimensions = dimensions;
126 
127  int k = 0;
128 
129  for (int i = 0; i < ndims (); i++)
130  {
131  if (dimensions(i) == 1)
132  dims_changed = true;
133  else
134  new_dimensions(k++) = dimensions(i);
135  }
136 
137  if (dims_changed)
138  {
139  switch (k)
140  {
141  case 0:
142  new_dimensions = dim_vector (1, 1);
143  break;
144 
145  case 1:
146  {
147  octave_idx_type tmp = new_dimensions(0);
148 
149  new_dimensions.resize (2);
150 
151  new_dimensions(0) = tmp;
152  new_dimensions(1) = 1;
153  }
154  break;
155 
156  default:
157  new_dimensions.resize (k);
158  break;
159  }
160  }
161 
162  retval = Array<T> (*this, new_dimensions);
163  }
164 
165  return retval;
166 }
167 
168 template <typename T>
171 {
172  return ::compute_index (i, j, dimensions);
173 }
174 
175 template <typename T>
178  octave_idx_type k) const
179 {
180  return ::compute_index (i, j, k, dimensions);
181 }
182 
183 template <typename T>
186 {
187  return ::compute_index (ra_idx, dimensions);
188 }
189 
190 template <typename T>
191 T&
193 {
194  // Do checks directly to avoid recomputing slice_len.
195  if (n < 0)
197  if (n >= slice_len)
198  octave::err_index_out_of_range (1, 1, n+1, slice_len, dimensions);
199 
200  return elem (n);
201 }
202 
203 template <typename T>
204 T&
206 {
207  return elem (compute_index (i, j));
208 }
209 
210 template <typename T>
211 T&
213 {
214  return elem (compute_index (i, j, k));
215 }
216 
217 template <typename T>
218 T&
220 {
221  return elem (compute_index (ra_idx));
222 }
223 
224 template <typename T>
225 typename Array<T>::crefT
227 {
228  // Do checks directly to avoid recomputing slice_len.
229  if (n < 0)
231  if (n >= slice_len)
232  octave::err_index_out_of_range (1, 1, n+1, slice_len, dimensions);
233 
234  return elem (n);
235 }
236 
237 template <typename T>
238 typename Array<T>::crefT
240 {
241  return elem (compute_index (i, j));
242 }
243 
244 template <typename T>
245 typename Array<T>::crefT
247  octave_idx_type k) const
248 {
249  return elem (compute_index (i, j, k));
250 }
251 
252 template <typename T>
253 typename Array<T>::crefT
255 {
256  return elem (compute_index (ra_idx));
257 }
258 
259 template <typename T>
260 Array<T>
262 {
263  octave_idx_type r = dimensions(0);
264 
265  return Array<T> (*this, dim_vector (r, 1), k*r, k*r + r);
266 }
267 
268 template <typename T>
269 Array<T>
271 {
272  octave_idx_type r = dimensions(0);
273  octave_idx_type c = dimensions(1);
274  octave_idx_type p = r*c;
275 
276  return Array<T> (*this, dim_vector (r, c), k*p, k*p + p);
277 }
278 
279 template <typename T>
280 Array<T>
282 {
283  if (up < lo)
284  up = lo;
285 
286  return Array<T> (*this, dim_vector (up - lo, 1), lo, up);
287 }
288 
289 // Helper class for multi-d dimension permuting (generalized transpose).
291 {
292  // STRIDE occupies the last half of the space allocated for dim to
293  // avoid a double allocation.
294 
295  int n;
296  int top;
299  bool use_blk;
300 
301 public:
303 
304  : n (dv.ndims ()), top (0), dim (new octave_idx_type [2*n]),
305  stride (dim + n), use_blk (false)
306  {
307  assert (n == perm.numel ());
308 
309  // Get cumulative dimensions.
311  cdim[0] = 1;
312  for (int i = 1; i < n+1; i++) cdim[i] = cdim[i-1] * dv(i-1);
313 
314  // Setup the permuted strides.
315  for (int k = 0; k < n; k++)
316  {
317  int kk = perm(k);
318  dim[k] = dv(kk);
319  stride[k] = cdim[kk];
320  }
321 
322  // Reduce contiguous runs.
323  for (int k = 1; k < n; k++)
324  {
325  if (stride[k] == stride[top]*dim[top])
326  dim[top] *= dim[k];
327  else
328  {
329  top++;
330  dim[top] = dim[k];
331  stride[top] = stride[k];
332  }
333  }
334 
335  // Determine whether we can use block transposes.
336  use_blk = top >= 1 && stride[1] == 1 && stride[0] == dim[1];
337 
338  }
339 
340  // No copying!
341 
343 
345 
346  ~rec_permute_helper (void) { delete [] dim; }
347 
348  // Helper method for fast blocked transpose.
349  template <typename T>
350  static T *
351  blk_trans (const T *src, T *dest, octave_idx_type nr, octave_idx_type nc)
352  {
353  static const octave_idx_type m = 8;
354  OCTAVE_LOCAL_BUFFER (T, blk, m*m);
355  for (octave_idx_type kr = 0; kr < nr; kr += m)
356  for (octave_idx_type kc = 0; kc < nc; kc += m)
357  {
358  octave_idx_type lr = std::min (m, nr - kr);
359  octave_idx_type lc = std::min (m, nc - kc);
360  if (lr == m && lc == m)
361  {
362  const T *ss = src + kc * nr + kr;
363  for (octave_idx_type j = 0; j < m; j++)
364  for (octave_idx_type i = 0; i < m; i++)
365  blk[j*m+i] = ss[j*nr + i];
366  T *dd = dest + kr * nc + kc;
367  for (octave_idx_type j = 0; j < m; j++)
368  for (octave_idx_type i = 0; i < m; i++)
369  dd[j*nc+i] = blk[i*m+j];
370  }
371  else
372  {
373  const T *ss = src + kc * nr + kr;
374  for (octave_idx_type j = 0; j < lc; j++)
375  for (octave_idx_type i = 0; i < lr; i++)
376  blk[j*m+i] = ss[j*nr + i];
377  T *dd = dest + kr * nc + kc;
378  for (octave_idx_type j = 0; j < lr; j++)
379  for (octave_idx_type i = 0; i < lc; i++)
380  dd[j*nc+i] = blk[i*m+j];
381  }
382  }
383 
384  return dest + nr*nc;
385  }
386 
387 private:
388 
389  // Recursive N-D generalized transpose
390  template <typename T>
391  T * do_permute (const T *src, T *dest, int lev) const
392  {
393  if (lev == 0)
394  {
395  octave_idx_type step = stride[0];
396  octave_idx_type len = dim[0];
397  if (step == 1)
398  {
399  std::copy_n (src, len, dest);
400  dest += len;
401  }
402  else
403  {
404  for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
405  dest[i] = src[j];
406 
407  dest += len;
408  }
409  }
410  else if (use_blk && lev == 1)
411  dest = blk_trans (src, dest, dim[1], dim[0]);
412  else
413  {
414  octave_idx_type step = stride[lev];
415  octave_idx_type len = dim[lev];
416  for (octave_idx_type i = 0, j = 0; i < len; i++, j+= step)
417  dest = do_permute (src + i * step, dest, lev-1);
418  }
419 
420  return dest;
421  }
422 
423 public:
424 
425  template <typename T>
426  void permute (const T *src, T *dest) const { do_permute (src, dest, top); }
427 };
428 
429 template <typename T>
430 Array<T>
431 Array<T>::permute (const Array<octave_idx_type>& perm_vec_arg, bool inv) const
432 {
434 
435  Array<octave_idx_type> perm_vec = perm_vec_arg;
436 
437  dim_vector dv = dims ();
438 
439  int perm_vec_len = perm_vec_arg.numel ();
440 
441  if (perm_vec_len < dv.ndims ())
442  (*current_liboctave_error_handler)
443  ("%s: invalid permutation vector", inv ? "ipermute" : "permute");
444 
445  dim_vector dv_new = dim_vector::alloc (perm_vec_len);
446 
447  // Append singleton dimensions as needed.
448  dv.resize (perm_vec_len, 1);
449 
450  // Need this array to check for identical elements in permutation array.
451  OCTAVE_LOCAL_BUFFER_INIT (bool, checked, perm_vec_len, false);
452 
453  bool identity = true;
454 
455  // Find dimension vector of permuted array.
456  for (int i = 0; i < perm_vec_len; i++)
457  {
458  octave_idx_type perm_elt = perm_vec.elem (i);
459  if (perm_elt >= perm_vec_len || perm_elt < 0)
460  (*current_liboctave_error_handler)
461  ("%s: permutation vector contains an invalid element",
462  inv ? "ipermute" : "permute");
463 
464  if (checked[perm_elt])
465  (*current_liboctave_error_handler)
466  ("%s: permutation vector cannot contain identical elements",
467  inv ? "ipermute" : "permute");
468  else
469  {
470  checked[perm_elt] = true;
471  identity = identity && perm_elt == i;
472  }
473  }
474 
475  if (identity)
476  return *this;
477 
478  if (inv)
479  {
480  for (int i = 0; i < perm_vec_len; i++)
481  perm_vec(perm_vec_arg(i)) = i;
482  }
483 
484  for (int i = 0; i < perm_vec_len; i++)
485  dv_new(i) = dv(perm_vec(i));
486 
487  retval = Array<T> (dv_new);
488 
489  if (numel () > 0)
490  {
491  rec_permute_helper rh (dv, perm_vec);
492  rh.permute (data (), retval.fortran_vec ());
493  }
494 
495  return retval;
496 }
497 
498 // Helper class for multi-d index reduction and recursive
499 // indexing/indexed assignment. Rationale: we could avoid recursion
500 // using a state machine instead. However, using recursion is much
501 // more amenable to possible parallelization in the future.
502 // Also, the recursion solution is cleaner and more understandable.
503 
505 {
506  // CDIM occupies the last half of the space allocated for dim to
507  // avoid a double allocation.
508 
509  int n;
510  int top;
514 
515 public:
517  : n (ia.numel ()), top (0), dim (new octave_idx_type [2*n]),
518  cdim (dim + n), idx (new idx_vector [n])
519  {
520  assert (n > 0 && (dv.ndims () == std::max (n, 2)));
521 
522  dim[0] = dv(0);
523  cdim[0] = 1;
524  idx[0] = ia(0);
525 
526  for (int i = 1; i < n; i++)
527  {
528  // Try reduction...
529  if (idx[top].maybe_reduce (dim[top], ia(i), dv(i)))
530  {
531  // Reduction successful, fold dimensions.
532  dim[top] *= dv(i);
533  }
534  else
535  {
536  // Unsuccessful, store index & cumulative dim.
537  top++;
538  idx[top] = ia(i);
539  dim[top] = dv(i);
540  cdim[top] = cdim[top-1] * dim[top-1];
541  }
542  }
543  }
544 
545  // No copying!
546 
548 
550 
551  ~rec_index_helper (void) { delete [] idx; delete [] dim; }
552 
553 private:
554 
555  // Recursive N-D indexing
556  template <typename T>
557  T * do_index (const T *src, T *dest, int lev) const
558  {
559  if (lev == 0)
560  dest += idx[0].index (src, dim[0], dest);
561  else
562  {
563  octave_idx_type nn = idx[lev].length (dim[lev]);
564  octave_idx_type d = cdim[lev];
565  for (octave_idx_type i = 0; i < nn; i++)
566  dest = do_index (src + d*idx[lev].xelem (i), dest, lev-1);
567  }
568 
569  return dest;
570  }
571 
572  // Recursive N-D indexed assignment
573  template <typename T>
574  const T * do_assign (const T *src, T *dest, int lev) const
575  {
576  if (lev == 0)
577  src += idx[0].assign (src, dim[0], dest);
578  else
579  {
580  octave_idx_type nn = idx[lev].length (dim[lev]);
581  octave_idx_type d = cdim[lev];
582  for (octave_idx_type i = 0; i < nn; i++)
583  src = do_assign (src, dest + d*idx[lev].xelem (i), lev-1);
584  }
585 
586  return src;
587  }
588 
589  // Recursive N-D indexed assignment
590  template <typename T>
591  void do_fill (const T& val, T *dest, int lev) const
592  {
593  if (lev == 0)
594  idx[0].fill (val, dim[0], dest);
595  else
596  {
597  octave_idx_type nn = idx[lev].length (dim[lev]);
598  octave_idx_type d = cdim[lev];
599  for (octave_idx_type i = 0; i < nn; i++)
600  do_fill (val, dest + d*idx[lev].xelem (i), lev-1);
601  }
602  }
603 
604 public:
605 
606  template <typename T>
607  void index (const T *src, T *dest) const { do_index (src, dest, top); }
608 
609  template <typename T>
610  void assign (const T *src, T *dest) const { do_assign (src, dest, top); }
611 
612  template <typename T>
613  void fill (const T& val, T *dest) const { do_fill (val, dest, top); }
614 
616  octave_idx_type& u) const
617  {
618  return top == 0 && idx[0].is_cont_range (dim[0], l, u);
619  }
620 };
621 
622 // Helper class for multi-d recursive resizing
623 // This handles resize () in an efficient manner, touching memory only
624 // once (apart from reinitialization)
626 {
630  int n;
631 
632 public:
633  rec_resize_helper (const dim_vector& ndv, const dim_vector& odv)
634  : cext (nullptr), sext (nullptr), dext (nullptr), n (0)
635  {
636  int l = ndv.ndims ();
637  assert (odv.ndims () == l);
638  octave_idx_type ld = 1;
639  int i = 0;
640  for (; i < l-1 && ndv(i) == odv(i); i++) ld *= ndv(i);
641  n = l - i;
642  cext = new octave_idx_type [3*n];
643  // Trick to avoid three allocations
644  sext = cext + n;
645  dext = sext + n;
646 
647  octave_idx_type sld = ld;
648  octave_idx_type dld = ld;
649  for (int j = 0; j < n; j++)
650  {
651  cext[j] = std::min (ndv(i+j), odv(i+j));
652  sext[j] = sld *= odv(i+j);
653  dext[j] = dld *= ndv(i+j);
654  }
655  cext[0] *= ld;
656  }
657 
658  // No copying!
659 
661 
663 
664  ~rec_resize_helper (void) { delete [] cext; }
665 
666 private:
667 
668  // recursive resizing
669  template <typename T>
670  void do_resize_fill (const T *src, T *dest, const T& rfv, int lev) const
671  {
672  if (lev == 0)
673  {
674  std::copy_n (src, cext[0], dest);
675  std::fill_n (dest + cext[0], dext[0] - cext[0], rfv);
676  }
677  else
678  {
679  octave_idx_type sd, dd, k;
680  sd = sext[lev-1];
681  dd = dext[lev-1];
682  for (k = 0; k < cext[lev]; k++)
683  do_resize_fill (src + k * sd, dest + k * dd, rfv, lev - 1);
684 
685  std::fill_n (dest + k * dd, dext[lev] - k * dd, rfv);
686  }
687  }
688 
689 public:
690 
691  template <typename T>
692  void resize_fill (const T *src, T *dest, const T& rfv) const
693  { do_resize_fill (src, dest, rfv, n-1); }
694 };
695 
696 template <typename T>
697 Array<T>
698 Array<T>::index (const idx_vector& i) const
699 {
700  // Colon:
701  //
702  // object | index | result orientation
703  // ---------+----------+-------------------
704  // anything | colon | column vector
705  //
706  // Numeric array or logical mask:
707  //
708  // Note that logical mask indices are always transformed to vectors
709  // before we see them.
710  //
711  // object | index | result orientation
712  // ---------+----------+-------------------
713  // vector | vector | indexed object
714  // | other | same size as index
715  // ---------+----------+-------------------
716  // array | anything | same size as index
717 
720 
721  if (i.is_colon ())
722  {
723  // A(:) produces a shallow copy as a column vector.
724  retval = Array<T> (*this, dim_vector (n, 1));
725  }
726  else
727  {
728  if (i.extent (n) != n)
729  octave::err_index_out_of_range (1, 1, i.extent (n), n, dimensions);
730 
731  dim_vector result_dims = i.orig_dimensions ();
732  octave_idx_type idx_len = i.length ();
733 
734  if (n != 1 && is_nd_vector () && idx_len != 1
735  && result_dims.is_nd_vector ())
736  {
737  // Indexed object and index are both vectors. Set result size
738  // and orientation as above.
739 
740  dim_vector dv = dims ();
741 
742  result_dims = dv.make_nd_vector (idx_len);
743  }
744 
745  octave_idx_type l, u;
746  if (idx_len != 0 && i.is_cont_range (n, l, u))
747  // If suitable, produce a shallow slice.
748  retval = Array<T> (*this, result_dims, l, u);
749  else
750  {
751  // Don't use resize here to avoid useless initialization for POD
752  // types.
753  retval = Array<T> (result_dims);
754 
755  if (idx_len != 0)
756  i.index (data (), n, retval.fortran_vec ());
757  }
758  }
759 
760  return retval;
761 }
762 
763 template <typename T>
764 Array<T>
765 Array<T>::index (const idx_vector& i, const idx_vector& j) const
766 {
767  // Get dimensions, allowing Fortran indexing in the 2nd dim.
768  dim_vector dv = dimensions.redim (2);
769  octave_idx_type r = dv(0);
770  octave_idx_type c = dv(1);
772 
773  if (i.is_colon () && j.is_colon ())
774  {
775  // A(:,:) produces a shallow copy.
776  retval = Array<T> (*this, dv);
777  }
778  else
779  {
780  if (i.extent (r) != r)
781  octave::err_index_out_of_range (2, 1, i.extent (r), r, dimensions); // throws
782  if (j.extent (c) != c)
783  octave::err_index_out_of_range (2, 2, j.extent (c), c, dimensions); // throws
784 
785  octave_idx_type n = numel ();
786  octave_idx_type il = i.length (r);
787  octave_idx_type jl = j.length (c);
788 
789  idx_vector ii (i);
790 
791  if (ii.maybe_reduce (r, j, c))
792  {
793  octave_idx_type l, u;
794  if (ii.length () > 0 && ii.is_cont_range (n, l, u))
795  // If suitable, produce a shallow slice.
796  retval = Array<T> (*this, dim_vector (il, jl), l, u);
797  else
798  {
799  // Don't use resize to avoid useless initialization for POD types.
800  retval = Array<T> (dim_vector (il, jl));
801 
802  ii.index (data (), n, retval.fortran_vec ());
803  }
804  }
805  else
806  {
807  // Don't use resize to avoid useless initialization for POD types.
808  retval = Array<T> (dim_vector (il, jl));
809 
810  const T *src = data ();
811  T *dest = retval.fortran_vec ();
812 
813  for (octave_idx_type k = 0; k < jl; k++)
814  dest += i.index (src + r * j.xelem (k), r, dest);
815  }
816  }
817 
818  return retval;
819 }
820 
821 template <typename T>
822 Array<T>
824 {
825  int ial = ia.numel ();
827 
828  // FIXME: is this dispatching necessary?
829  if (ial == 1)
830  retval = index (ia(0));
831  else if (ial == 2)
832  retval = index (ia(0), ia(1));
833  else if (ial > 0)
834  {
835  // Get dimensions, allowing Fortran indexing in the last dim.
836  dim_vector dv = dimensions.redim (ial);
837 
838  // Check for out of bounds conditions.
839  bool all_colons = true;
840  for (int i = 0; i < ial; i++)
841  {
842  if (ia(i).extent (dv(i)) != dv(i))
843  octave::err_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i),
844  dimensions); // throws
845 
846  all_colons = all_colons && ia(i).is_colon ();
847  }
848 
849  if (all_colons)
850  {
851  // A(:,:,...,:) produces a shallow copy.
853  retval = Array<T> (*this, dv);
854  }
855  else
856  {
857  // Form result dimensions.
858  dim_vector rdv = dim_vector::alloc (ial);
859  for (int i = 0; i < ial; i++) rdv(i) = ia(i).length (dv(i));
861 
862  // Prepare for recursive indexing
863  rec_index_helper rh (dv, ia);
864 
865  octave_idx_type l, u;
866  if (rh.is_cont_range (l, u))
867  // If suitable, produce a shallow slice.
868  retval = Array<T> (*this, rdv, l, u);
869  else
870  {
871  // Don't use resize to avoid useless initialization for POD types.
872  retval = Array<T> (rdv);
873 
874  // Do it.
875  rh.index (data (), retval.fortran_vec ());
876  }
877  }
878  }
879 
880  return retval;
881 }
882 
883 // The default fill value. Override if you want a different one.
884 
885 template <typename T>
886 T
888 {
889  static T zero = T ();
890  return zero;
891 }
892 
893 // Yes, we could do resize using index & assign. However, that would
894 // possibly involve a lot more memory traffic than we actually need.
895 
896 template <typename T>
897 void
899 {
900  if (n < 0 || ndims () != 2)
902 
903  dim_vector dv;
904  // This is driven by Matlab's behavior of giving a *row* vector
905  // on some out-of-bounds assignments. Specifically, Matlab
906  // allows a(i) with out-of-bouds i when a is either of 0x0, 1x0,
907  // 1x1, 0xN, and gives a row vector in all cases (yes, even the
908  // last one, search me why). Giving a column vector would make
909  // much more sense (given the way trailing singleton dims are
910  // treated).
911  bool invalid = false;
912  if (rows () == 0 || rows () == 1)
913  dv = dim_vector (1, n);
914  else if (columns () == 1)
915  dv = dim_vector (n, 1);
916  else
917  invalid = true;
918 
919  if (invalid)
921 
922  octave_idx_type nx = numel ();
923  if (n == nx - 1 && n > 0)
924  {
925  // Stack "pop" operation.
926  if (rep->count == 1)
927  slice_data[slice_len-1] = T ();
928  slice_len--;
929  dimensions = dv;
930  }
931  else if (n == nx + 1 && nx > 0)
932  {
933  // Stack "push" operation.
934  if (rep->count == 1
935  && slice_data + slice_len < rep->data + rep->len)
936  {
937  slice_data[slice_len++] = rfv;
938  dimensions = dv;
939  }
940  else
941  {
942  static const octave_idx_type max_stack_chunk = 1024;
943  octave_idx_type nn = n + std::min (nx, max_stack_chunk);
944  Array<T> tmp (Array<T> (dim_vector (nn, 1)), dv, 0, n);
945  T *dest = tmp.fortran_vec ();
946 
947  std::copy_n (data (), nx, dest);
948  dest[nx] = rfv;
949 
950  *this = tmp;
951  }
952  }
953  else if (n != nx)
954  {
955  Array<T> tmp = Array<T> (dv);
956  T *dest = tmp.fortran_vec ();
957 
958  octave_idx_type n0 = std::min (n, nx);
959  octave_idx_type n1 = n - n0;
960  std::copy_n (data (), n0, dest);
961  std::fill_n (dest + n0, n1, rfv);
962 
963  *this = tmp;
964  }
965 }
966 
967 template <typename T>
968 void
970 {
971  if (r < 0 || c < 0 || ndims () != 2)
973 
974  octave_idx_type rx = rows ();
975  octave_idx_type cx = columns ();
976  if (r != rx || c != cx)
977  {
978  Array<T> tmp = Array<T> (dim_vector (r, c));
979  T *dest = tmp.fortran_vec ();
980 
981  octave_idx_type r0 = std::min (r, rx);
982  octave_idx_type r1 = r - r0;
983  octave_idx_type c0 = std::min (c, cx);
984  octave_idx_type c1 = c - c0;
985  const T *src = data ();
986  if (r == rx)
987  {
988  std::copy_n (src, r * c0, dest);
989  dest += r * c0;
990  }
991  else
992  {
993  for (octave_idx_type k = 0; k < c0; k++)
994  {
995  std::copy_n (src, r0, dest);
996  src += rx;
997  dest += r0;
998  std::fill_n (dest, r1, rfv);
999  dest += r1;
1000  }
1001  }
1002 
1003  std::fill_n (dest, r * c1, rfv);
1004 
1005  *this = tmp;
1006  }
1007 }
1008 
1009 template <typename T>
1010 void
1011 Array<T>::resize (const dim_vector& dv, const T& rfv)
1012 {
1013  int dvl = dv.ndims ();
1014  if (dvl == 2)
1015  resize2 (dv(0), dv(1), rfv);
1016  else if (dimensions != dv)
1017  {
1018  if (dimensions.ndims () > dvl || dv.any_neg ())
1020 
1021  Array<T> tmp (dv);
1022  // Prepare for recursive resizing.
1023  rec_resize_helper rh (dv, dimensions.redim (dvl));
1024 
1025  // Do it.
1026  rh.resize_fill (data (), tmp.fortran_vec (), rfv);
1027  *this = tmp;
1028  }
1029 }
1030 
1031 template <typename T>
1032 Array<T>
1033 Array<T>::index (const idx_vector& i, bool resize_ok, const T& rfv) const
1034 {
1035  Array<T> tmp = *this;
1036  if (resize_ok)
1037  {
1038  octave_idx_type n = numel ();
1039  octave_idx_type nx = i.extent (n);
1040  if (n != nx)
1041  {
1042  if (i.is_scalar ())
1043  return Array<T> (dim_vector (1, 1), rfv);
1044  else
1045  tmp.resize1 (nx, rfv);
1046  }
1047 
1048  if (tmp.numel () != nx)
1049  return Array<T> ();
1050  }
1051 
1052  return tmp.index (i);
1053 }
1054 
1055 template <typename T>
1056 Array<T>
1058  bool resize_ok, const T& rfv) const
1059 {
1060  Array<T> tmp = *this;
1061  if (resize_ok)
1062  {
1063  dim_vector dv = dimensions.redim (2);
1064  octave_idx_type r = dv(0);
1065  octave_idx_type c = dv(1);
1066  octave_idx_type rx = i.extent (r);
1067  octave_idx_type cx = j.extent (c);
1068  if (r != rx || c != cx)
1069  {
1070  if (i.is_scalar () && j.is_scalar ())
1071  return Array<T> (dim_vector (1, 1), rfv);
1072  else
1073  tmp.resize2 (rx, cx, rfv);
1074  }
1075 
1076  if (tmp.rows () != rx || tmp.columns () != cx)
1077  return Array<T> ();
1078  }
1079 
1080  return tmp.index (i, j);
1081 }
1082 
1083 template <typename T>
1084 Array<T>
1086  bool resize_ok, const T& rfv) const
1087 {
1088  Array<T> tmp = *this;
1089  if (resize_ok)
1090  {
1091  int ial = ia.numel ();
1092  dim_vector dv = dimensions.redim (ial);
1093  dim_vector dvx = dim_vector::alloc (ial);
1094  for (int i = 0; i < ial; i++)
1095  dvx(i) = ia(i).extent (dv(i));
1096  if (! (dvx == dv))
1097  {
1098  bool all_scalars = true;
1099  for (int i = 0; i < ial; i++)
1100  all_scalars = all_scalars && ia(i).is_scalar ();
1101  if (all_scalars)
1102  return Array<T> (dim_vector (1, 1), rfv);
1103  else
1104  tmp.resize (dvx, rfv);
1105 
1106  if (tmp.dimensions != dvx)
1107  return Array<T> ();
1108  }
1109  }
1110 
1111  return tmp.index (ia);
1112 }
1113 
1114 template <typename T>
1115 void
1116 Array<T>::assign (const idx_vector& i, const Array<T>& rhs, const T& rfv)
1117 {
1118  octave_idx_type n = numel ();
1119  octave_idx_type rhl = rhs.numel ();
1120 
1121  if (rhl != 1 && i.length (n) != rhl)
1122  octave::err_nonconformant ("=", dim_vector(i.length(n),1), rhs.dims());
1123 
1124  octave_idx_type nx = i.extent (n);
1125  bool colon = i.is_colon_equiv (nx);
1126  // Try to resize first if necessary.
1127  if (nx != n)
1128  {
1129  // Optimize case A = []; A(1:n) = X with A empty.
1130  if (dimensions.zero_by_zero () && colon)
1131  {
1132  if (rhl == 1)
1133  *this = Array<T> (dim_vector (1, nx), rhs(0));
1134  else
1135  *this = Array<T> (rhs, dim_vector (1, nx));
1136  return;
1137  }
1138 
1139  resize1 (nx, rfv);
1140  n = numel ();
1141  }
1142 
1143  if (colon)
1144  {
1145  // A(:) = X makes a full fill or a shallow copy.
1146  if (rhl == 1)
1147  fill (rhs(0));
1148  else
1149  *this = rhs.reshape (dimensions);
1150  }
1151  else
1152  {
1153  if (rhl == 1)
1154  i.fill (rhs(0), n, fortran_vec ());
1155  else
1156  i.assign (rhs.data (), n, fortran_vec ());
1157  }
1158 }
1159 
1160 // Assignment to a 2-dimensional array
1161 template <typename T>
1162 void
1164  const Array<T>& rhs, const T& rfv)
1165 {
1166  bool initial_dims_all_zero = dimensions.all_zero ();
1167 
1168  // Get RHS extents, discarding singletons.
1169  dim_vector rhdv = rhs.dims ();
1170 
1171  // Get LHS extents, allowing Fortran indexing in the second dim.
1172  dim_vector dv = dimensions.redim (2);
1173 
1174  // Check for out-of-bounds and form resizing dimensions.
1175  dim_vector rdv;
1176 
1177  // In the special when all dimensions are zero, colons are allowed
1178  // to inquire the shape of RHS. The rules are more obscure, so we
1179  // solve that elsewhere.
1180  if (initial_dims_all_zero)
1181  rdv = zero_dims_inquire (i, j, rhdv);
1182  else
1183  {
1184  rdv(0) = i.extent (dv(0));
1185  rdv(1) = j.extent (dv(1));
1186  }
1187 
1188  bool isfill = rhs.numel () == 1;
1189  octave_idx_type il = i.length (rdv(0));
1190  octave_idx_type jl = j.length (rdv(1));
1191  rhdv.chop_all_singletons ();
1192  bool match = (isfill
1193  || (rhdv.ndims () == 2 && il == rhdv(0) && jl == rhdv(1)));
1194  match = match || (il == 1 && jl == rhdv(0) && rhdv(1) == 1);
1195 
1196  if (match)
1197  {
1198  bool all_colons = (i.is_colon_equiv (rdv(0))
1199  && j.is_colon_equiv (rdv(1)));
1200  // Resize if requested.
1201  if (rdv != dv)
1202  {
1203  // Optimize case A = []; A(1:m, 1:n) = X
1204  if (dv.zero_by_zero () && all_colons)
1205  {
1206  if (isfill)
1207  *this = Array<T> (rdv, rhs(0));
1208  else
1209  *this = Array<T> (rhs, rdv);
1210  return;
1211  }
1212 
1213  resize (rdv, rfv);
1214  dv = dimensions;
1215  }
1216 
1217  if (all_colons)
1218  {
1219  // A(:,:) = X makes a full fill or a shallow copy
1220  if (isfill)
1221  fill (rhs(0));
1222  else
1223  *this = rhs.reshape (dimensions);
1224  }
1225  else
1226  {
1227  // The actual work.
1228  octave_idx_type n = numel ();
1229  octave_idx_type r = dv(0);
1230  octave_idx_type c = dv(1);
1231  idx_vector ii (i);
1232 
1233  const T *src = rhs.data ();
1234  T *dest = fortran_vec ();
1235 
1236  // Try reduction first.
1237  if (ii.maybe_reduce (r, j, c))
1238  {
1239  if (isfill)
1240  ii.fill (*src, n, dest);
1241  else
1242  ii.assign (src, n, dest);
1243  }
1244  else
1245  {
1246  if (isfill)
1247  {
1248  for (octave_idx_type k = 0; k < jl; k++)
1249  i.fill (*src, r, dest + r * j.xelem (k));
1250  }
1251  else
1252  {
1253  for (octave_idx_type k = 0; k < jl; k++)
1254  src += i.assign (src, r, dest + r * j.xelem (k));
1255  }
1256  }
1257  }
1258  }
1259  // any empty RHS can be assigned to an empty LHS
1260  else if ((il != 0 && jl != 0) || (rhdv(0) != 0 && rhdv(1) != 0))
1261  octave::err_nonconformant ("=", il, jl, rhs.dim1 (), rhs.dim2 ());
1262 }
1263 
1264 // Assignment to a multi-dimensional array
1265 template <typename T>
1266 void
1268  const Array<T>& rhs, const T& rfv)
1269 {
1270  int ial = ia.numel ();
1271 
1272  // FIXME: is this dispatching necessary / desirable?
1273  if (ial == 1)
1274  assign (ia(0), rhs, rfv);
1275  else if (ial == 2)
1276  assign (ia(0), ia(1), rhs, rfv);
1277  else if (ial > 0)
1278  {
1279  bool initial_dims_all_zero = dimensions.all_zero ();
1280 
1281  // Get RHS extents, discarding singletons.
1282  dim_vector rhdv = rhs.dims ();
1283 
1284  // Get LHS extents, allowing Fortran indexing in the second dim.
1285  dim_vector dv = dimensions.redim (ial);
1286 
1287  // Get the extents forced by indexing.
1288  dim_vector rdv;
1289 
1290  // In the special when all dimensions are zero, colons are
1291  // allowed to inquire the shape of RHS. The rules are more
1292  // obscure, so we solve that elsewhere.
1293  if (initial_dims_all_zero)
1294  rdv = zero_dims_inquire (ia, rhdv);
1295  else
1296  {
1297  rdv = dim_vector::alloc (ial);
1298  for (int i = 0; i < ial; i++)
1299  rdv(i) = ia(i).extent (dv(i));
1300  }
1301 
1302  // Check whether LHS and RHS match, up to singleton dims.
1303  bool match = true;
1304  bool all_colons = true;
1305  bool isfill = rhs.numel () == 1;
1306 
1307  rhdv.chop_all_singletons ();
1308  int j = 0;
1309  int rhdvl = rhdv.ndims ();
1310  for (int i = 0; i < ial; i++)
1311  {
1312  all_colons = all_colons && ia(i).is_colon_equiv (rdv(i));
1313  octave_idx_type l = ia(i).length (rdv(i));
1314  if (l == 1) continue;
1315  match = match && j < rhdvl && l == rhdv(j++);
1316  }
1317 
1318  match = match && (j == rhdvl || rhdv(j) == 1);
1319  match = match || isfill;
1320 
1321  if (match)
1322  {
1323  // Resize first if necessary.
1324  if (rdv != dv)
1325  {
1326  // Optimize case A = []; A(1:m, 1:n) = X
1327  if (dv.zero_by_zero () && all_colons)
1328  {
1329  rdv.chop_trailing_singletons ();
1330  if (isfill)
1331  *this = Array<T> (rdv, rhs(0));
1332  else
1333  *this = Array<T> (rhs, rdv);
1334  return;
1335  }
1336 
1337  resize (rdv, rfv);
1338  dv = rdv;
1339  }
1340 
1341  if (all_colons)
1342  {
1343  // A(:,:,...,:) = X makes a full fill or a shallow copy.
1344  if (isfill)
1345  fill (rhs(0));
1346  else
1347  *this = rhs.reshape (dimensions);
1348  }
1349  else
1350  {
1351  // Do the actual work.
1352 
1353  // Prepare for recursive indexing
1354  rec_index_helper rh (dv, ia);
1355 
1356  // Do it.
1357  if (isfill)
1358  rh.fill (rhs(0), fortran_vec ());
1359  else
1360  rh.assign (rhs.data (), fortran_vec ());
1361  }
1362  }
1363  else
1364  {
1365  // dimension mismatch, unless LHS and RHS both empty
1366  bool lhsempty, rhsempty;
1367  lhsempty = rhsempty = false;
1368  for (int i = 0; i < ial; i++)
1369  {
1370  octave_idx_type l = ia(i).length (rdv(i));
1371  lhsempty = lhsempty || (l == 0);
1372  rhsempty = rhsempty || (rhdv(j++) == 0);
1373  }
1374  if (! lhsempty || ! rhsempty)
1375  octave::err_nonconformant ("=", dv, rhdv);
1376  }
1377  }
1378 }
1379 
1380 /*
1381 %!shared a
1382 %! a = [1 2; 3 4];
1383 %!error <op1 is 1x2, op2 is 1x3> a(1,:) = [1 2 3]
1384 %!error <op1 is 2x1, op2 is 1x3> a(:,1) = [1 2 3]
1385 %!error <op1 is 2x2, op2 is 2x1> a(1:2,2:3) = [1;2]
1386 */
1387 
1388 template <typename T>
1389 void
1391 {
1392  octave_idx_type n = numel ();
1393  if (i.is_colon ())
1394  {
1395  *this = Array<T> ();
1396  }
1397  else if (i.length (n) != 0)
1398  {
1399  if (i.extent (n) != n)
1401 
1402  octave_idx_type l, u;
1403  bool col_vec = ndims () == 2 && columns () == 1 && rows () != 1;
1404  if (i.is_scalar () && i(0) == n-1 && dimensions.isvector ())
1405  {
1406  // Stack "pop" operation.
1407  resize1 (n-1);
1408  }
1409  else if (i.is_cont_range (n, l, u))
1410  {
1411  // Special case deleting a contiguous range.
1412  octave_idx_type m = n + l - u;
1413  Array<T> tmp (dim_vector (col_vec ? m : 1, ! col_vec ? m : 1));
1414  const T *src = data ();
1415  T *dest = tmp.fortran_vec ();
1416  std::copy_n (src, l, dest);
1417  std::copy (src + u, src + n, dest + l);
1418  *this = tmp;
1419  }
1420  else
1421  {
1422  // Use index.
1423  *this = index (i.complement (n));
1424  }
1425  }
1426 }
1427 
1428 template <typename T>
1429 void
1431 {
1432  if (dim < 0 || dim >= ndims ())
1433  (*current_liboctave_error_handler) ("invalid dimension in delete_elements");
1434 
1435  octave_idx_type n = dimensions(dim);
1436  if (i.is_colon ())
1437  {
1438  *this = Array<T> ();
1439  }
1440  else if (i.length (n) != 0)
1441  {
1442  if (i.extent (n) != n)
1444 
1445  octave_idx_type l, u;
1446 
1447  if (i.is_cont_range (n, l, u))
1448  {
1449  // Special case deleting a contiguous range.
1450  octave_idx_type nd = n + l - u;
1451  octave_idx_type dl = 1;
1452  octave_idx_type du = 1;
1453  dim_vector rdv = dimensions;
1454  rdv(dim) = nd;
1455  for (int k = 0; k < dim; k++) dl *= dimensions(k);
1456  for (int k = dim + 1; k < ndims (); k++) du *= dimensions(k);
1457 
1458  // Special case deleting a contiguous range.
1459  Array<T> tmp = Array<T> (rdv);
1460  const T *src = data ();
1461  T *dest = tmp.fortran_vec ();
1462  l *= dl; u *= dl; n *= dl;
1463  for (octave_idx_type k = 0; k < du; k++)
1464  {
1465  std::copy_n (src, l, dest);
1466  dest += l;
1467  std::copy (src + u, src + n, dest);
1468  dest += n - u;
1469  src += n;
1470  }
1471 
1472  *this = tmp;
1473  }
1474  else
1475  {
1476  // Use index.
1477  Array<idx_vector> ia (dim_vector (ndims (), 1), idx_vector::colon);
1478  ia (dim) = i.complement (n);
1479  *this = index (ia);
1480  }
1481  }
1482 }
1483 
1484 template <typename T>
1485 void
1487 {
1488  int ial = ia.numel ();
1489 
1490  if (ial == 1)
1491  delete_elements (ia(0));
1492  else
1493  {
1494  int k, dim = -1;
1495  for (k = 0; k < ial; k++)
1496  {
1497  if (! ia(k).is_colon ())
1498  {
1499  if (dim < 0)
1500  dim = k;
1501  else
1502  break;
1503  }
1504  }
1505  if (dim < 0)
1506  {
1507  dim_vector dv = dimensions;
1508  dv(0) = 0;
1509  *this = Array<T> (dv);
1510  }
1511  else if (k == ial)
1512  {
1513  delete_elements (dim, ia(dim));
1514  }
1515  else
1516  {
1517  // Allow the null assignment to succeed if it won't change
1518  // anything because the indices reference an empty slice,
1519  // provided that there is at most one non-colon (or
1520  // equivalent) index. So, we still have the requirement of
1521  // deleting a slice, but it is OK if the slice is empty.
1522 
1523  // For compatibility with Matlab, stop checking once we see
1524  // more than one non-colon index or an empty index. Matlab
1525  // considers "[]" to be an empty index but not "false". We
1526  // accept both.
1527 
1528  bool empty_assignment = false;
1529 
1530  int num_non_colon_indices = 0;
1531 
1532  int nd = ndims ();
1533 
1534  for (int i = 0; i < ial; i++)
1535  {
1536  octave_idx_type dim_len = (i >= nd ? 1 : dimensions(i));
1537 
1538  if (ia(i).length (dim_len) == 0)
1539  {
1540  empty_assignment = true;
1541  break;
1542  }
1543 
1544  if (! ia(i).is_colon_equiv (dim_len))
1545  {
1546  num_non_colon_indices++;
1547 
1548  if (num_non_colon_indices == 2)
1549  break;
1550  }
1551  }
1552 
1553  if (! empty_assignment)
1554  (*current_liboctave_error_handler)
1555  ("a null assignment can only have one non-colon index");
1556  }
1557  }
1558 
1559 }
1560 
1561 template <typename T>
1562 Array<T>&
1564 {
1565  idx_vector i (r, r + a.rows ());
1566  idx_vector j (c, c + a.columns ());
1567  if (ndims () == 2 && a.ndims () == 2)
1568  assign (i, j, a);
1569  else
1570  {
1571  Array<idx_vector> idx (dim_vector (a.ndims (), 1));
1572  idx(0) = i;
1573  idx(1) = j;
1574  for (int k = 2; k < a.ndims (); k++)
1575  idx(k) = idx_vector (0, a.dimensions(k));
1576  assign (idx, a);
1577  }
1578 
1579  return *this;
1580 }
1581 
1582 template <typename T>
1583 Array<T>&
1585 {
1587  Array<idx_vector> idx (dim_vector (n, 1));
1588  const dim_vector dva = a.dims ().redim (n);
1589  for (octave_idx_type k = 0; k < n; k++)
1590  idx(k) = idx_vector (ra_idx(k), ra_idx(k) + dva(k));
1591 
1592  assign (idx, a);
1593 
1594  return *this;
1595 }
1596 
1597 template <typename T>
1598 Array<T>
1600 {
1601  assert (ndims () == 2);
1602 
1603  octave_idx_type nr = dim1 ();
1604  octave_idx_type nc = dim2 ();
1605 
1606  if (nr >= 8 && nc >= 8)
1607  {
1608  Array<T> result (dim_vector (nc, nr));
1609 
1610  // Reuse the implementation used for permuting.
1611 
1612  rec_permute_helper::blk_trans (data (), result.fortran_vec (), nr, nc);
1613 
1614  return result;
1615  }
1616  else if (nr > 1 && nc > 1)
1617  {
1618  Array<T> result (dim_vector (nc, nr));
1619 
1620  for (octave_idx_type j = 0; j < nc; j++)
1621  for (octave_idx_type i = 0; i < nr; i++)
1622  result.xelem (j, i) = xelem (i, j);
1623 
1624  return result;
1625  }
1626  else
1627  {
1628  // Fast transpose for vectors and empty matrices.
1629  return Array<T> (*this, dim_vector (nc, nr));
1630  }
1631 }
1632 
1633 template <typename T>
1634 static T
1635 no_op_fcn (const T& x)
1636 {
1637  return x;
1638 }
1639 
1640 template <typename T>
1641 Array<T>
1642 Array<T>::hermitian (T (*fcn) (const T&)) const
1643 {
1644  assert (ndims () == 2);
1645 
1646  if (! fcn)
1647  fcn = no_op_fcn<T>;
1648 
1649  octave_idx_type nr = dim1 ();
1650  octave_idx_type nc = dim2 ();
1651 
1652  if (nr >= 8 && nc >= 8)
1653  {
1654  Array<T> result (dim_vector (nc, nr));
1655 
1656  // Blocked transpose to attempt to avoid cache misses.
1657 
1658  T buf[64];
1659 
1660  octave_idx_type jj;
1661  for (jj = 0; jj < (nc - 8 + 1); jj += 8)
1662  {
1663  octave_idx_type ii;
1664  for (ii = 0; ii < (nr - 8 + 1); ii += 8)
1665  {
1666  // Copy to buffer
1667  for (octave_idx_type j = jj, k = 0, idxj = jj * nr;
1668  j < jj + 8; j++, idxj += nr)
1669  for (octave_idx_type i = ii; i < ii + 8; i++)
1670  buf[k++] = xelem (i + idxj);
1671 
1672  // Copy from buffer
1673  for (octave_idx_type i = ii, idxi = ii * nc; i < ii + 8;
1674  i++, idxi += nc)
1675  for (octave_idx_type j = jj, k = i - ii; j < jj + 8;
1676  j++, k+=8)
1677  result.xelem (j + idxi) = fcn (buf[k]);
1678  }
1679 
1680  if (ii < nr)
1681  for (octave_idx_type j = jj; j < jj + 8; j++)
1682  for (octave_idx_type i = ii; i < nr; i++)
1683  result.xelem (j, i) = fcn (xelem (i, j));
1684  }
1685 
1686  for (octave_idx_type j = jj; j < nc; j++)
1687  for (octave_idx_type i = 0; i < nr; i++)
1688  result.xelem (j, i) = fcn (xelem (i, j));
1689 
1690  return result;
1691  }
1692  else
1693  {
1694  Array<T> result (dim_vector (nc, nr));
1695 
1696  for (octave_idx_type j = 0; j < nc; j++)
1697  for (octave_idx_type i = 0; i < nr; i++)
1698  result.xelem (j, i) = fcn (xelem (i, j));
1699 
1700  return result;
1701  }
1702 }
1703 
1704 /*
1705 
1706 ## Transpose tests for matrices of the tile size and plus or minus a row
1707 ## and with four tiles.
1708 
1709 %!shared m7, mt7, m8, mt8, m9, mt9
1710 %! m7 = reshape (1 : 7*8, 8, 7);
1711 %! mt7 = [1:8; 9:16; 17:24; 25:32; 33:40; 41:48; 49:56];
1712 %! m8 = reshape (1 : 8*8, 8, 8);
1713 %! mt8 = mt8 = [mt7; 57:64];
1714 %! m9 = reshape (1 : 9*8, 8, 9);
1715 %! mt9 = [mt8; 65:72];
1716 
1717 %!assert (m7', mt7)
1718 %!assert ((1i*m7).', 1i * mt7)
1719 %!assert ((1i*m7)', conj (1i * mt7))
1720 %!assert (m8', mt8)
1721 %!assert ((1i*m8).', 1i * mt8)
1722 %!assert ((1i*m8)', conj (1i * mt8))
1723 %!assert (m9', mt9)
1724 %!assert ((1i*m9).', 1i * mt9)
1725 %!assert ((1i*m9)', conj (1i * mt9))
1726 %!assert ([m7, m8; m7, m8]', [mt7, mt7; mt8, mt8])
1727 %!assert ((1i*[m7, m8; m7, m8]).', 1i * [mt7, mt7; mt8, mt8])
1728 %!assert ((1i*[m7, m8; m7, m8])', conj (1i * [mt7, mt7; mt8, mt8]))
1729 %!assert ([m8, m8; m8, m8]', [mt8, mt8; mt8, mt8])
1730 %!assert ((1i*[m8, m8; m8, m8]).', 1i * [mt8, mt8; mt8, mt8])
1731 %!assert ((1i*[m8, m8; m8, m8])', conj (1i * [mt8, mt8; mt8, mt8]))
1732 %!assert ([m9, m8; m9, m8]', [mt9, mt9; mt8, mt8])
1733 %!assert ((1i*[m9, m8; m9, m8]).', 1i * [mt9, mt9; mt8, mt8])
1734 %!assert ((1i*[m9, m8; m9, m8])', conj (1i * [mt9, mt9; mt8, mt8]))
1735 
1736 */
1737 
1738 template <typename T>
1739 T *
1741 {
1742  make_unique ();
1743 
1744  return slice_data;
1745 }
1746 
1747 // Non-real types don't have NaNs.
1748 template <typename T>
1749 inline bool
1751 {
1752  return false;
1753 }
1754 
1755 template <typename T>
1756 Array<T>
1757 Array<T>::sort (int dim, sortmode mode) const
1758 {
1759  if (dim < 0)
1760  (*current_liboctave_error_handler) ("sort: invalid dimension");
1761 
1762  Array<T> m (dims ());
1763 
1764  dim_vector dv = m.dims ();
1765 
1766  if (m.numel () < 1)
1767  return m;
1768 
1769  if (dim >= dv.ndims ())
1770  dv.resize (dim+1, 1);
1771 
1772  octave_idx_type ns = dv(dim);
1773  octave_idx_type iter = dv.numel () / ns;
1774  octave_idx_type stride = 1;
1775 
1776  for (int i = 0; i < dim; i++)
1777  stride *= dv(i);
1778 
1779  T *v = m.fortran_vec ();
1780  const T *ov = data ();
1781 
1782  octave_sort<T> lsort;
1783 
1784  if (mode != UNSORTED)
1785  lsort.set_compare (mode);
1786  else
1787  return m;
1788 
1789  if (stride == 1)
1790  {
1791  for (octave_idx_type j = 0; j < iter; j++)
1792  {
1793  // copy and partition out NaNs.
1794  // FIXME: impact on integer types noticeable?
1795  octave_idx_type kl = 0;
1796  octave_idx_type ku = ns;
1797  for (octave_idx_type i = 0; i < ns; i++)
1798  {
1799  T tmp = ov[i];
1800  if (sort_isnan<T> (tmp))
1801  v[--ku] = tmp;
1802  else
1803  v[kl++] = tmp;
1804  }
1805 
1806  // sort.
1807  lsort.sort (v, kl);
1808 
1809  if (ku < ns)
1810  {
1811  // NaNs are in reverse order
1812  std::reverse (v + ku, v + ns);
1813  if (mode == DESCENDING)
1814  std::rotate (v, v + ku, v + ns);
1815  }
1816 
1817  v += ns;
1818  ov += ns;
1819  }
1820  }
1821  else
1822  {
1823  OCTAVE_LOCAL_BUFFER (T, buf, ns);
1824 
1825  for (octave_idx_type j = 0; j < iter; j++)
1826  {
1827  octave_idx_type offset = j;
1828  octave_idx_type offset2 = 0;
1829 
1830  while (offset >= stride)
1831  {
1832  offset -= stride;
1833  offset2++;
1834  }
1835 
1836  offset += offset2 * stride * ns;
1837 
1838  // gather and partition out NaNs.
1839  // FIXME: impact on integer types noticeable?
1840  octave_idx_type kl = 0;
1841  octave_idx_type ku = ns;
1842  for (octave_idx_type i = 0; i < ns; i++)
1843  {
1844  T tmp = ov[i*stride + offset];
1845  if (sort_isnan<T> (tmp))
1846  buf[--ku] = tmp;
1847  else
1848  buf[kl++] = tmp;
1849  }
1850 
1851  // sort.
1852  lsort.sort (buf, kl);
1853 
1854  if (ku < ns)
1855  {
1856  // NaNs are in reverse order
1857  std::reverse (buf + ku, buf + ns);
1858  if (mode == DESCENDING)
1859  std::rotate (buf, buf + ku, buf + ns);
1860  }
1861 
1862  // scatter.
1863  for (octave_idx_type i = 0; i < ns; i++)
1864  v[i*stride + offset] = buf[i];
1865  }
1866  }
1867 
1868  return m;
1869 }
1870 
1871 template <typename T>
1872 Array<T>
1874  sortmode mode) const
1875 {
1876  if (dim < 0 || dim >= ndims ())
1877  (*current_liboctave_error_handler) ("sort: invalid dimension");
1878 
1879  Array<T> m (dims ());
1880 
1881  dim_vector dv = m.dims ();
1882 
1883  if (m.numel () < 1)
1884  {
1885  sidx = Array<octave_idx_type> (dv);
1886  return m;
1887  }
1888 
1889  octave_idx_type ns = dv(dim);
1890  octave_idx_type iter = dv.numel () / ns;
1891  octave_idx_type stride = 1;
1892 
1893  for (int i = 0; i < dim; i++)
1894  stride *= dv(i);
1895 
1896  T *v = m.fortran_vec ();
1897  const T *ov = data ();
1898 
1899  octave_sort<T> lsort;
1900 
1901  sidx = Array<octave_idx_type> (dv);
1902  octave_idx_type *vi = sidx.fortran_vec ();
1903 
1904  if (mode != UNSORTED)
1905  lsort.set_compare (mode);
1906  else
1907  return m;
1908 
1909  if (stride == 1)
1910  {
1911  for (octave_idx_type j = 0; j < iter; j++)
1912  {
1913  // copy and partition out NaNs.
1914  // FIXME: impact on integer types noticeable?
1915  octave_idx_type kl = 0;
1916  octave_idx_type ku = ns;
1917  for (octave_idx_type i = 0; i < ns; i++)
1918  {
1919  T tmp = ov[i];
1920  if (sort_isnan<T> (tmp))
1921  {
1922  --ku;
1923  v[ku] = tmp;
1924  vi[ku] = i;
1925  }
1926  else
1927  {
1928  v[kl] = tmp;
1929  vi[kl] = i;
1930  kl++;
1931  }
1932  }
1933 
1934  // sort.
1935  lsort.sort (v, vi, kl);
1936 
1937  if (ku < ns)
1938  {
1939  // NaNs are in reverse order
1940  std::reverse (v + ku, v + ns);
1941  std::reverse (vi + ku, vi + ns);
1942  if (mode == DESCENDING)
1943  {
1944  std::rotate (v, v + ku, v + ns);
1945  std::rotate (vi, vi + ku, vi + ns);
1946  }
1947  }
1948 
1949  v += ns;
1950  vi += ns;
1951  ov += ns;
1952  }
1953  }
1954  else
1955  {
1956  OCTAVE_LOCAL_BUFFER (T, buf, ns);
1958 
1959  for (octave_idx_type j = 0; j < iter; j++)
1960  {
1961  octave_idx_type offset = j;
1962  octave_idx_type offset2 = 0;
1963 
1964  while (offset >= stride)
1965  {
1966  offset -= stride;
1967  offset2++;
1968  }
1969 
1970  offset += offset2 * stride * ns;
1971 
1972  // gather and partition out NaNs.
1973  // FIXME: impact on integer types noticeable?
1974  octave_idx_type kl = 0;
1975  octave_idx_type ku = ns;
1976  for (octave_idx_type i = 0; i < ns; i++)
1977  {
1978  T tmp = ov[i*stride + offset];
1979  if (sort_isnan<T> (tmp))
1980  {
1981  --ku;
1982  buf[ku] = tmp;
1983  bufi[ku] = i;
1984  }
1985  else
1986  {
1987  buf[kl] = tmp;
1988  bufi[kl] = i;
1989  kl++;
1990  }
1991  }
1992 
1993  // sort.
1994  lsort.sort (buf, bufi, kl);
1995 
1996  if (ku < ns)
1997  {
1998  // NaNs are in reverse order
1999  std::reverse (buf + ku, buf + ns);
2000  std::reverse (bufi + ku, bufi + ns);
2001  if (mode == DESCENDING)
2002  {
2003  std::rotate (buf, buf + ku, buf + ns);
2004  std::rotate (bufi, bufi + ku, bufi + ns);
2005  }
2006  }
2007 
2008  // scatter.
2009  for (octave_idx_type i = 0; i < ns; i++)
2010  v[i*stride + offset] = buf[i];
2011  for (octave_idx_type i = 0; i < ns; i++)
2012  vi[i*stride + offset] = bufi[i];
2013  }
2014  }
2015 
2016  return m;
2017 }
2018 
2019 template <typename T>
2021 safe_comparator (sortmode mode, const Array<T>& /* a */,
2022  bool /* allow_chk */)
2023 {
2024  if (mode == ASCENDING)
2026  else if (mode == DESCENDING)
2028  else
2029  return nullptr;
2030 }
2031 
2032 template <typename T>
2033 sortmode
2035 {
2036  octave_sort<T> lsort;
2037 
2038  octave_idx_type n = numel ();
2039 
2040  if (n <= 1)
2041  return (mode == UNSORTED) ? ASCENDING : mode;
2042 
2043  if (mode == UNSORTED)
2044  {
2045  // Auto-detect mode.
2046  compare_fcn_type compare
2047  = safe_comparator (ASCENDING, *this, false);
2048 
2049  if (compare (elem (n-1), elem (0)))
2050  mode = DESCENDING;
2051  else
2052  mode = ASCENDING;
2053  }
2054 
2055  lsort.set_compare (safe_comparator (mode, *this, false));
2056 
2057  if (! lsort.issorted (data (), n))
2058  mode = UNSORTED;
2059 
2060  return mode;
2061 
2062 }
2063 
2064 template <typename T>
2067 {
2069 
2070  octave_sort<T> lsort (safe_comparator (mode, *this, true));
2071 
2072  octave_idx_type r = rows ();
2073  octave_idx_type c = cols ();
2074 
2075  idx = Array<octave_idx_type> (dim_vector (r, 1));
2076 
2077  lsort.sort_rows (data (), idx.fortran_vec (), r, c);
2078 
2079  return idx;
2080 }
2081 
2082 template <typename T>
2083 sortmode
2085 {
2086  octave_sort<T> lsort;
2087 
2088  octave_idx_type r = rows ();
2089  octave_idx_type c = cols ();
2090 
2091  if (r <= 1 || c == 0)
2092  return (mode == UNSORTED) ? ASCENDING : mode;
2093 
2094  if (mode == UNSORTED)
2095  {
2096  // Auto-detect mode.
2097  compare_fcn_type compare
2098  = safe_comparator (ASCENDING, *this, false);
2099 
2100  octave_idx_type i;
2101  for (i = 0; i < cols (); i++)
2102  {
2103  T l = elem (0, i);
2104  T u = elem (rows () - 1, i);
2105  if (compare (l, u))
2106  {
2107  if (mode == DESCENDING)
2108  {
2109  mode = UNSORTED;
2110  break;
2111  }
2112  else
2113  mode = ASCENDING;
2114  }
2115  else if (compare (u, l))
2116  {
2117  if (mode == ASCENDING)
2118  {
2119  mode = UNSORTED;
2120  break;
2121  }
2122  else
2123  mode = DESCENDING;
2124  }
2125  }
2126  if (mode == UNSORTED && i == cols ())
2127  mode = ASCENDING;
2128  }
2129 
2130  if (mode != UNSORTED)
2131  {
2132  lsort.set_compare (safe_comparator (mode, *this, false));
2133 
2134  if (! lsort.is_sorted_rows (data (), r, c))
2135  mode = UNSORTED;
2136  }
2137 
2138  return mode;
2139 
2140 }
2141 
2142 // Do a binary lookup in a sorted array.
2143 template <typename T>
2145 Array<T>::lookup (const T& value, sortmode mode) const
2146 {
2147  octave_idx_type n = numel ();
2148  octave_sort<T> lsort;
2149 
2150  if (mode == UNSORTED)
2151  {
2152  // auto-detect mode
2153  if (n > 1 && lsort.descending_compare (elem (0), elem (n-1)))
2154  mode = DESCENDING;
2155  else
2156  mode = ASCENDING;
2157  }
2158 
2159  lsort.set_compare (mode);
2160 
2161  return lsort.lookup (data (), n, value);
2162 }
2163 
2164 template <typename T>
2166 Array<T>::lookup (const Array<T>& values, sortmode mode) const
2167 {
2168  octave_idx_type n = numel ();
2169  octave_idx_type nval = values.numel ();
2170  octave_sort<T> lsort;
2171  Array<octave_idx_type> idx (values.dims ());
2172 
2173  if (mode == UNSORTED)
2174  {
2175  // auto-detect mode
2176  if (n > 1 && lsort.descending_compare (elem (0), elem (n-1)))
2177  mode = DESCENDING;
2178  else
2179  mode = ASCENDING;
2180  }
2181 
2182  lsort.set_compare (mode);
2183 
2184  // This determines the split ratio between the O(M*log2(N)) and O(M+N)
2185  // algorithms.
2186  static const double ratio = 1.0;
2187  sortmode vmode = UNSORTED;
2188 
2189  // Attempt the O(M+N) algorithm if M is large enough.
2190  if (nval > ratio * n / octave::math::log2 (n + 1.0))
2191  {
2192  vmode = values.issorted ();
2193  // The table must not contain a NaN.
2194  if ((vmode == ASCENDING && sort_isnan<T> (values(nval-1)))
2195  || (vmode == DESCENDING && sort_isnan<T> (values(0))))
2196  vmode = UNSORTED;
2197  }
2198 
2199  if (vmode != UNSORTED)
2200  lsort.lookup_sorted (data (), n, values.data (), nval,
2201  idx.fortran_vec (), vmode != mode);
2202  else
2203  lsort.lookup (data (), n, values.data (), nval, idx.fortran_vec ());
2204 
2205  return idx;
2206 }
2207 
2208 template <typename T>
2210 Array<T>::nnz (void) const
2211 {
2212  const T *src = data ();
2213  octave_idx_type nel = numel ();
2214  octave_idx_type retval = 0;
2215  const T zero = T ();
2216  for (octave_idx_type i = 0; i < nel; i++)
2217  if (src[i] != zero)
2218  retval++;
2219 
2220  return retval;
2221 }
2222 
2223 template <typename T>
2225 Array<T>::find (octave_idx_type n, bool backward) const
2226 {
2228  const T *src = data ();
2229  octave_idx_type nel = numel ();
2230  const T zero = T ();
2231  if (n < 0 || n >= nel)
2232  {
2233  // We want all elements, which means we'll almost surely need
2234  // to resize. So count first, then allocate array of exact size.
2235  octave_idx_type cnt = 0;
2236  for (octave_idx_type i = 0; i < nel; i++)
2237  cnt += src[i] != zero;
2238 
2239  retval.clear (cnt, 1);
2240  octave_idx_type *dest = retval.fortran_vec ();
2241  for (octave_idx_type i = 0; i < nel; i++)
2242  if (src[i] != zero) *dest++ = i;
2243  }
2244  else
2245  {
2246  // We want a fixed max number of elements, usually small. So be
2247  // optimistic, alloc the array in advance, and then resize if
2248  // needed.
2249  retval.clear (n, 1);
2250  if (backward)
2251  {
2252  // Do the search as a series of successive single-element searches.
2253  octave_idx_type k = 0;
2254  octave_idx_type l = nel - 1;
2255  for (; k < n; k++)
2256  {
2257  for (; l >= 0 && src[l] == zero; l--) ;
2258  if (l >= 0)
2259  retval(k) = l--;
2260  else
2261  break;
2262  }
2263  if (k < n)
2264  retval.resize2 (k, 1);
2265  octave_idx_type *rdata = retval.fortran_vec ();
2266  std::reverse (rdata, rdata + k);
2267  }
2268  else
2269  {
2270  // Do the search as a series of successive single-element searches.
2271  octave_idx_type k = 0;
2272  octave_idx_type l = 0;
2273  for (; k < n; k++)
2274  {
2275  for (; l != nel && src[l] == zero; l++) ;
2276  if (l != nel)
2277  retval(k) = l++;
2278  else
2279  break;
2280  }
2281  if (k < n)
2282  retval.resize2 (k, 1);
2283  }
2284  }
2285 
2286  // Fixup return dimensions, for Matlab compatibility.
2287  // find (zeros (0,0)) -> zeros (0,0)
2288  // find (zeros (1,0)) -> zeros (1,0)
2289  // find (zeros (0,1)) -> zeros (0,1)
2290  // find (zeros (0,X)) -> zeros (0,1)
2291  // find (zeros (1,1)) -> zeros (0,0) !!!! WHY?
2292  // find (zeros (0,1,0)) -> zeros (0,0)
2293  // find (zeros (0,1,0,1)) -> zeros (0,0) etc
2294 
2295  if ((numel () == 1 && retval.isempty ())
2296  || (rows () == 0 && dims ().numel (1) == 0))
2298  else if (rows () == 1 && ndims () == 2)
2300 
2301  return retval;
2302 }
2303 
2304 template <typename T>
2305 Array<T>
2306 Array<T>::nth_element (const idx_vector& n, int dim) const
2307 {
2308  if (dim < 0)
2309  (*current_liboctave_error_handler) ("nth_element: invalid dimension");
2310 
2311  dim_vector dv = dims ();
2312  if (dim >= dv.ndims ())
2313  dv.resize (dim+1, 1);
2314 
2315  octave_idx_type ns = dv(dim);
2316 
2317  octave_idx_type nn = n.length (ns);
2318 
2319  dv(dim) = std::min (nn, ns);
2320  dv.chop_trailing_singletons ();
2321  dim = std::min (dv.ndims (), static_cast<octave_idx_type> (dim));
2322 
2323  Array<T> m (dv);
2324 
2325  if (m.isempty ())
2326  return m;
2327 
2328  sortmode mode = UNSORTED;
2329  octave_idx_type lo = 0;
2330 
2331  switch (n.idx_class ())
2332  {
2334  mode = ASCENDING;
2335  lo = n(0);
2336  break;
2338  {
2339  octave_idx_type inc = n.increment ();
2340  if (inc == 1)
2341  {
2342  mode = ASCENDING;
2343  lo = n(0);
2344  }
2345  else if (inc == -1)
2346  {
2347  mode = DESCENDING;
2348  lo = ns - 1 - n(0);
2349  }
2350  }
2351  break;
2353  // This case resolves bug #51329, a fallback to allow the given index
2354  // to be a sequential vector instead of the typical scalar or range
2355  if (n(1) - n(0) == 1)
2356  {
2357  mode = ASCENDING;
2358  lo = n(0);
2359  }
2360  else if (n(1) - n(0) == -1)
2361  {
2362  mode = DESCENDING;
2363  lo = ns - 1 - n(0);
2364  }
2365  // Ensure that the vector is actually an arithmetic contiguous sequence
2366  for (octave_idx_type i = 2; i < n.length () && mode != UNSORTED; i++)
2367  if ((mode == ASCENDING && n(i) - n(i-1) != 1)
2368  || (mode == DESCENDING && n(i) - n(i-1) != -1))
2369  mode = UNSORTED;
2370  break;
2371  default:
2372  break;
2373  }
2374 
2375  if (mode == UNSORTED)
2376  (*current_liboctave_error_handler)
2377  ("nth_element: n must be a scalar or a contiguous range");
2378 
2379  octave_idx_type up = lo + nn;
2380 
2381  if (lo < 0 || up > ns)
2382  (*current_liboctave_error_handler) ("nth_element: invalid element index");
2383 
2384  octave_idx_type iter = numel () / ns;
2385  octave_idx_type stride = 1;
2386 
2387  for (int i = 0; i < dim; i++)
2388  stride *= dv(i);
2389 
2390  T *v = m.fortran_vec ();
2391  const T *ov = data ();
2392 
2393  OCTAVE_LOCAL_BUFFER (T, buf, ns);
2394 
2395  octave_sort<T> lsort;
2396  lsort.set_compare (mode);
2397 
2398  for (octave_idx_type j = 0; j < iter; j++)
2399  {
2400  octave_idx_type kl = 0;
2401  octave_idx_type ku = ns;
2402 
2403  if (stride == 1)
2404  {
2405  // copy without NaNs.
2406  // FIXME: impact on integer types noticeable?
2407  for (octave_idx_type i = 0; i < ns; i++)
2408  {
2409  T tmp = ov[i];
2410  if (sort_isnan<T> (tmp))
2411  buf[--ku] = tmp;
2412  else
2413  buf[kl++] = tmp;
2414  }
2415 
2416  ov += ns;
2417  }
2418  else
2419  {
2420  octave_idx_type offset = j % stride;
2421  // copy without NaNs.
2422  // FIXME: impact on integer types noticeable?
2423  for (octave_idx_type i = 0; i < ns; i++)
2424  {
2425  T tmp = ov[offset + i*stride];
2426  if (sort_isnan<T> (tmp))
2427  buf[--ku] = tmp;
2428  else
2429  buf[kl++] = tmp;
2430  }
2431 
2432  if (offset == stride-1)
2433  ov += ns*stride;
2434  }
2435 
2436  if (ku == ns)
2437  lsort.nth_element (buf, ns, lo, up);
2438  else if (mode == ASCENDING)
2439  lsort.nth_element (buf, ku, lo, std::min (ku, up));
2440  else
2441  {
2442  octave_idx_type nnan = ns - ku;
2443  octave_idx_type zero = 0;
2444  lsort.nth_element (buf, ku, std::max (lo - nnan, zero),
2445  std::max (up - nnan, zero));
2446  std::rotate (buf, buf + ku, buf + ns);
2447  }
2448 
2449  if (stride == 1)
2450  {
2451  for (octave_idx_type i = 0; i < nn; i++)
2452  v[i] = buf[lo + i];
2453 
2454  v += nn;
2455  }
2456  else
2457  {
2458  octave_idx_type offset = j % stride;
2459  for (octave_idx_type i = 0; i < nn; i++)
2460  v[offset + stride * i] = buf[lo + i];
2461  if (offset == stride-1)
2462  v += nn*stride;
2463  }
2464  }
2465 
2466  return m;
2467 }
2468 
2469 #define NO_INSTANTIATE_ARRAY_SORT(T) \
2470  template <> Array<T> \
2471  Array<T>::sort (int, sortmode) const \
2472  { \
2473  return *this; \
2474  } \
2475  template <> Array<T> \
2476  Array<T>::sort (Array<octave_idx_type> &sidx, int, sortmode) const \
2477  { \
2478  sidx = Array<octave_idx_type> (); \
2479  return *this; \
2480  } \
2481  template <> sortmode \
2482  Array<T>::issorted (sortmode) const \
2483  { \
2484  return UNSORTED; \
2485  } \
2486  Array<T>::compare_fcn_type \
2487  safe_comparator (sortmode, const Array<T>&, bool) \
2488  { \
2489  return nullptr; \
2490  } \
2491  template <> Array<octave_idx_type> \
2492  Array<T>::sort_rows_idx (sortmode) const \
2493  { \
2494  return Array<octave_idx_type> (); \
2495  } \
2496  template <> sortmode \
2497  Array<T>::is_sorted_rows (sortmode) const \
2498  { \
2499  return UNSORTED; \
2500  } \
2501  template <> octave_idx_type \
2502  Array<T>::lookup (T const &, sortmode) const \
2503  { \
2504  return 0; \
2505  } \
2506  template <> Array<octave_idx_type> \
2507  Array<T>::lookup (const Array<T>&, sortmode) const \
2508  { \
2509  return Array<octave_idx_type> (); \
2510  } \
2511  template <> octave_idx_type \
2512  Array<T>::nnz (void) const \
2513  { \
2514  return 0; \
2515  } \
2516  template <> Array<octave_idx_type> \
2517  Array<T>::find (octave_idx_type, bool) const \
2518  { \
2519  return Array<octave_idx_type> (); \
2520  } \
2521  template <> Array<T> \
2522  Array<T>::nth_element (const idx_vector&, int) const { \
2523  return Array<T> (); \
2524  }
2525 
2526 template <typename T>
2527 Array<T>
2529 {
2530  dim_vector dv = dims ();
2531  octave_idx_type nd = dv.ndims ();
2532  Array<T> d;
2533 
2534  if (nd > 2)
2535  (*current_liboctave_error_handler) ("Matrix must be 2-dimensional");
2536 
2537  octave_idx_type nnr = dv(0);
2538  octave_idx_type nnc = dv(1);
2539 
2540  if (nnr == 0 && nnc == 0)
2541  ; // do nothing for empty matrix
2542  else if (nnr != 1 && nnc != 1)
2543  {
2544  // Extract diag from matrix
2545  if (k > 0)
2546  nnc -= k;
2547  else if (k < 0)
2548  nnr += k;
2549 
2550  if (nnr > 0 && nnc > 0)
2551  {
2552  octave_idx_type ndiag = (nnr < nnc) ? nnr : nnc;
2553 
2554  d.resize (dim_vector (ndiag, 1));
2555 
2556  if (k > 0)
2557  {
2558  for (octave_idx_type i = 0; i < ndiag; i++)
2559  d.xelem (i) = elem (i, i+k);
2560  }
2561  else if (k < 0)
2562  {
2563  for (octave_idx_type i = 0; i < ndiag; i++)
2564  d.xelem (i) = elem (i-k, i);
2565  }
2566  else
2567  {
2568  for (octave_idx_type i = 0; i < ndiag; i++)
2569  d.xelem (i) = elem (i, i);
2570  }
2571  }
2572  else // Matlab returns [] 0x1 for out-of-range diagonal
2573  d.resize (dim_vector (0, 1));
2574  }
2575  else
2576  {
2577  // Create diag matrix from vector
2578  octave_idx_type roff = 0;
2579  octave_idx_type coff = 0;
2580  if (k > 0)
2581  {
2582  roff = 0;
2583  coff = k;
2584  }
2585  else if (k < 0)
2586  {
2587  roff = -k;
2588  coff = 0;
2589  }
2590 
2591  if (nnr == 1)
2592  {
2593  octave_idx_type n = nnc + std::abs (k);
2594  d = Array<T> (dim_vector (n, n), resize_fill_value ());
2595 
2596  for (octave_idx_type i = 0; i < nnc; i++)
2597  d.xelem (i+roff, i+coff) = elem (0, i);
2598  }
2599  else
2600  {
2601  octave_idx_type n = nnr + std::abs (k);
2602  d = Array<T> (dim_vector (n, n), resize_fill_value ());
2603 
2604  for (octave_idx_type i = 0; i < nnr; i++)
2605  d.xelem (i+roff, i+coff) = elem (i, 0);
2606  }
2607  }
2608 
2609  return d;
2610 }
2611 
2612 template <typename T>
2613 Array<T>
2615 {
2616  if (ndims () != 2 || (rows () != 1 && cols () != 1))
2617  (*current_liboctave_error_handler) ("cat: invalid dimension");
2618 
2619  Array<T> retval (dim_vector (m, n), resize_fill_value ());
2620 
2621  octave_idx_type nel = std::min (numel (), std::min (m, n));
2622  for (octave_idx_type i = 0; i < nel; i++)
2623  retval.xelem (i, i) = xelem (i);
2624 
2625  return retval;
2626 }
2627 
2628 template <typename T>
2629 Array<T>
2630 Array<T>::cat (int dim, octave_idx_type n, const Array<T> *array_list)
2631 {
2632  // Default concatenation.
2633  bool (dim_vector::*concat_rule) (const dim_vector&, int) = &dim_vector::concat;
2634 
2635  if (dim == -1 || dim == -2)
2636  {
2637  concat_rule = &dim_vector::hvcat;
2638  dim = -dim - 1;
2639  }
2640  else if (dim < 0)
2641  (*current_liboctave_error_handler) ("cat: invalid dimension");
2642 
2643  if (n == 1)
2644  return array_list[0];
2645  else if (n == 0)
2646  return Array<T> ();
2647 
2648  // Special case:
2649  //
2650  // cat (dim, [], ..., [], A, ...)
2651  //
2652  // with dim > 2, A not 0x0, and at least three arguments to
2653  // concatenate is equivalent to
2654  //
2655  // cat (dim, A, ...)
2656  //
2657  // Note that this check must be performed here because for full-on
2658  // braindead Matlab compatibility, we need to have things like
2659  //
2660  // cat (3, [], [], A)
2661  //
2662  // succeed, but to have things like
2663  //
2664  // cat (3, cat (3, [], []), A)
2665  // cat (3, zeros (0, 0, 2), A)
2666  //
2667  // fail. See also bug report #31615.
2668 
2669  octave_idx_type istart = 0;
2670 
2671  if (n > 2 && dim > 1)
2672  {
2673  for (octave_idx_type i = 0; i < n; i++)
2674  {
2675  dim_vector dv = array_list[i].dims ();
2676 
2677  if (dv.zero_by_zero ())
2678  istart++;
2679  else
2680  break;
2681  }
2682 
2683  // Don't skip any initial arguments if they are all empty.
2684  if (istart >= n)
2685  istart = 0;
2686  }
2687 
2688  dim_vector dv = array_list[istart++].dims ();
2689 
2690  for (octave_idx_type i = istart; i < n; i++)
2691  if (! (dv.*concat_rule) (array_list[i].dims (), dim))
2692  (*current_liboctave_error_handler) ("cat: dimension mismatch");
2693 
2694  Array<T> retval (dv);
2695 
2696  if (retval.isempty ())
2697  return retval;
2698 
2699  int nidx = std::max (dv.ndims (), static_cast<octave_idx_type> (dim + 1));
2701  octave_idx_type l = 0;
2702 
2703  for (octave_idx_type i = 0; i < n; i++)
2704  {
2705  // NOTE: This takes some thinking, but no matter what the above rules
2706  // are, an empty array can always be skipped at this point, because
2707  // the result dimensions are already determined, and there is no way
2708  // an empty array may contribute a nonzero piece along the dimension
2709  // at this point, unless an empty array can be promoted to a non-empty
2710  // one (which makes no sense). I repeat, *no way*, think about it.
2711  if (array_list[i].isempty ())
2712  continue;
2713 
2714  octave_quit ();
2715 
2716  octave_idx_type u;
2717  if (dim < array_list[i].ndims ())
2718  u = l + array_list[i].dims ()(dim);
2719  else
2720  u = l + 1;
2721 
2722  idxa(dim) = idx_vector (l, u);
2723 
2724  retval.assign (idxa, array_list[i]);
2725 
2726  l = u;
2727  }
2728 
2729  return retval;
2730 }
2731 
2732 template <typename T>
2733 void
2734 Array<T>::print_info (std::ostream& os, const std::string& prefix) const
2735 {
2736  os << prefix << "rep address: " << rep << '\n'
2737  << prefix << "rep->len: " << rep->len << '\n'
2738  << prefix << "rep->data: " << static_cast<void *> (rep->data) << '\n'
2739  << prefix << "rep->count: " << rep->count << '\n'
2740  << prefix << "slice_data: " << static_cast<void *> (slice_data) << '\n'
2741  << prefix << "slice_len: " << slice_len << '\n';
2742 
2743  // 2D info:
2744  //
2745  // << pefix << "rows: " << rows () << "\n"
2746  // << prefix << "cols: " << cols () << "\n";
2747 }
2748 
2749 template <typename T>
2751 {
2752  bool retval = dimensions == dv;
2753  if (retval)
2754  dimensions = dv;
2755 
2756  return retval;
2757 }
2758 
2759 template <typename T>
2761 {
2762  // This guards against accidental implicit instantiations.
2763  // Array<T> instances should always be explicit and use INSTANTIATE_ARRAY.
2764  T::__xXxXx__ ();
2765 }
2766 
2767 #define INSTANTIATE_ARRAY(T, API) \
2768  template <> void Array<T>::instantiation_guard () { } \
2769  template class API Array<T>
2770 
2771 // FIXME: is this used?
2772 
2773 template <typename T>
2774 std::ostream&
2775 operator << (std::ostream& os, const Array<T>& a)
2776 {
2777  dim_vector a_dims = a.dims ();
2778 
2779  int n_dims = a_dims.ndims ();
2780 
2781  os << n_dims << "-dimensional array";
2782 
2783  if (n_dims)
2784  os << " (" << a_dims.str () << ')';
2785 
2786  os <<"\n\n";
2787 
2788  if (n_dims)
2789  {
2790  os << "data:";
2791 
2792  Array<octave_idx_type> ra_idx (dim_vector (n_dims, 1), 0);
2793 
2794  // Number of times the first 2d-array is to be displayed.
2795 
2796  octave_idx_type m = 1;
2797  for (int i = 2; i < n_dims; i++)
2798  m *= a_dims(i);
2799 
2800  if (m == 1)
2801  {
2802  octave_idx_type rows = 0;
2803  octave_idx_type cols = 0;
2804 
2805  switch (n_dims)
2806  {
2807  case 2:
2808  rows = a_dims(0);
2809  cols = a_dims(1);
2810 
2811  for (octave_idx_type j = 0; j < rows; j++)
2812  {
2813  ra_idx(0) = j;
2814  for (octave_idx_type k = 0; k < cols; k++)
2815  {
2816  ra_idx(1) = k;
2817  os << ' ' << a.elem (ra_idx);
2818  }
2819  os << "\n";
2820  }
2821  break;
2822 
2823  default:
2824  rows = a_dims(0);
2825 
2826  for (octave_idx_type k = 0; k < rows; k++)
2827  {
2828  ra_idx(0) = k;
2829  os << ' ' << a.elem (ra_idx);
2830  }
2831  break;
2832  }
2833 
2834  os << "\n";
2835  }
2836  else
2837  {
2838  octave_idx_type rows = a_dims(0);
2839  octave_idx_type cols = a_dims(1);
2840 
2841  for (int i = 0; i < m; i++)
2842  {
2843  os << "\n(:,:,";
2844 
2845  for (int j = 2; j < n_dims - 1; j++)
2846  os << ra_idx(j) + 1 << ',';
2847 
2848  os << ra_idx(n_dims - 1) + 1 << ") = \n";
2849 
2850  for (octave_idx_type j = 0; j < rows; j++)
2851  {
2852  ra_idx(0) = j;
2853 
2854  for (octave_idx_type k = 0; k < cols; k++)
2855  {
2856  ra_idx(1) = k;
2857  os << ' ' << a.elem (ra_idx);
2858  }
2859 
2860  os << "\n";
2861  }
2862 
2863  os << "\n";
2864 
2865  if (i != m - 1)
2866  increment_index (ra_idx, a_dims, 2);
2867  }
2868  }
2869  }
2870 
2871  return os;
2872 }
template class OCTAVE_API Array< octave_idx_type >
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:177
dim_vector zero_dims_inquire(const Array< idx_vector > &ia, const dim_vector &rhdv)
Definition: Array-util.cc:429
void increment_index(Array< octave_idx_type > &ra_idx, const dim_vector &dimensions, int start_dimension)
Definition: Array-util.cc:60
std::ostream & operator<<(std::ostream &os, const Array< T > &a)
Definition: Array.cc:2775
Array< T >::compare_fcn_type safe_comparator(sortmode mode, const Array< T > &, bool)
Definition: Array.cc:2021
bool sort_isnan(typename ref_param< T >::type)
Definition: Array.cc:1750
static T no_op_fcn(const T &x)
Definition: Array.cc:1635
static F77_INT nn
Definition: DASPK.cc:66
static int elem
Definition: __contourc__.cc:52
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
The real representation of all arrays.
Definition: Array.h:133
octave::refcount< octave_idx_type > count
Definition: Array.h:138
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:128
static Array< T >::ArrayRep * nil_rep(void)
Definition: Array.cc:42
octave_idx_type nnz(void) const
Count nonzero elements.
Definition: Array.cc:2210
Array< T >::ArrayRep * rep
Definition: Array.h:219
Array< octave_idx_type > sort_rows_idx(sortmode mode=ASCENDING) const
Sort by rows returns only indices.
Definition: Array.cc:2066
Array< T > page(octave_idx_type k) const
Extract page: A(:,:,k+1).
Definition: Array.cc:270
Array< T > & insert(const Array< T > &a, const Array< octave_idx_type > &idx)
Insert an array into another at a specified position.
Definition: Array.cc:1584
void resize1(octave_idx_type n, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:898
static void instantiation_guard()
Size of the specified dimension.
Definition: Array.cc:2760
Array< T > sort(int dim=0, sortmode mode=ASCENDING) const
Size of the specified dimension.
Definition: Array.cc:1757
virtual T resize_fill_value(void) const
Size of the specified dimension.
Definition: Array.cc:887
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
sortmode issorted(sortmode mode=UNSORTED) const
Ordering is auto-detected or can be specified.
Definition: Array.cc:2034
Array< T > squeeze(void) const
Chop off leading singleton dimensions.
Definition: Array.cc:117
void assign(const idx_vector &i, const Array< T > &rhs, const T &rfv)
Indexed assignment (always with resize & fill).
Definition: Array.cc:1116
octave_idx_type columns(void) const
Definition: Array.h:424
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
Array< T > nth_element(const idx_vector &n, int dim=0) const
Returns the n-th element in increasing order, using the same ordering as used for sort.
Definition: Array.cc:2306
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
Array< octave_idx_type > find(octave_idx_type n=-1, bool backward=false) const
Find indices of (at most n) nonzero elements.
Definition: Array.cc:2225
dim_vector dimensions
Definition: Array.h:217
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:499
void fill(const T &val)
Definition: Array.cc:73
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:581
octave_idx_type lookup(const T &value, sortmode mode=UNSORTED) const
Do a binary lookup in a sorted array.
Definition: Array.cc:2145
T & checkelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.cc:192
octave_idx_type rows(void) const
Definition: Array.h:415
Array< T > hermitian(T(*fcn)(const T &)=nullptr) const
Size of the specified dimension.
Definition: Array.cc:1642
void resize2(octave_idx_type nr, octave_idx_type nc, const T &rfv)
Resizing (with fill).
Definition: Array.cc:969
friend class Array
Size of the specified dimension.
Definition: Array.h:833
Array< T > column(octave_idx_type k) const
Extract column: A(:,k+1).
Definition: Array.cc:261
sortmode is_sorted_rows(sortmode mode=UNSORTED) const
Ordering is auto-detected or can be specified.
Definition: Array.cc:2084
ref_param< T >::type crefT
Definition: Array.h:210
Array< T > index(const idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:698
Array< T > reshape(octave_idx_type nr, octave_idx_type nc) const
Size of the specified dimension.
Definition: Array.h:560
void clear(void)
Definition: Array.cc:87
Array< T > diag(octave_idx_type k=0) const
Get the kth super or subdiagonal.
Definition: Array.cc:2528
Array< T > transpose(void) const
Size of the specified dimension.
Definition: Array.cc:1599
octave_idx_type dim2(void) const
Definition: Array.h:422
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
int ndims(void) const
Size of the specified dimension.
Definition: Array.h:589
octave_idx_type compute_index(octave_idx_type i, octave_idx_type j) const
Size of the specified dimension.
Definition: Array.cc:170
void print_info(std::ostream &os, const std::string &prefix) const
Size of the specified dimension.
Definition: Array.cc:2734
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
static Array< T > cat(int dim, octave_idx_type n, const Array< T > *array_list)
Concatenation along a specified (0-based) dimension, equivalent to cat().
Definition: Array.cc:2630
Array< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Size of the specified dimension.
Definition: Array.cc:431
bool optimize_dimensions(const dim_vector &dv)
Returns true if this->dims () == dv, and if so, replaces this->dimensions by a shallow copy of dv.
Definition: Array.cc:2750
Array< T > linear_slice(octave_idx_type lo, octave_idx_type up) const
Extract a slice from this array as a column vector: A(:)(lo+1:up).
Definition: Array.cc:281
octave_idx_type dim1(void) const
Definition: Array.h:414
void delete_elements(const idx_vector &i)
Deleting elements.
Definition: Array.cc:1390
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:572
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
Definition: dim-vector.cc:157
void chop_all_singletons(void)
Definition: dim-vector.cc:65
std::string str(char sep='x') const
Definition: dim-vector.cc:85
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:401
bool zero_by_zero(void) const
Definition: dim-vector.h:377
void resize(int n, int fill_value=0)
Definition: dim-vector.h:349
static dim_vector alloc(int n)
Definition: dim-vector.h:281
bool hvcat(const dim_vector &dvb, int dim)
This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
Definition: dim-vector.cc:220
void chop_trailing_singletons(void)
Definition: dim-vector.h:241
bool any_neg(void) const
Definition: dim-vector.h:423
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:334
bool is_nd_vector(void) const
Definition: dim-vector.h:466
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:245
octave_idx_type safe_numel(void) const
The following function will throw a std::bad_alloc () exception if the requested size is larger than ...
Definition: dim-vector.cc:115
dim_vector make_nd_vector(octave_idx_type n) const
Definition: dim-vector.h:487
octave_idx_type xelem(octave_idx_type n) const
Definition: idx-vector.h:564
bool is_colon(void) const
Definition: idx-vector.h:576
octave_idx_type fill(const T &val, octave_idx_type n, T *dest) const
Definition: idx-vector.h:768
static const idx_vector colon
Definition: idx-vector.h:499
bool maybe_reduce(octave_idx_type n, const idx_vector &j, octave_idx_type nj)
Definition: idx-vector.cc:786
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:558
octave_idx_type index(const T *src, octave_idx_type n, T *dest) const
Definition: idx-vector.h:622
bool is_scalar(void) const
Definition: idx-vector.h:579
bool is_cont_range(octave_idx_type n, octave_idx_type &l, octave_idx_type &u) const
Definition: idx-vector.cc:955
octave_idx_type assign(const T *src, octave_idx_type n, T *dest) const
Definition: idx-vector.h:696
idx_vector complement(octave_idx_type n) const
Definition: idx-vector.cc:1110
dim_vector orig_dimensions(void) const
Definition: idx-vector.h:594
octave_idx_type extent(octave_idx_type n) const
Definition: idx-vector.h:561
@ class_vector
Definition: idx-vector.h:65
@ class_scalar
Definition: idx-vector.h:64
bool is_colon_equiv(octave_idx_type n) const
Definition: idx-vector.h:585
virtual octave_idx_type numel(void) const
Definition: ov-base.h:335
void set_compare(compare_fcn_type comp)
Definition: oct-sort.h:118
void sort_rows(const T *data, octave_idx_type *idx, octave_idx_type rows, octave_idx_type cols)
Definition: oct-sort.cc:1661
static bool descending_compare(typename ref_param< T >::type, typename ref_param< T >::type)
Definition: oct-sort.cc:1973
bool issorted(const T *data, octave_idx_type nel)
Definition: oct-sort.cc:1574
octave_idx_type lookup(const T *data, octave_idx_type nel, const T &value)
Definition: oct-sort.cc:1784
void sort(T *data, octave_idx_type nel)
Definition: oct-sort.cc:1517
void nth_element(T *data, octave_idx_type nel, octave_idx_type lo, octave_idx_type up=-1)
Definition: oct-sort.cc:1944
bool is_sorted_rows(const T *data, octave_idx_type rows, octave_idx_type cols)
Definition: oct-sort.cc:1738
void lookup_sorted(const T *data, octave_idx_type nel, const T *values, octave_idx_type nvalues, octave_idx_type *idx, bool rev=false)
Definition: oct-sort.cc:1896
void assign(const T *src, T *dest) const
Definition: Array.cc:610
~rec_index_helper(void)
Definition: Array.cc:551
rec_index_helper & operator=(const rec_index_helper &)=delete
rec_index_helper(const rec_index_helper &)=delete
const T * do_assign(const T *src, T *dest, int lev) const
Definition: Array.cc:574
void index(const T *src, T *dest) const
Definition: Array.cc:607
void do_fill(const T &val, T *dest, int lev) const
Definition: Array.cc:591
rec_index_helper(const dim_vector &dv, const Array< idx_vector > &ia)
Definition: Array.cc:516
T * do_index(const T *src, T *dest, int lev) const
Definition: Array.cc:557
octave_idx_type * dim
Definition: Array.cc:511
idx_vector * idx
Definition: Array.cc:513
void fill(const T &val, T *dest) const
Definition: Array.cc:613
octave_idx_type * cdim
Definition: Array.cc:512
bool is_cont_range(octave_idx_type &l, octave_idx_type &u) const
Definition: Array.cc:615
~rec_permute_helper(void)
Definition: Array.cc:346
octave_idx_type * stride
Definition: Array.cc:298
void permute(const T *src, T *dest) const
Definition: Array.cc:426
T * do_permute(const T *src, T *dest, int lev) const
Definition: Array.cc:391
static T * blk_trans(const T *src, T *dest, octave_idx_type nr, octave_idx_type nc)
Definition: Array.cc:351
rec_permute_helper(const dim_vector &dv, const Array< octave_idx_type > &perm)
Definition: Array.cc:302
octave_idx_type * dim
Definition: Array.cc:297
rec_permute_helper & operator=(const rec_permute_helper &)=delete
rec_permute_helper(const rec_permute_helper &)=delete
void do_resize_fill(const T *src, T *dest, const T &rfv, int lev) const
Definition: Array.cc:670
octave_idx_type * dext
Definition: Array.cc:629
void resize_fill(const T *src, T *dest, const T &rfv) const
Definition: Array.cc:692
octave_idx_type * cext
Definition: Array.cc:627
~rec_resize_helper(void)
Definition: Array.cc:664
rec_resize_helper(const dim_vector &ndv, const dim_vector &odv)
Definition: Array.cc:633
rec_resize_helper & operator=(const rec_resize_helper &)=delete
octave_idx_type * sext
Definition: Array.cc:628
if_then_else< is_class_type< T >::no, T, T const & >::result type
Definition: lo-traits.h:121
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
Complex log2(const Complex &x)
Definition: lo-mappers.cc:139
void err_invalid_index(const std::string &idx, octave_idx_type nd, octave_idx_type dim, const std::string &)
void err_del_index_out_of_range(bool is1d, octave_idx_type idx, octave_idx_type ext)
void err_invalid_resize(void)
void err_index_out_of_range(int nd, int dim, octave_idx_type idx, octave_idx_type ext, const dim_vector &dv)
void err_nonconformant(const char *op, octave_idx_type op1_len, octave_idx_type op2_len)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value)
Definition: oct-locbuf.h:50
sortmode
Definition: oct-sort.h:95
@ UNSORTED
Definition: oct-sort.h:95
@ ASCENDING
Definition: oct-sort.h:95
@ DESCENDING
Definition: oct-sort.h:95
T::size_type numel(const T &str)
Definition: oct-string.cc:71
const octave_base_value const Array< octave_idx_type > & ra_idx
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
static T abs(T x)
Definition: pr-output.cc:1678
F77_RET_T len
Definition: xerbla.cc:61