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