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