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