00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029
00030 #include <cassert>
00031 #include <climits>
00032
00033 #include <iostream>
00034 #include <sstream>
00035 #include <vector>
00036 #include <algorithm>
00037 #include <new>
00038
00039 #include "Array.h"
00040 #include "Array-util.h"
00041 #include "idx-vector.h"
00042 #include "lo-error.h"
00043 #include "oct-locbuf.h"
00044
00045
00046
00047
00048 template <class T>
00049 Array<T>::Array (const Array<T>& a, const dim_vector& dv)
00050 : dimensions (dv), rep (a.rep),
00051 slice_data (a.slice_data), slice_len (a.slice_len)
00052 {
00053 if (dimensions.safe_numel () != a.numel ())
00054 {
00055 std::string dimensions_str = a.dimensions.str ();
00056 std::string new_dims_str = dimensions.str ();
00057
00058 (*current_liboctave_error_handler)
00059 ("reshape: can't reshape %s array to %s array",
00060 dimensions_str.c_str (), new_dims_str.c_str ());
00061 }
00062
00063
00064
00065 rep->count++;
00066 dimensions.chop_trailing_singletons ();
00067 }
00068
00069 template <class T>
00070 void
00071 Array<T>::fill (const T& val)
00072 {
00073 if (rep->count > 1)
00074 {
00075 --rep->count;
00076 rep = new ArrayRep (length (), val);
00077 slice_data = rep->data;
00078 }
00079 else
00080 fill_or_memset (slice_len, val, slice_data);
00081 }
00082
00083 template <class T>
00084 void
00085 Array<T>::clear (void)
00086 {
00087 if (--rep->count == 0)
00088 delete rep;
00089
00090 rep = nil_rep ();
00091 rep->count++;
00092 slice_data = rep->data;
00093 slice_len = rep->len;
00094
00095 dimensions = dim_vector ();
00096 }
00097
00098 template <class T>
00099 void
00100 Array<T>::clear (const dim_vector& dv)
00101 {
00102 if (--rep->count == 0)
00103 delete rep;
00104
00105 rep = new ArrayRep (dv.safe_numel ());
00106 slice_data = rep->data;
00107 slice_len = rep->len;
00108
00109 dimensions = dv;
00110 dimensions.chop_trailing_singletons ();
00111 }
00112
00113 template <class T>
00114 Array<T>
00115 Array<T>::squeeze (void) const
00116 {
00117 Array<T> retval = *this;
00118
00119 if (ndims () > 2)
00120 {
00121 bool dims_changed = false;
00122
00123 dim_vector new_dimensions = dimensions;
00124
00125 int k = 0;
00126
00127 for (int i = 0; i < ndims (); i++)
00128 {
00129 if (dimensions(i) == 1)
00130 dims_changed = true;
00131 else
00132 new_dimensions(k++) = dimensions(i);
00133 }
00134
00135 if (dims_changed)
00136 {
00137 switch (k)
00138 {
00139 case 0:
00140 new_dimensions = dim_vector (1, 1);
00141 break;
00142
00143 case 1:
00144 {
00145 octave_idx_type tmp = new_dimensions(0);
00146
00147 new_dimensions.resize (2);
00148
00149 new_dimensions(0) = tmp;
00150 new_dimensions(1) = 1;
00151 }
00152 break;
00153
00154 default:
00155 new_dimensions.resize (k);
00156 break;
00157 }
00158 }
00159
00160 retval = Array<T> (*this, new_dimensions);
00161 }
00162
00163 return retval;
00164 }
00165
00166 template <class T>
00167 octave_idx_type
00168 Array<T>::compute_index (octave_idx_type i, octave_idx_type j) const
00169 {
00170 return ::compute_index (i, j, dimensions);
00171 }
00172
00173 template <class T>
00174 octave_idx_type
00175 Array<T>::compute_index (octave_idx_type i, octave_idx_type j, octave_idx_type k) const
00176 {
00177 return ::compute_index (i, j, k, dimensions);
00178 }
00179
00180 template <class T>
00181 octave_idx_type
00182 Array<T>::compute_index (const Array<octave_idx_type>& ra_idx) const
00183 {
00184 return ::compute_index (ra_idx, dimensions);
00185 }
00186
00187 template <class T>
00188 T&
00189 Array<T>::checkelem (octave_idx_type n)
00190 {
00191
00192 if (n < 0)
00193 gripe_invalid_index ();
00194 if (n >= slice_len)
00195 gripe_index_out_of_range (1, 1, n+1, slice_len);
00196
00197 return elem (n);
00198 }
00199
00200 template <class T>
00201 T&
00202 Array<T>::checkelem (octave_idx_type i, octave_idx_type j)
00203 {
00204 return elem (compute_index (i, j));
00205 }
00206
00207 template <class T>
00208 T&
00209 Array<T>::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k)
00210 {
00211 return elem (compute_index (i, j, k));
00212 }
00213
00214 template <class T>
00215 T&
00216 Array<T>::checkelem (const Array<octave_idx_type>& ra_idx)
00217 {
00218 return elem (compute_index (ra_idx));
00219 }
00220
00221 template <class T>
00222 typename Array<T>::crefT
00223 Array<T>::checkelem (octave_idx_type n) const
00224 {
00225
00226 if (n < 0)
00227 gripe_invalid_index ();
00228 if (n >= slice_len)
00229 gripe_index_out_of_range (1, 1, n+1, slice_len);
00230
00231 return elem (n);
00232 }
00233
00234 template <class T>
00235 typename Array<T>::crefT
00236 Array<T>::checkelem (octave_idx_type i, octave_idx_type j) const
00237 {
00238 return elem (compute_index (i, j));
00239 }
00240
00241 template <class T>
00242 typename Array<T>::crefT
00243 Array<T>::checkelem (octave_idx_type i, octave_idx_type j, octave_idx_type k) const
00244 {
00245 return elem (compute_index (i, j, k));
00246 }
00247
00248 template <class T>
00249 typename Array<T>::crefT
00250 Array<T>::checkelem (const Array<octave_idx_type>& ra_idx) const
00251 {
00252 return elem (compute_index (ra_idx));
00253 }
00254
00255 template <class T>
00256 Array<T>
00257 Array<T>::column (octave_idx_type k) const
00258 {
00259 octave_idx_type r = dimensions(0);
00260 #ifdef BOUNDS_CHECKING
00261 if (k < 0 || k > dimensions.numel (1))
00262 gripe_index_out_of_range (2, 2, k+1, dimensions.numel (1));
00263 #endif
00264
00265 return Array<T> (*this, dim_vector (r, 1), k*r, k*r + r);
00266 }
00267
00268 template <class T>
00269 Array<T>
00270 Array<T>::page (octave_idx_type k) const
00271 {
00272 octave_idx_type r = dimensions(0), c = dimensions (1), p = r*c;
00273 #ifdef BOUNDS_CHECKING
00274 if (k < 0 || k > dimensions.numel (2))
00275 gripe_index_out_of_range (3, 3, k+1, dimensions.numel (2));
00276 #endif
00277
00278 return Array<T> (*this, dim_vector (r, c), k*p, k*p + p);
00279 }
00280
00281 template <class T>
00282 Array<T>
00283 Array<T>::linear_slice (octave_idx_type lo, octave_idx_type up) const
00284 {
00285 #ifdef BOUNDS_CHECKING
00286 if (lo < 0)
00287 gripe_index_out_of_range (1, 1, lo+1, numel ());
00288 if (up > numel ())
00289 gripe_index_out_of_range (1, 1, up, numel ());
00290 #endif
00291 if (up < lo) up = lo;
00292 return Array<T> (*this, dim_vector (up - lo, 1), lo, up);
00293 }
00294
00295
00296 class rec_permute_helper
00297 {
00298
00299
00300
00301 int n;
00302 int top;
00303 octave_idx_type *dim;
00304 octave_idx_type *stride;
00305 bool use_blk;
00306
00307 public:
00308 rec_permute_helper (const dim_vector& dv, const Array<octave_idx_type>& perm)
00309
00310 : n (dv.length ()), top (0), dim (new octave_idx_type [2*n]),
00311 stride (dim + n), use_blk (false)
00312 {
00313 assert (n == perm.length ());
00314
00315
00316 OCTAVE_LOCAL_BUFFER (octave_idx_type, cdim, n+1);
00317 cdim[0] = 1;
00318 for (int i = 1; i < n+1; i++) cdim[i] = cdim[i-1] * dv(i-1);
00319
00320
00321 for (int k = 0; k < n; k++)
00322 {
00323 int kk = perm(k);
00324 dim[k] = dv(kk);
00325 stride[k] = cdim[kk];
00326 }
00327
00328
00329 for (int k = 1; k < n; k++)
00330 {
00331 if (stride[k] == stride[top]*dim[top])
00332 dim[top] *= dim[k];
00333 else
00334 {
00335 top++;
00336 dim[top] = dim[k];
00337 stride[top] = stride[k];
00338 }
00339 }
00340
00341
00342 use_blk = top >= 1 && stride[1] == 1 && stride[0] == dim[1];
00343
00344 }
00345
00346 ~rec_permute_helper (void) { delete [] dim; }
00347
00348
00349 template <class T>
00350 static T *
00351 blk_trans (const T *src, T *dest, octave_idx_type nr, octave_idx_type nc)
00352 {
00353 static const octave_idx_type m = 8;
00354 OCTAVE_LOCAL_BUFFER (T, blk, m*m);
00355 for (octave_idx_type kr = 0; kr < nr; kr += m)
00356 for (octave_idx_type kc = 0; kc < nc; kc += m)
00357 {
00358 octave_idx_type lr = std::min (m, nr - kr);
00359 octave_idx_type lc = std::min (m, nc - kc);
00360 if (lr == m && lc == m)
00361 {
00362 const T *ss = src + kc * nr + kr;
00363 for (octave_idx_type j = 0; j < m; j++)
00364 for (octave_idx_type i = 0; i < m; i++)
00365 blk[j*m+i] = ss[j*nr + i];
00366 T *dd = dest + kr * nc + kc;
00367 for (octave_idx_type j = 0; j < m; j++)
00368 for (octave_idx_type i = 0; i < m; i++)
00369 dd[j*nc+i] = blk[i*m+j];
00370 }
00371 else
00372 {
00373 const T *ss = src + kc * nr + kr;
00374 for (octave_idx_type j = 0; j < lc; j++)
00375 for (octave_idx_type i = 0; i < lr; i++)
00376 blk[j*m+i] = ss[j*nr + i];
00377 T *dd = dest + kr * nc + kc;
00378 for (octave_idx_type j = 0; j < lr; j++)
00379 for (octave_idx_type i = 0; i < lc; i++)
00380 dd[j*nc+i] = blk[i*m+j];
00381 }
00382 }
00383
00384 return dest + nr*nc;
00385 }
00386
00387 private:
00388
00389
00390 template <class T>
00391 T *do_permute (const T *src, T *dest, int lev) const
00392 {
00393 if (lev == 0)
00394 {
00395 octave_idx_type step = stride[0], len = dim[0];
00396 if (step == 1)
00397 {
00398 copy_or_memcpy (len, src, dest);
00399 dest += len;
00400 }
00401 else
00402 {
00403 for (octave_idx_type i = 0, j = 0; i < len; i++, j += step)
00404 dest[i] = src[j];
00405
00406 dest += len;
00407 }
00408 }
00409 else if (use_blk && lev == 1)
00410 dest = blk_trans (src, dest, dim[1], dim[0]);
00411 else
00412 {
00413 octave_idx_type step = stride[lev], len = dim[lev];
00414 for (octave_idx_type i = 0, j = 0; i < len; i++, j+= step)
00415 dest = do_permute (src + i * step, dest, lev-1);
00416 }
00417
00418 return dest;
00419 }
00420
00421
00422
00423 rec_permute_helper (const rec_permute_helper&);
00424
00425 rec_permute_helper& operator = (const rec_permute_helper&);
00426
00427 public:
00428
00429 template <class T>
00430 void permute (const T *src, T *dest) const { do_permute (src, dest, top); }
00431 };
00432
00433
00434 template <class T>
00435 Array<T>
00436 Array<T>::permute (const Array<octave_idx_type>& perm_vec_arg, bool inv) const
00437 {
00438 Array<T> retval;
00439
00440 Array<octave_idx_type> perm_vec = perm_vec_arg;
00441
00442 dim_vector dv = dims ();
00443
00444 int perm_vec_len = perm_vec_arg.length ();
00445
00446 if (perm_vec_len < dv.length ())
00447 (*current_liboctave_error_handler)
00448 ("%s: invalid permutation vector", inv ? "ipermute" : "permute");
00449
00450 dim_vector dv_new = dim_vector::alloc (perm_vec_len);
00451
00452
00453 dv.resize (perm_vec_len, 1);
00454
00455
00456 OCTAVE_LOCAL_BUFFER_INIT (bool, checked, perm_vec_len, false);
00457
00458 bool identity = true;
00459
00460
00461 for (int i = 0; i < perm_vec_len; i++)
00462 {
00463 octave_idx_type perm_elt = perm_vec.elem (i);
00464 if (perm_elt >= perm_vec_len || perm_elt < 0)
00465 {
00466 (*current_liboctave_error_handler)
00467 ("%s: permutation vector contains an invalid element",
00468 inv ? "ipermute" : "permute");
00469
00470 return retval;
00471 }
00472
00473 if (checked[perm_elt])
00474 {
00475 (*current_liboctave_error_handler)
00476 ("%s: permutation vector cannot contain identical elements",
00477 inv ? "ipermute" : "permute");
00478
00479 return retval;
00480 }
00481 else
00482 {
00483 checked[perm_elt] = true;
00484 identity = identity && perm_elt == i;
00485 }
00486 }
00487
00488 if (identity)
00489 return *this;
00490
00491 if (inv)
00492 {
00493 for (int i = 0; i < perm_vec_len; i++)
00494 perm_vec(perm_vec_arg(i)) = i;
00495 }
00496
00497 for (int i = 0; i < perm_vec_len; i++)
00498 dv_new(i) = dv(perm_vec(i));
00499
00500 retval = Array<T> (dv_new);
00501
00502 if (numel () > 0)
00503 {
00504 rec_permute_helper rh (dv, perm_vec);
00505 rh.permute (data (), retval.fortran_vec ());
00506 }
00507
00508 return retval;
00509 }
00510
00511
00512
00513
00514
00515
00516
00517 class rec_index_helper
00518 {
00519
00520
00521
00522 int n;
00523 int top;
00524 octave_idx_type *dim;
00525 octave_idx_type *cdim;
00526 idx_vector *idx;
00527
00528 public:
00529 rec_index_helper (const dim_vector& dv, const Array<idx_vector>& ia)
00530 : n (ia.length ()), top (0), dim (new octave_idx_type [2*n]),
00531 cdim (dim + n), idx (new idx_vector [n])
00532 {
00533 assert (n > 0 && (dv.length () == std::max (n, 2)));
00534
00535 dim[0] = dv(0);
00536 cdim[0] = 1;
00537 idx[0] = ia(0);
00538
00539 for (int i = 1; i < n; i++)
00540 {
00541
00542 if (idx[top].maybe_reduce (dim[top], ia(i), dv(i)))
00543 {
00544
00545 dim[top] *= dv(i);
00546 }
00547 else
00548 {
00549
00550 top++;
00551 idx[top] = ia(i);
00552 dim[top] = dv(i);
00553 cdim[top] = cdim[top-1] * dim[top-1];
00554 }
00555 }
00556 }
00557
00558 ~rec_index_helper (void) { delete [] idx; delete [] dim; }
00559
00560 private:
00561
00562
00563 template <class T>
00564 T *do_index (const T *src, T *dest, int lev) const
00565 {
00566 if (lev == 0)
00567 dest += idx[0].index (src, dim[0], dest);
00568 else
00569 {
00570 octave_idx_type nn = idx[lev].length (dim[lev]), d = cdim[lev];
00571 for (octave_idx_type i = 0; i < nn; i++)
00572 dest = do_index (src + d*idx[lev].xelem (i), dest, lev-1);
00573 }
00574
00575 return dest;
00576 }
00577
00578
00579 template <class T>
00580 const T *do_assign (const T *src, T *dest, int lev) const
00581 {
00582 if (lev == 0)
00583 src += idx[0].assign (src, dim[0], dest);
00584 else
00585 {
00586 octave_idx_type nn = idx[lev].length (dim[lev]), d = cdim[lev];
00587 for (octave_idx_type i = 0; i < nn; i++)
00588 src = do_assign (src, dest + d*idx[lev].xelem (i), lev-1);
00589 }
00590
00591 return src;
00592 }
00593
00594
00595 template <class T>
00596 void do_fill (const T& val, T *dest, int lev) const
00597 {
00598 if (lev == 0)
00599 idx[0].fill (val, dim[0], dest);
00600 else
00601 {
00602 octave_idx_type nn = idx[lev].length (dim[lev]), d = cdim[lev];
00603 for (octave_idx_type i = 0; i < nn; i++)
00604 do_fill (val, dest + d*idx[lev].xelem (i), lev-1);
00605 }
00606 }
00607
00608
00609
00610 rec_index_helper (const rec_index_helper&);
00611
00612 rec_index_helper& operator = (const rec_index_helper&);
00613
00614 public:
00615
00616 template <class T>
00617 void index (const T *src, T *dest) const { do_index (src, dest, top); }
00618
00619 template <class T>
00620 void assign (const T *src, T *dest) const { do_assign (src, dest, top); }
00621
00622 template <class T>
00623 void fill (const T& val, T *dest) const { do_fill (val, dest, top); }
00624
00625 bool is_cont_range (octave_idx_type& l,
00626 octave_idx_type& u) const
00627 {
00628 return top == 0 && idx[0].is_cont_range (dim[0], l, u);
00629 }
00630 };
00631
00632
00633
00634
00635 class rec_resize_helper
00636 {
00637 octave_idx_type *cext;
00638 octave_idx_type *sext;
00639 octave_idx_type *dext;
00640 int n;
00641
00642 public:
00643 rec_resize_helper (const dim_vector& ndv, const dim_vector& odv)
00644 : cext (0), sext (0), dext (0), n (0)
00645 {
00646 int l = ndv.length ();
00647 assert (odv.length () == l);
00648 octave_idx_type ld = 1;
00649 int i = 0;
00650 for (; i < l-1 && ndv(i) == odv(i); i++) ld *= ndv(i);
00651 n = l - i;
00652 cext = new octave_idx_type[3*n];
00653
00654 sext = cext + n;
00655 dext = sext + n;
00656
00657 octave_idx_type sld = ld, dld = ld;
00658 for (int j = 0; j < n; j++)
00659 {
00660 cext[j] = std::min (ndv(i+j), odv(i+j));
00661 sext[j] = sld *= odv(i+j);
00662 dext[j] = dld *= ndv(i+j);
00663 }
00664 cext[0] *= ld;
00665 }
00666
00667 ~rec_resize_helper (void) { delete [] cext; }
00668
00669 private:
00670
00671
00672 template <class T>
00673 void do_resize_fill (const T* src, T *dest, const T& rfv, int lev) const
00674 {
00675 if (lev == 0)
00676 {
00677 copy_or_memcpy (cext[0], src, dest);
00678 fill_or_memset (dext[0] - cext[0], rfv, dest + cext[0]);
00679 }
00680 else
00681 {
00682 octave_idx_type sd = sext[lev-1], dd = dext[lev-1], k;
00683 for (k = 0; k < cext[lev]; k++)
00684 do_resize_fill (src + k * sd, dest + k * dd, rfv, lev - 1);
00685
00686 fill_or_memset (dext[lev] - k * dd, rfv, dest + k * dd);
00687 }
00688 }
00689
00690
00691
00692 rec_resize_helper (const rec_resize_helper&);
00693
00694 rec_resize_helper& operator = (const rec_resize_helper&);
00695
00696 public:
00697
00698 template <class T>
00699 void resize_fill (const T* src, T *dest, const T& rfv) const
00700 { do_resize_fill (src, dest, rfv, n-1); }
00701 };
00702
00703 template <class T>
00704 Array<T>
00705 Array<T>::index (const idx_vector& i) const
00706 {
00707 octave_idx_type n = numel ();
00708 Array<T> retval;
00709
00710 if (i.is_colon ())
00711 {
00712
00713 retval = Array<T> (*this, dim_vector (n, 1));
00714 }
00715 else
00716 {
00717 if (i.extent (n) != n)
00718 gripe_index_out_of_range (1, 1, i.extent (n), n);
00719
00720
00721 dim_vector rd = i.orig_dimensions ();
00722 octave_idx_type il = i.length (n);
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 if (ndims () == 2 && n != 1 && rd.is_vector ())
00742 {
00743 if (columns () == 1)
00744 rd = dim_vector (il, 1);
00745 else if (rows () == 1)
00746 rd = dim_vector (1, il);
00747 }
00748
00749 octave_idx_type l, u;
00750 if (il != 0 && i.is_cont_range (n, l, u))
00751
00752 retval = Array<T> (*this, rd, l, u);
00753 else
00754 {
00755
00756
00757 retval = Array<T> (rd);
00758
00759 if (il != 0)
00760 i.index (data (), n, retval.fortran_vec ());
00761 }
00762 }
00763
00764 return retval;
00765 }
00766
00767 template <class T>
00768 Array<T>
00769 Array<T>::index (const idx_vector& i, const idx_vector& j) const
00770 {
00771
00772 dim_vector dv = dimensions.redim (2);
00773 octave_idx_type r = dv(0), c = dv(1);
00774 Array<T> retval;
00775
00776 if (i.is_colon () && j.is_colon ())
00777 {
00778
00779 retval = Array<T> (*this, dv);
00780 }
00781 else
00782 {
00783 if (i.extent (r) != r)
00784 gripe_index_out_of_range (2, 1, i.extent (r), r);
00785 if (j.extent (c) != c)
00786 gripe_index_out_of_range (2, 2, j.extent (c), c);
00787
00788 octave_idx_type n = numel (), il = i.length (r), jl = j.length (c);
00789
00790 idx_vector ii (i);
00791
00792 if (ii.maybe_reduce (r, j, c))
00793 {
00794 octave_idx_type l, u;
00795 if (ii.length () > 0 && ii.is_cont_range (n, l, u))
00796
00797 retval = Array<T> (*this, dim_vector (il, jl), l, u);
00798 else
00799 {
00800
00801 retval = Array<T> (dim_vector (il, jl));
00802
00803 ii.index (data (), n, retval.fortran_vec ());
00804 }
00805 }
00806 else
00807 {
00808
00809 retval = Array<T> (dim_vector (il, jl));
00810
00811 const T* src = data ();
00812 T *dest = retval.fortran_vec ();
00813
00814 for (octave_idx_type k = 0; k < jl; k++)
00815 dest += i.index (src + r * j.xelem (k), r, dest);
00816 }
00817 }
00818
00819 return retval;
00820 }
00821
00822 template <class T>
00823 Array<T>
00824 Array<T>::index (const Array<idx_vector>& ia) const
00825 {
00826 int ial = ia.length ();
00827 Array<T> retval;
00828
00829
00830 if (ial == 1)
00831 retval = index (ia(0));
00832 else if (ial == 2)
00833 retval = index (ia(0), ia(1));
00834 else if (ial > 0)
00835 {
00836
00837 dim_vector dv = dimensions.redim (ial);
00838
00839
00840 bool all_colons = true;
00841 for (int i = 0; i < ial; i++)
00842 {
00843 if (ia(i).extent (dv(i)) != dv(i))
00844 gripe_index_out_of_range (ial, i+1, ia(i).extent (dv(i)), dv(i));
00845
00846 all_colons = all_colons && ia(i).is_colon ();
00847 }
00848
00849
00850 if (all_colons)
00851 {
00852
00853 dv.chop_trailing_singletons ();
00854 retval = Array<T> (*this, dv);
00855 }
00856 else
00857 {
00858
00859 dim_vector rdv = dim_vector::alloc (ial);
00860 for (int i = 0; i < ial; i++) rdv(i) = ia(i).length (dv(i));
00861 rdv.chop_trailing_singletons ();
00862
00863
00864 rec_index_helper rh (dv, ia);
00865
00866 octave_idx_type l, u;
00867 if (rh.is_cont_range (l, u))
00868
00869 retval = Array<T> (*this, rdv, l, u);
00870 else
00871 {
00872
00873 retval = Array<T> (rdv);
00874
00875
00876 rh.index (data (), retval.fortran_vec ());
00877 }
00878 }
00879 }
00880
00881 return retval;
00882 }
00883
00884
00885
00886 template <class T>
00887 const T& Array<T>::resize_fill_value ()
00888 {
00889 static T zero = T ();
00890 return zero;
00891 }
00892
00893
00894
00895
00896 template <class T>
00897 void
00898 Array<T>::resize1 (octave_idx_type n, const T& rfv)
00899 {
00900 if (n >= 0 && ndims () == 2)
00901 {
00902 dim_vector dv;
00903
00904
00905
00906
00907
00908
00909
00910 bool invalid = false;
00911 if (rows () == 0 || rows () == 1)
00912 dv = dim_vector (1, n);
00913 else if (columns () == 1)
00914 dv = dim_vector (n, 1);
00915 else
00916 invalid = true;
00917
00918 if (invalid)
00919 gripe_invalid_resize ();
00920 else
00921 {
00922 octave_idx_type nx = numel ();
00923 if (n == nx - 1 && n > 0)
00924 {
00925
00926 if (rep->count == 1)
00927 slice_data[slice_len-1] = T ();
00928 slice_len--;
00929 dimensions = dv;
00930 }
00931 else if (n == nx + 1 && nx > 0)
00932 {
00933
00934 if (rep->count == 1 && slice_data + slice_len < rep->data + rep->len)
00935 {
00936 slice_data[slice_len++] = rfv;
00937 dimensions = dv;
00938 }
00939 else
00940 {
00941 static const octave_idx_type max_stack_chunk = 1024;
00942 octave_idx_type nn = n + std::min (nx, max_stack_chunk);
00943 Array<T> tmp (Array<T> (dim_vector (nn, 1)), dv, 0, n);
00944 T *dest = tmp.fortran_vec ();
00945
00946 copy_or_memcpy (nx, data (), dest);
00947 dest[nx] = rfv;
00948
00949 *this = tmp;
00950 }
00951 }
00952 else if (n != nx)
00953 {
00954 Array<T> tmp = Array<T> (dv);
00955 T *dest = tmp.fortran_vec ();
00956
00957 octave_idx_type n0 = std::min (n, nx), n1 = n - n0;
00958 copy_or_memcpy (n0, data (), dest);
00959 fill_or_memset (n1, rfv, dest + n0);
00960
00961 *this = tmp;
00962 }
00963 }
00964 }
00965 else
00966 gripe_invalid_resize ();
00967 }
00968
00969 template <class T>
00970 void
00971 Array<T>::resize2 (octave_idx_type r, octave_idx_type c, const T& rfv)
00972 {
00973 if (r >= 0 && c >= 0 && ndims () == 2)
00974 {
00975 octave_idx_type rx = rows (), cx = columns ();
00976 if (r != rx || c != cx)
00977 {
00978 Array<T> tmp = Array<T> (dim_vector (r, c));
00979 T *dest = tmp.fortran_vec ();
00980
00981 octave_idx_type r0 = std::min (r, rx), r1 = r - r0;
00982 octave_idx_type c0 = std::min (c, cx), c1 = c - c0;
00983 const T *src = data ();
00984 if (r == rx)
00985 {
00986 copy_or_memcpy (r * c0, src, dest);
00987 dest += r * c0;
00988 }
00989 else
00990 {
00991 for (octave_idx_type k = 0; k < c0; k++)
00992 {
00993 copy_or_memcpy (r0, src, dest);
00994 src += rx;
00995 dest += r0;
00996 fill_or_memset (r1, rfv, dest);
00997 dest += r1;
00998 }
00999 }
01000
01001 fill_or_memset (r * c1, rfv, dest);
01002
01003 *this = tmp;
01004 }
01005 }
01006 else
01007 gripe_invalid_resize ();
01008
01009 }
01010
01011 template<class T>
01012 void
01013 Array<T>::resize (const dim_vector& dv, const T& rfv)
01014 {
01015 int dvl = dv.length ();
01016 if (dvl == 2)
01017 resize2 (dv(0), dv(1), rfv);
01018 else if (dimensions != dv)
01019 {
01020 if (dimensions.length () <= dvl && ! dv.any_neg ())
01021 {
01022 Array<T> tmp (dv);
01023
01024 rec_resize_helper rh (dv, dimensions.redim (dvl));
01025
01026
01027 rh.resize_fill (data (), tmp.fortran_vec (), rfv);
01028 *this = tmp;
01029 }
01030 else
01031 gripe_invalid_resize ();
01032 }
01033 }
01034
01035 template <class T>
01036 Array<T>
01037 Array<T>::index (const idx_vector& i, bool resize_ok, const T& rfv) const
01038 {
01039 Array<T> tmp = *this;
01040 if (resize_ok)
01041 {
01042 octave_idx_type n = numel (), nx = i.extent (n);
01043 if (n != nx)
01044 {
01045 if (i.is_scalar ())
01046 return Array<T> (dim_vector (1, 1), rfv);
01047 else
01048 tmp.resize1 (nx, rfv);
01049 }
01050
01051 if (tmp.numel () != nx)
01052 return Array<T> ();
01053 }
01054
01055 return tmp.index (i);
01056 }
01057
01058 template <class T>
01059 Array<T>
01060 Array<T>::index (const idx_vector& i, const idx_vector& j,
01061 bool resize_ok, const T& rfv) const
01062 {
01063 Array<T> tmp = *this;
01064 if (resize_ok)
01065 {
01066 dim_vector dv = dimensions.redim (2);
01067 octave_idx_type r = dv(0), c = dv(1);
01068 octave_idx_type rx = i.extent (r), cx = j.extent (c);
01069 if (r != rx || c != cx)
01070 {
01071 if (i.is_scalar () && j.is_scalar ())
01072 return Array<T> (dim_vector (1, 1), rfv);
01073 else
01074 tmp.resize2 (rx, cx, rfv);
01075 }
01076
01077 if (tmp.rows () != rx || tmp.columns () != cx)
01078 return Array<T> ();
01079 }
01080
01081 return tmp.index (i, j);
01082 }
01083
01084 template <class T>
01085 Array<T>
01086 Array<T>::index (const Array<idx_vector>& ia,
01087 bool resize_ok, const T& rfv) const
01088 {
01089 Array<T> tmp = *this;
01090 if (resize_ok)
01091 {
01092 int ial = ia.length ();
01093 dim_vector dv = dimensions.redim (ial);
01094 dim_vector dvx = dim_vector::alloc (ial);
01095 for (int i = 0; i < ial; i++) dvx(i) = ia(i).extent (dv (i));
01096 if (! (dvx == dv))
01097 {
01098 bool all_scalars = true;
01099 for (int i = 0; i < ial; i++)
01100 all_scalars = all_scalars && ia(i).is_scalar ();
01101 if (all_scalars)
01102 return Array<T> (dim_vector (1, 1), rfv);
01103 else
01104 tmp.resize (dvx, rfv);
01105 }
01106
01107 if (tmp.dimensions != dvx)
01108 return Array<T> ();
01109 }
01110
01111 return tmp.index (ia);
01112 }
01113
01114
01115 template <class T>
01116 void
01117 Array<T>::assign (const idx_vector& i, const Array<T>& rhs, const T& rfv)
01118 {
01119 octave_idx_type n = numel (), rhl = rhs.numel ();
01120
01121 if (rhl == 1 || i.length (n) == rhl)
01122 {
01123 octave_idx_type nx = i.extent (n);
01124 bool colon = i.is_colon_equiv (nx);
01125
01126 if (nx != n)
01127 {
01128
01129 if (dimensions.zero_by_zero () && colon)
01130 {
01131 if (rhl == 1)
01132 *this = Array<T> (dim_vector (1, nx), rhs(0));
01133 else
01134 *this = Array<T> (rhs, dim_vector (1, nx));
01135 return;
01136 }
01137
01138 resize1 (nx, rfv);
01139 n = numel ();
01140 }
01141
01142 if (colon)
01143 {
01144
01145 if (rhl == 1)
01146 fill (rhs(0));
01147 else
01148 *this = rhs.reshape (dimensions);
01149 }
01150 else
01151 {
01152 if (rhl == 1)
01153 i.fill (rhs(0), n, fortran_vec ());
01154 else
01155 i.assign (rhs.data (), n, fortran_vec ());
01156 }
01157 }
01158 else
01159 gripe_invalid_assignment_size ();
01160 }
01161
01162 template <class T>
01163 void
01164 Array<T>::assign (const idx_vector& i, const idx_vector& j,
01165 const Array<T>& rhs, const T& rfv)
01166 {
01167 bool initial_dims_all_zero = dimensions.all_zero ();
01168
01169
01170 dim_vector rhdv = rhs.dims ();
01171
01172
01173 dim_vector dv = dimensions.redim (2);
01174
01175
01176 dim_vector rdv;
01177
01178
01179
01180
01181 if (initial_dims_all_zero)
01182 rdv = zero_dims_inquire (i, j, rhdv);
01183 else
01184 {
01185 rdv(0) = i.extent (dv(0));
01186 rdv(1) = j.extent (dv(1));
01187 }
01188
01189 bool isfill = rhs.numel () == 1;
01190 octave_idx_type il = i.length (rdv(0)), jl = j.length (rdv(1));
01191 rhdv.chop_all_singletons ();
01192 bool match = (isfill
01193 || (rhdv.length () == 2 && il == rhdv(0) && jl == rhdv(1)));
01194 match = match || (il == 1 && jl == rhdv(0) && rhdv(1) == 1);
01195
01196 if (match)
01197 {
01198 bool all_colons = (i.is_colon_equiv (rdv(0))
01199 && j.is_colon_equiv (rdv(1)));
01200
01201 if (rdv != dv)
01202 {
01203
01204 if (dv.zero_by_zero () && all_colons)
01205 {
01206 if (isfill)
01207 *this = Array<T> (rdv, rhs(0));
01208 else
01209 *this = Array<T> (rhs, rdv);
01210 return;
01211 }
01212
01213 resize (rdv, rfv);
01214 dv = dimensions;
01215 }
01216
01217 if (all_colons)
01218 {
01219
01220 if (isfill)
01221 fill (rhs(0));
01222 else
01223 *this = rhs.reshape (dimensions);
01224 }
01225 else
01226 {
01227
01228 octave_idx_type n = numel (), r = dv (0), c = dv (1);
01229 idx_vector ii (i);
01230
01231 const T* src = rhs.data ();
01232 T *dest = fortran_vec ();
01233
01234
01235 if (ii.maybe_reduce (r, j, c))
01236 {
01237 if (isfill)
01238 ii.fill (*src, n, dest);
01239 else
01240 ii.assign (src, n, dest);
01241 }
01242 else
01243 {
01244 if (isfill)
01245 {
01246 for (octave_idx_type k = 0; k < jl; k++)
01247 i.fill (*src, r, dest + r * j.xelem (k));
01248 }
01249 else
01250 {
01251 for (octave_idx_type k = 0; k < jl; k++)
01252 src += i.assign (src, r, dest + r * j.xelem (k));
01253 }
01254 }
01255 }
01256 }
01257 else
01258 gripe_assignment_dimension_mismatch ();
01259 }
01260
01261 template <class T>
01262 void
01263 Array<T>::assign (const Array<idx_vector>& ia,
01264 const Array<T>& rhs, const T& rfv)
01265 {
01266 int ial = ia.length ();
01267
01268
01269 if (ial == 1)
01270 assign (ia(0), rhs, rfv);
01271 else if (ial == 2)
01272 assign (ia(0), ia(1), rhs, rfv);
01273 else if (ial > 0)
01274 {
01275 bool initial_dims_all_zero = dimensions.all_zero ();
01276
01277
01278 dim_vector rhdv = rhs.dims ();
01279
01280
01281 dim_vector dv = dimensions.redim (ial);
01282
01283
01284 dim_vector rdv;
01285
01286
01287
01288
01289 if (initial_dims_all_zero)
01290 rdv = zero_dims_inquire (ia, rhdv);
01291 else
01292 {
01293 rdv = dim_vector::alloc (ial);
01294 for (int i = 0; i < ial; i++)
01295 rdv(i) = ia(i).extent (dv(i));
01296 }
01297
01298
01299 bool match = true, all_colons = true, isfill = rhs.numel () == 1;
01300
01301 rhdv.chop_all_singletons ();
01302 int j = 0, rhdvl = rhdv.length ();
01303 for (int i = 0; i < ial; i++)
01304 {
01305 all_colons = all_colons && ia(i).is_colon_equiv (rdv(i));
01306 octave_idx_type l = ia(i).length (rdv(i));
01307 if (l == 1) continue;
01308 match = match && j < rhdvl && l == rhdv(j++);
01309 }
01310
01311 match = match && (j == rhdvl || rhdv(j) == 1);
01312 match = match || isfill;
01313
01314 if (match)
01315 {
01316
01317 if (rdv != dv)
01318 {
01319
01320 if (dv.zero_by_zero () && all_colons)
01321 {
01322 rdv.chop_trailing_singletons ();
01323 if (isfill)
01324 *this = Array<T> (rdv, rhs(0));
01325 else
01326 *this = Array<T> (rhs, rdv);
01327 return;
01328 }
01329
01330 resize (rdv, rfv);
01331 dv = rdv;
01332 }
01333
01334 if (all_colons)
01335 {
01336
01337 if (isfill)
01338 fill (rhs(0));
01339 else
01340 *this = rhs.reshape (dimensions);
01341 }
01342 else
01343 {
01344
01345
01346
01347 rec_index_helper rh (dv, ia);
01348
01349
01350 if (isfill)
01351 rh.fill (rhs(0), fortran_vec ());
01352 else
01353 rh.assign (rhs.data (), fortran_vec ());
01354 }
01355 }
01356 else
01357 gripe_assignment_dimension_mismatch ();
01358 }
01359 }
01360
01361 template <class T>
01362 void
01363 Array<T>::delete_elements (const idx_vector& i)
01364 {
01365 octave_idx_type n = numel ();
01366 if (i.is_colon ())
01367 {
01368 *this = Array<T> ();
01369 }
01370 else if (i.length (n) != 0)
01371 {
01372 if (i.extent (n) != n)
01373 gripe_del_index_out_of_range (true, i.extent (n), n);
01374
01375 octave_idx_type l, u;
01376 bool col_vec = ndims () == 2 && columns () == 1 && rows () != 1;
01377 if (i.is_scalar () && i(0) == n-1 && dimensions.is_vector ())
01378 {
01379
01380 resize1 (n-1);
01381 }
01382 else if (i.is_cont_range (n, l, u))
01383 {
01384
01385 octave_idx_type m = n + l - u;
01386 Array<T> tmp (dim_vector (col_vec ? m : 1, !col_vec ? m : 1));
01387 const T *src = data ();
01388 T *dest = tmp.fortran_vec ();
01389 copy_or_memcpy (l, src, dest);
01390 copy_or_memcpy (n - u, src + u, dest + l);
01391 *this = tmp;
01392 }
01393 else
01394 {
01395
01396 *this = index (i.complement (n));
01397 }
01398 }
01399 }
01400
01401 template <class T>
01402 void
01403 Array<T>::delete_elements (int dim, const idx_vector& i)
01404 {
01405 if (dim < 0 || dim >= ndims ())
01406 {
01407 (*current_liboctave_error_handler)
01408 ("invalid dimension in delete_elements");
01409 return;
01410 }
01411
01412 octave_idx_type n = dimensions (dim);
01413 if (i.is_colon ())
01414 {
01415 *this = Array<T> ();
01416 }
01417 else if (i.length (n) != 0)
01418 {
01419 if (i.extent (n) != n)
01420 gripe_del_index_out_of_range (false, i.extent (n), n);
01421
01422 octave_idx_type l, u;
01423
01424 if (i.is_cont_range (n, l, u))
01425 {
01426
01427 octave_idx_type nd = n + l - u, dl = 1, du = 1;
01428 dim_vector rdv = dimensions;
01429 rdv(dim) = nd;
01430 for (int k = 0; k < dim; k++) dl *= dimensions(k);
01431 for (int k = dim + 1; k < ndims (); k++) du *= dimensions(k);
01432
01433
01434 Array<T> tmp = Array<T> (rdv);
01435 const T *src = data ();
01436 T *dest = tmp.fortran_vec ();
01437 l *= dl; u *= dl; n *= dl;
01438 for (octave_idx_type k = 0; k < du; k++)
01439 {
01440 copy_or_memcpy (l, src, dest);
01441 dest += l;
01442 copy_or_memcpy (n - u, src + u, dest);
01443 dest += n - u;
01444 src += n;
01445 }
01446
01447 *this = tmp;
01448 }
01449 else
01450 {
01451
01452 Array<idx_vector> ia (dim_vector (ndims (), 1), idx_vector::colon);
01453 ia (dim) = i.complement (n);
01454 *this = index (ia);
01455 }
01456 }
01457 }
01458
01459 template <class T>
01460 void
01461 Array<T>::delete_elements (const Array<idx_vector>& ia)
01462 {
01463 if (ia.length () == 1)
01464 delete_elements (ia(0));
01465 else
01466 {
01467 int len = ia.length (), k, dim = -1;
01468 for (k = 0; k < len; k++)
01469 {
01470 if (! ia(k).is_colon ())
01471 {
01472 if (dim < 0)
01473 dim = k;
01474 else
01475 break;
01476 }
01477 }
01478 if (dim < 0)
01479 {
01480 dim_vector dv = dimensions;
01481 dv(0) = 0;
01482 *this = Array<T> (dv);
01483 }
01484 else if (k == len)
01485 {
01486 delete_elements (dim, ia(dim));
01487 }
01488 else
01489 {
01490 (*current_liboctave_error_handler)
01491 ("a null assignment can only have one non-colon index");
01492 }
01493 }
01494
01495 }
01496
01497 template <class T>
01498 Array<T>&
01499 Array<T>::insert (const Array<T>& a, octave_idx_type r, octave_idx_type c)
01500 {
01501 idx_vector i (r, r + a.rows ());
01502 idx_vector j (c, c + a.columns ());
01503 if (ndims () == 2 && a.ndims () == 2)
01504 assign (i, j, a);
01505 else
01506 {
01507 Array<idx_vector> idx (dim_vector (a.ndims (), 1));
01508 idx(0) = i;
01509 idx(1) = j;
01510 for (int k = 2; k < a.ndims (); k++)
01511 idx(k) = idx_vector (0, a.dimensions(k));
01512 assign (idx, a);
01513 }
01514
01515 return *this;
01516 }
01517
01518 template <class T>
01519 Array<T>&
01520 Array<T>::insert (const Array<T>& a, const Array<octave_idx_type>& ra_idx)
01521 {
01522 octave_idx_type n = ra_idx.length ();
01523 Array<idx_vector> idx (dim_vector (n, 1));
01524 const dim_vector dva = a.dims ().redim (n);
01525 for (octave_idx_type k = 0; k < n; k++)
01526 idx(k) = idx_vector (ra_idx (k), ra_idx (k) + dva(k));
01527
01528 assign (idx, a);
01529
01530 return *this;
01531 }
01532
01533
01534 template <class T>
01535 Array<T>
01536 Array<T>::transpose (void) const
01537 {
01538 assert (ndims () == 2);
01539
01540 octave_idx_type nr = dim1 ();
01541 octave_idx_type nc = dim2 ();
01542
01543 if (nr >= 8 && nc >= 8)
01544 {
01545 Array<T> result (dim_vector (nc, nr));
01546
01547
01548
01549 rec_permute_helper::blk_trans (data (), result.fortran_vec (), nr, nc);
01550
01551 return result;
01552 }
01553 else if (nr > 1 && nc > 1)
01554 {
01555 Array<T> result (dim_vector (nc, nr));
01556
01557 for (octave_idx_type j = 0; j < nc; j++)
01558 for (octave_idx_type i = 0; i < nr; i++)
01559 result.xelem (j, i) = xelem (i, j);
01560
01561 return result;
01562 }
01563 else
01564 {
01565
01566 return Array<T> (*this, dim_vector (nc, nr));
01567 }
01568 }
01569
01570 template <class T>
01571 static T
01572 no_op_fcn (const T& x)
01573 {
01574 return x;
01575 }
01576
01577 template <class T>
01578 Array<T>
01579 Array<T>::hermitian (T (*fcn) (const T&)) const
01580 {
01581 assert (ndims () == 2);
01582
01583 if (! fcn)
01584 fcn = no_op_fcn<T>;
01585
01586 octave_idx_type nr = dim1 ();
01587 octave_idx_type nc = dim2 ();
01588
01589 if (nr >= 8 && nc >= 8)
01590 {
01591 Array<T> result (dim_vector (nc, nr));
01592
01593
01594
01595
01596
01597 T buf[64];
01598
01599 octave_idx_type ii = 0, jj;
01600 for (jj = 0; jj < (nc - 8 + 1); jj += 8)
01601 {
01602 for (ii = 0; ii < (nr - 8 + 1); ii += 8)
01603 {
01604
01605 for (octave_idx_type j = jj, k = 0, idxj = jj * nr;
01606 j < jj + 8; j++, idxj += nr)
01607 for (octave_idx_type i = ii; i < ii + 8; i++)
01608 buf[k++] = xelem (i + idxj);
01609
01610
01611 for (octave_idx_type i = ii, idxi = ii * nc; i < ii + 8;
01612 i++, idxi += nc)
01613 for (octave_idx_type j = jj, k = i - ii; j < jj + 8;
01614 j++, k+=8)
01615 result.xelem (j + idxi) = fcn (buf[k]);
01616 }
01617
01618 if (ii < nr)
01619 for (octave_idx_type j = jj; j < jj + 8; j++)
01620 for (octave_idx_type i = ii; i < nr; i++)
01621 result.xelem (j, i) = fcn (xelem (i, j));
01622 }
01623
01624 for (octave_idx_type j = jj; j < nc; j++)
01625 for (octave_idx_type i = 0; i < nr; i++)
01626 result.xelem (j, i) = fcn (xelem (i, j));
01627
01628 return result;
01629 }
01630 else
01631 {
01632 Array<T> result (dim_vector (nc, nr));
01633
01634 for (octave_idx_type j = 0; j < nc; j++)
01635 for (octave_idx_type i = 0; i < nr; i++)
01636 result.xelem (j, i) = fcn (xelem (i, j));
01637
01638 return result;
01639 }
01640 }
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676 template <class T>
01677 T *
01678 Array<T>::fortran_vec (void)
01679 {
01680 make_unique ();
01681
01682 return slice_data;
01683 }
01684
01685
01686 template <class T>
01687 inline bool
01688 sort_isnan (typename ref_param<T>::type)
01689 {
01690 return false;
01691 }
01692
01693 template <class T>
01694 Array<T>
01695 Array<T>::sort (int dim, sortmode mode) const
01696 {
01697 if (dim < 0)
01698 {
01699 (*current_liboctave_error_handler)
01700 ("sort: invalid dimension");
01701 return Array<T> ();
01702 }
01703
01704 Array<T> m (dims ());
01705
01706 dim_vector dv = m.dims ();
01707
01708 if (m.length () < 1)
01709 return m;
01710
01711 if (dim >= dv.length ())
01712 dv.resize (dim+1, 1);
01713
01714 octave_idx_type ns = dv(dim);
01715 octave_idx_type iter = dv.numel () / ns;
01716 octave_idx_type stride = 1;
01717
01718 for (int i = 0; i < dim; i++)
01719 stride *= dv(i);
01720
01721 T *v = m.fortran_vec ();
01722 const T *ov = data ();
01723
01724 octave_sort<T> lsort;
01725
01726 if (mode != UNSORTED)
01727 lsort.set_compare (mode);
01728 else
01729 return m;
01730
01731 if (stride == 1)
01732 {
01733 for (octave_idx_type j = 0; j < iter; j++)
01734 {
01735
01736
01737 octave_idx_type kl = 0, ku = ns;
01738 for (octave_idx_type i = 0; i < ns; i++)
01739 {
01740 T tmp = ov[i];
01741 if (sort_isnan<T> (tmp))
01742 v[--ku] = tmp;
01743 else
01744 v[kl++] = tmp;
01745 }
01746
01747
01748 lsort.sort (v, kl);
01749
01750 if (ku < ns)
01751 {
01752
01753 std::reverse (v + ku, v + ns);
01754 if (mode == DESCENDING)
01755 std::rotate (v, v + ku, v + ns);
01756 }
01757
01758 v += ns;
01759 ov += ns;
01760 }
01761 }
01762 else
01763 {
01764 OCTAVE_LOCAL_BUFFER (T, buf, ns);
01765
01766 for (octave_idx_type j = 0; j < iter; j++)
01767 {
01768 octave_idx_type offset = j;
01769 octave_idx_type offset2 = 0;
01770
01771 while (offset >= stride)
01772 {
01773 offset -= stride;
01774 offset2++;
01775 }
01776
01777 offset += offset2 * stride * ns;
01778
01779
01780
01781 octave_idx_type kl = 0, ku = ns;
01782 for (octave_idx_type i = 0; i < ns; i++)
01783 {
01784 T tmp = ov[i*stride + offset];
01785 if (sort_isnan<T> (tmp))
01786 buf[--ku] = tmp;
01787 else
01788 buf[kl++] = tmp;
01789 }
01790
01791
01792 lsort.sort (buf, kl);
01793
01794 if (ku < ns)
01795 {
01796
01797 std::reverse (buf + ku, buf + ns);
01798 if (mode == DESCENDING)
01799 std::rotate (buf, buf + ku, buf + ns);
01800 }
01801
01802
01803 for (octave_idx_type i = 0; i < ns; i++)
01804 v[i*stride + offset] = buf[i];
01805 }
01806 }
01807
01808 return m;
01809 }
01810
01811 template <class T>
01812 Array<T>
01813 Array<T>::sort (Array<octave_idx_type> &sidx, int dim,
01814 sortmode mode) const
01815 {
01816 if (dim < 0 || dim >= ndims ())
01817 {
01818 (*current_liboctave_error_handler)
01819 ("sort: invalid dimension");
01820 return Array<T> ();
01821 }
01822
01823 Array<T> m (dims ());
01824
01825 dim_vector dv = m.dims ();
01826
01827 if (m.length () < 1)
01828 {
01829 sidx = Array<octave_idx_type> (dv);
01830 return m;
01831 }
01832
01833 octave_idx_type ns = dv(dim);
01834 octave_idx_type iter = dv.numel () / ns;
01835 octave_idx_type stride = 1;
01836
01837 for (int i = 0; i < dim; i++)
01838 stride *= dv(i);
01839
01840 T *v = m.fortran_vec ();
01841 const T *ov = data ();
01842
01843 octave_sort<T> lsort;
01844
01845 sidx = Array<octave_idx_type> (dv);
01846 octave_idx_type *vi = sidx.fortran_vec ();
01847
01848 if (mode != UNSORTED)
01849 lsort.set_compare (mode);
01850 else
01851 return m;
01852
01853 if (stride == 1)
01854 {
01855 for (octave_idx_type j = 0; j < iter; j++)
01856 {
01857
01858
01859 octave_idx_type kl = 0, ku = ns;
01860 for (octave_idx_type i = 0; i < ns; i++)
01861 {
01862 T tmp = ov[i];
01863 if (sort_isnan<T> (tmp))
01864 {
01865 --ku;
01866 v[ku] = tmp;
01867 vi[ku] = i;
01868 }
01869 else
01870 {
01871 v[kl] = tmp;
01872 vi[kl] = i;
01873 kl++;
01874 }
01875 }
01876
01877
01878 lsort.sort (v, vi, kl);
01879
01880 if (ku < ns)
01881 {
01882
01883 std::reverse (v + ku, v + ns);
01884 std::reverse (vi + ku, vi + ns);
01885 if (mode == DESCENDING)
01886 {
01887 std::rotate (v, v + ku, v + ns);
01888 std::rotate (vi, vi + ku, vi + ns);
01889 }
01890 }
01891
01892 v += ns;
01893 vi += ns;
01894 ov += ns;
01895 }
01896 }
01897 else
01898 {
01899 OCTAVE_LOCAL_BUFFER (T, buf, ns);
01900 OCTAVE_LOCAL_BUFFER (octave_idx_type, bufi, ns);
01901
01902 for (octave_idx_type j = 0; j < iter; j++)
01903 {
01904 octave_idx_type offset = j;
01905 octave_idx_type offset2 = 0;
01906
01907 while (offset >= stride)
01908 {
01909 offset -= stride;
01910 offset2++;
01911 }
01912
01913 offset += offset2 * stride * ns;
01914
01915
01916
01917 octave_idx_type kl = 0, ku = ns;
01918 for (octave_idx_type i = 0; i < ns; i++)
01919 {
01920 T tmp = ov[i*stride + offset];
01921 if (sort_isnan<T> (tmp))
01922 {
01923 --ku;
01924 buf[ku] = tmp;
01925 bufi[ku] = i;
01926 }
01927 else
01928 {
01929 buf[kl] = tmp;
01930 bufi[kl] = i;
01931 kl++;
01932 }
01933 }
01934
01935
01936 lsort.sort (buf, bufi, kl);
01937
01938 if (ku < ns)
01939 {
01940
01941 std::reverse (buf + ku, buf + ns);
01942 std::reverse (bufi + ku, bufi + ns);
01943 if (mode == DESCENDING)
01944 {
01945 std::rotate (buf, buf + ku, buf + ns);
01946 std::rotate (bufi, bufi + ku, bufi + ns);
01947 }
01948 }
01949
01950
01951 for (octave_idx_type i = 0; i < ns; i++)
01952 v[i*stride + offset] = buf[i];
01953 for (octave_idx_type i = 0; i < ns; i++)
01954 vi[i*stride + offset] = bufi[i];
01955 }
01956 }
01957
01958 return m;
01959 }
01960
01961 template <class T>
01962 typename Array<T>::compare_fcn_type
01963 safe_comparator (sortmode mode, const Array<T>& ,
01964 bool )
01965 {
01966 if (mode == ASCENDING)
01967 return octave_sort<T>::ascending_compare;
01968 else if (mode == DESCENDING)
01969 return octave_sort<T>::descending_compare;
01970 else
01971 return 0;
01972 }
01973
01974 template <class T>
01975 sortmode
01976 Array<T>::is_sorted (sortmode mode) const
01977 {
01978 octave_sort<T> lsort;
01979
01980 octave_idx_type n = numel ();
01981
01982 if (n <= 1)
01983 return mode ? mode : ASCENDING;
01984
01985 if (mode == UNSORTED)
01986 {
01987
01988 compare_fcn_type compare
01989 = safe_comparator (ASCENDING, *this, false);
01990
01991 if (compare (elem (n-1), elem (0)))
01992 mode = DESCENDING;
01993 else
01994 mode = ASCENDING;
01995 }
01996
01997 if (mode != UNSORTED)
01998 {
01999 lsort.set_compare (safe_comparator (mode, *this, false));
02000
02001 if (! lsort.is_sorted (data (), n))
02002 mode = UNSORTED;
02003 }
02004
02005 return mode;
02006
02007 }
02008
02009 template <class T>
02010 Array<octave_idx_type>
02011 Array<T>::sort_rows_idx (sortmode mode) const
02012 {
02013 Array<octave_idx_type> idx;
02014
02015 octave_sort<T> lsort (safe_comparator (mode, *this, true));
02016
02017 octave_idx_type r = rows (), c = cols ();
02018
02019 idx = Array<octave_idx_type> (dim_vector (r, 1));
02020
02021 lsort.sort_rows (data (), idx.fortran_vec (), r, c);
02022
02023 return idx;
02024 }
02025
02026
02027 template <class T>
02028 sortmode
02029 Array<T>::is_sorted_rows (sortmode mode) const
02030 {
02031 octave_sort<T> lsort;
02032
02033 octave_idx_type r = rows (), c = cols ();
02034
02035 if (r <= 1 || c == 0)
02036 return mode ? mode : ASCENDING;
02037
02038 if (mode == UNSORTED)
02039 {
02040
02041 compare_fcn_type compare
02042 = safe_comparator (ASCENDING, *this, false);
02043
02044 octave_idx_type i;
02045 for (i = 0; i < cols (); i++)
02046 {
02047 T l = elem (0, i), u = elem (rows () - 1, i);
02048 if (compare (l, u))
02049 {
02050 if (mode == DESCENDING)
02051 {
02052 mode = UNSORTED;
02053 break;
02054 }
02055 else
02056 mode = ASCENDING;
02057 }
02058 else if (compare (u, l))
02059 {
02060 if (mode == ASCENDING)
02061 {
02062 mode = UNSORTED;
02063 break;
02064 }
02065 else
02066 mode = DESCENDING;
02067 }
02068 }
02069 if (mode == UNSORTED && i == cols ())
02070 mode = ASCENDING;
02071 }
02072
02073 if (mode != UNSORTED)
02074 {
02075 lsort.set_compare (safe_comparator (mode, *this, false));
02076
02077 if (! lsort.is_sorted_rows (data (), r, c))
02078 mode = UNSORTED;
02079 }
02080
02081 return mode;
02082
02083 }
02084
02085
02086 template <class T>
02087 octave_idx_type
02088 Array<T>::lookup (const T& value, sortmode mode) const
02089 {
02090 octave_idx_type n = numel ();
02091 octave_sort<T> lsort;
02092
02093 if (mode == UNSORTED)
02094 {
02095
02096 if (n > 1 && lsort.descending_compare (elem (0), elem (n-1)))
02097 mode = DESCENDING;
02098 else
02099 mode = ASCENDING;
02100 }
02101
02102 lsort.set_compare (mode);
02103
02104 return lsort.lookup (data (), n, value);
02105 }
02106
02107 template <class T>
02108 Array<octave_idx_type>
02109 Array<T>::lookup (const Array<T>& values, sortmode mode) const
02110 {
02111 octave_idx_type n = numel (), nval = values.numel ();
02112 octave_sort<T> lsort;
02113 Array<octave_idx_type> idx (values.dims ());
02114
02115 if (mode == UNSORTED)
02116 {
02117
02118 if (n > 1 && lsort.descending_compare (elem (0), elem (n-1)))
02119 mode = DESCENDING;
02120 else
02121 mode = ASCENDING;
02122 }
02123
02124 lsort.set_compare (mode);
02125
02126
02127 static const double ratio = 1.0;
02128 sortmode vmode = UNSORTED;
02129
02130
02131 if (nval > ratio * n / xlog2 (n + 1.0))
02132 {
02133 vmode = values.is_sorted ();
02134
02135 if ((vmode == ASCENDING && sort_isnan<T> (values(nval-1)))
02136 || (vmode == DESCENDING && sort_isnan<T> (values(0))))
02137 vmode = UNSORTED;
02138 }
02139
02140 if (vmode != UNSORTED)
02141 lsort.lookup_sorted (data (), n, values.data (), nval,
02142 idx.fortran_vec (), vmode != mode);
02143 else
02144 lsort.lookup (data (), n, values.data (), nval, idx.fortran_vec ());
02145
02146 return idx;
02147 }
02148
02149 template <class T>
02150 octave_idx_type
02151 Array<T>::nnz (void) const
02152 {
02153 const T *src = data ();
02154 octave_idx_type nel = nelem (), retval = 0;
02155 const T zero = T ();
02156 for (octave_idx_type i = 0; i < nel; i++)
02157 if (src[i] != zero)
02158 retval++;
02159
02160 return retval;
02161 }
02162
02163 template <class T>
02164 Array<octave_idx_type>
02165 Array<T>::find (octave_idx_type n, bool backward) const
02166 {
02167 Array<octave_idx_type> retval;
02168 const T *src = data ();
02169 octave_idx_type nel = nelem ();
02170 const T zero = T ();
02171 if (n < 0 || n >= nel)
02172 {
02173
02174
02175 octave_idx_type cnt = 0;
02176 for (octave_idx_type i = 0; i < nel; i++)
02177 cnt += src[i] != zero;
02178
02179 retval.clear (cnt, 1);
02180 octave_idx_type *dest = retval.fortran_vec ();
02181 for (octave_idx_type i = 0; i < nel; i++)
02182 if (src[i] != zero) *dest++ = i;
02183 }
02184 else
02185 {
02186
02187
02188
02189 retval.clear (n, 1);
02190 if (backward)
02191 {
02192
02193 octave_idx_type k = 0, l = nel - 1;
02194 for (; k < n; k++)
02195 {
02196 for (;l >= 0 && src[l] == zero; l--) ;
02197 if (l >= 0)
02198 retval(k) = l--;
02199 else
02200 break;
02201 }
02202 if (k < n)
02203 retval.resize2 (k, 1);
02204 octave_idx_type *rdata = retval.fortran_vec ();
02205 std::reverse (rdata, rdata + k);
02206 }
02207 else
02208 {
02209
02210 octave_idx_type k = 0, l = 0;
02211 for (; k < n; k++)
02212 {
02213 for (;l != nel && src[l] == zero; l++) ;
02214 if (l != nel)
02215 retval(k) = l++;
02216 else
02217 break;
02218 }
02219 if (k < n)
02220 retval.resize2 (k, 1);
02221 }
02222 }
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233 if ((numel () == 1 && retval.is_empty ())
02234 || (rows () == 0 && dims ().numel (1) == 0))
02235 retval.dimensions = dim_vector ();
02236 else if (rows () == 1 && ndims () == 2)
02237 retval.dimensions = dim_vector (1, retval.length ());
02238
02239 return retval;
02240 }
02241
02242 template <class T>
02243 Array<T>
02244 Array<T>::nth_element (const idx_vector& n, int dim) const
02245 {
02246 if (dim < 0)
02247 {
02248 (*current_liboctave_error_handler)
02249 ("nth_element: invalid dimension");
02250 return Array<T> ();
02251 }
02252
02253 dim_vector dv = dims ();
02254 if (dim >= dv.length ())
02255 dv.resize (dim+1, 1);
02256
02257 octave_idx_type ns = dv(dim);
02258
02259 octave_idx_type nn = n.length (ns);
02260
02261 dv(dim) = std::min (nn, ns);
02262 dv.chop_trailing_singletons ();
02263 dim = std::min (dv.length (), dim);
02264
02265 Array<T> m (dv);
02266
02267 if (m.numel () == 0)
02268 return m;
02269
02270 sortmode mode = UNSORTED;
02271 octave_idx_type lo = 0;
02272
02273 switch (n.idx_class ())
02274 {
02275 case idx_vector::class_scalar:
02276 mode = ASCENDING;
02277 lo = n(0);
02278 break;
02279 case idx_vector::class_range:
02280 {
02281 octave_idx_type inc = n.increment ();
02282 if (inc == 1)
02283 {
02284 mode = ASCENDING;
02285 lo = n(0);
02286 }
02287 else if (inc == -1)
02288 {
02289 mode = DESCENDING;
02290 lo = ns - 1 - n(0);
02291 }
02292 }
02293 default:
02294 break;
02295 }
02296
02297 if (mode == UNSORTED)
02298 {
02299 (*current_liboctave_error_handler)
02300 ("nth_element: n must be a scalar or a contiguous range");
02301 return Array<T> ();
02302 }
02303
02304 octave_idx_type up = lo + nn;
02305
02306 if (lo < 0 || up > ns)
02307 {
02308 (*current_liboctave_error_handler)
02309 ("nth_element: invalid element index");
02310 return Array<T> ();
02311 }
02312
02313 octave_idx_type iter = numel () / ns;
02314 octave_idx_type stride = 1;
02315
02316 for (int i = 0; i < dim; i++)
02317 stride *= dv(i);
02318
02319 T *v = m.fortran_vec ();
02320 const T *ov = data ();
02321
02322 OCTAVE_LOCAL_BUFFER (T, buf, ns);
02323
02324 octave_sort<T> lsort;
02325 lsort.set_compare (mode);
02326
02327 for (octave_idx_type j = 0; j < iter; j++)
02328 {
02329 octave_idx_type kl = 0, ku = ns;
02330
02331 if (stride == 1)
02332 {
02333
02334
02335 for (octave_idx_type i = 0; i < ns; i++)
02336 {
02337 T tmp = ov[i];
02338 if (sort_isnan<T> (tmp))
02339 buf[--ku] = tmp;
02340 else
02341 buf[kl++] = tmp;
02342 }
02343
02344 ov += ns;
02345 }
02346 else
02347 {
02348 octave_idx_type offset = j % stride;
02349
02350
02351 for (octave_idx_type i = 0; i < ns; i++)
02352 {
02353 T tmp = ov[offset + i*stride];
02354 if (sort_isnan<T> (tmp))
02355 buf[--ku] = tmp;
02356 else
02357 buf[kl++] = tmp;
02358 }
02359
02360 if (offset == stride-1)
02361 ov += ns*stride;
02362 }
02363
02364 if (ku == ns)
02365 lsort.nth_element (buf, ns, lo, up);
02366 else if (mode == ASCENDING)
02367 lsort.nth_element (buf, ku, lo, std::min (ku, up));
02368 else
02369 {
02370 octave_idx_type nnan = ns - ku;
02371 octave_idx_type zero = 0;
02372 lsort.nth_element (buf, ku, std::max (lo - nnan, zero),
02373 std::max (up - nnan, zero));
02374 std::rotate (buf, buf + ku, buf + ns);
02375 }
02376
02377 if (stride == 1)
02378 {
02379 for (octave_idx_type i = 0; i < nn; i++)
02380 v[i] = buf[lo + i];
02381
02382 v += nn;
02383 }
02384 else
02385 {
02386 octave_idx_type offset = j % stride;
02387 for (octave_idx_type i = 0; i < nn; i++)
02388 v[offset + stride * i] = buf[lo + i];
02389 if (offset == stride-1)
02390 v += nn*stride;
02391 }
02392 }
02393
02394 return m;
02395 }
02396
02397
02398 #define INSTANTIATE_ARRAY_SORT(T) template class OCTAVE_API octave_sort<T>;
02399
02400 #define NO_INSTANTIATE_ARRAY_SORT(T) \
02401 \
02402 template <> Array<T> \
02403 Array<T>::sort (int, sortmode) const { return *this; } \
02404 \
02405 template <> Array<T> \
02406 Array<T>::sort (Array<octave_idx_type> &sidx, int, sortmode) const \
02407 { sidx = Array<octave_idx_type> (); return *this; } \
02408 \
02409 template <> sortmode \
02410 Array<T>::is_sorted (sortmode) const \
02411 { return UNSORTED; } \
02412 \
02413 Array<T>::compare_fcn_type \
02414 safe_comparator (sortmode, const Array<T>&, bool) \
02415 { return 0; } \
02416 \
02417 template <> Array<octave_idx_type> \
02418 Array<T>::sort_rows_idx (sortmode) const \
02419 { return Array<octave_idx_type> (); } \
02420 \
02421 template <> sortmode \
02422 Array<T>::is_sorted_rows (sortmode) const \
02423 { return UNSORTED; } \
02424 \
02425 template <> octave_idx_type \
02426 Array<T>::lookup (T const &, sortmode) const \
02427 { return 0; } \
02428 template <> Array<octave_idx_type> \
02429 Array<T>::lookup (const Array<T>&, sortmode) const \
02430 { return Array<octave_idx_type> (); } \
02431 \
02432 template <> octave_idx_type \
02433 Array<T>::nnz (void) const\
02434 { return 0; } \
02435 template <> Array<octave_idx_type> \
02436 Array<T>::find (octave_idx_type, bool) const\
02437 { return Array<octave_idx_type> (); } \
02438 \
02439 template <> Array<T> \
02440 Array<T>::nth_element (const idx_vector&, int) const { return Array<T> (); } \
02441
02442
02443 template <class T>
02444 Array<T>
02445 Array<T>::diag (octave_idx_type k) const
02446 {
02447 dim_vector dv = dims ();
02448 octave_idx_type nd = dv.length ();
02449 Array<T> d;
02450
02451 if (nd > 2)
02452 (*current_liboctave_error_handler) ("Matrix must be 2-dimensional");
02453 else
02454 {
02455 octave_idx_type nnr = dv (0);
02456 octave_idx_type nnc = dv (1);
02457
02458 if (nnr == 0 && nnc == 0)
02459 ;
02460 else if (nnr != 1 && nnc != 1)
02461 {
02462
02463 if (k > 0)
02464 nnc -= k;
02465 else if (k < 0)
02466 nnr += k;
02467
02468 if (nnr > 0 && nnc > 0)
02469 {
02470 octave_idx_type ndiag = (nnr < nnc) ? nnr : nnc;
02471
02472 d.resize (dim_vector (ndiag, 1));
02473
02474 if (k > 0)
02475 {
02476 for (octave_idx_type i = 0; i < ndiag; i++)
02477 d.xelem (i) = elem (i, i+k);
02478 }
02479 else if (k < 0)
02480 {
02481 for (octave_idx_type i = 0; i < ndiag; i++)
02482 d.xelem (i) = elem (i-k, i);
02483 }
02484 else
02485 {
02486 for (octave_idx_type i = 0; i < ndiag; i++)
02487 d.xelem (i) = elem (i, i);
02488 }
02489 }
02490 else
02491 (*current_liboctave_error_handler)
02492 ("diag: requested diagonal out of range");
02493 }
02494 else
02495 {
02496
02497 octave_idx_type roff = 0;
02498 octave_idx_type coff = 0;
02499 if (k > 0)
02500 {
02501 roff = 0;
02502 coff = k;
02503 }
02504 else if (k < 0)
02505 {
02506 roff = -k;
02507 coff = 0;
02508 }
02509
02510 if (nnr == 1)
02511 {
02512 octave_idx_type n = nnc + std::abs (k);
02513 d = Array<T> (dim_vector (n, n), resize_fill_value ());
02514
02515 for (octave_idx_type i = 0; i < nnc; i++)
02516 d.xelem (i+roff, i+coff) = elem (0, i);
02517 }
02518 else
02519 {
02520 octave_idx_type n = nnr + std::abs (k);
02521 d = Array<T> (dim_vector (n, n), resize_fill_value ());
02522
02523 for (octave_idx_type i = 0; i < nnr; i++)
02524 d.xelem (i+roff, i+coff) = elem (i, 0);
02525 }
02526 }
02527 }
02528
02529 return d;
02530 }
02531
02532 template <class T>
02533 Array<T>
02534 Array<T>::cat (int dim, octave_idx_type n, const Array<T> *array_list)
02535 {
02536
02537 bool (dim_vector::*concat_rule) (const dim_vector&, int) = &dim_vector::concat;
02538
02539 if (dim == -1 || dim == -2)
02540 {
02541 concat_rule = &dim_vector::hvcat;
02542 dim = -dim - 1;
02543 }
02544 else if (dim < 0)
02545 (*current_liboctave_error_handler)
02546 ("cat: invalid dimension");
02547
02548 if (n == 1)
02549 return array_list[0];
02550 else if (n == 0)
02551 return Array<T> ();
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574 octave_idx_type istart = 0;
02575
02576 if (n > 2 && dim > 1)
02577 {
02578 for (octave_idx_type i = 0; i < n; i++)
02579 {
02580 dim_vector dv = array_list[i].dims ();
02581
02582 if (dv.zero_by_zero ())
02583 istart++;
02584 else
02585 break;
02586 }
02587
02588
02589 if (istart >= n)
02590 istart = 0;
02591 }
02592
02593 dim_vector dv = array_list[istart++].dims ();
02594
02595 for (octave_idx_type i = istart; i < n; i++)
02596 if (! (dv.*concat_rule) (array_list[i].dims (), dim))
02597 (*current_liboctave_error_handler)
02598 ("cat: dimension mismatch");
02599
02600 Array<T> retval (dv);
02601
02602 if (retval.is_empty ())
02603 return retval;
02604
02605 int nidx = std::max (dv.length (), dim + 1);
02606 Array<idx_vector> idxa (dim_vector (nidx, 1), idx_vector::colon);
02607 octave_idx_type l = 0;
02608
02609 for (octave_idx_type i = 0; i < n; i++)
02610 {
02611
02612
02613
02614
02615
02616
02617 if (array_list[i].is_empty ())
02618 continue;
02619
02620 octave_quit ();
02621
02622 octave_idx_type u;
02623 if (dim < array_list[i].ndims ())
02624 u = l + array_list[i].dims ()(dim);
02625 else
02626 u = l + 1;
02627
02628 idxa(dim) = idx_vector (l, u);
02629
02630 retval.assign (idxa, array_list[i]);
02631
02632 l = u;
02633 }
02634
02635 return retval;
02636 }
02637
02638 template <class T>
02639 void
02640 Array<T>::print_info (std::ostream& os, const std::string& prefix) const
02641 {
02642 os << prefix << "rep address: " << rep << '\n'
02643 << prefix << "rep->len: " << rep->len << '\n'
02644 << prefix << "rep->data: " << static_cast<void *> (rep->data) << '\n'
02645 << prefix << "rep->count: " << rep->count << '\n'
02646 << prefix << "slice_data: " << static_cast<void *> (slice_data) << '\n'
02647 << prefix << "slice_len: " << slice_len << '\n';
02648
02649
02650
02651
02652
02653 }
02654
02655 template <class T>
02656 bool Array<T>::optimize_dimensions (const dim_vector& dv)
02657 {
02658 bool retval = dimensions == dv;
02659 if (retval)
02660 dimensions = dv;
02661
02662 return retval;
02663 }
02664
02665 template <class T>
02666 void Array<T>::instantiation_guard ()
02667 {
02668
02669
02670 T::__xXxXx__();
02671 }
02672
02673 #define INSTANTIATE_ARRAY(T, API) \
02674 template <> void Array<T>::instantiation_guard () { } \
02675 template class API Array<T>
02676
02677
02678
02679 template <class T>
02680 std::ostream&
02681 operator << (std::ostream& os, const Array<T>& a)
02682 {
02683 dim_vector a_dims = a.dims ();
02684
02685 int n_dims = a_dims.length ();
02686
02687 os << n_dims << "-dimensional array";
02688
02689 if (n_dims)
02690 os << " (" << a_dims.str () << ")";
02691
02692 os <<"\n\n";
02693
02694 if (n_dims)
02695 {
02696 os << "data:";
02697
02698 Array<octave_idx_type> ra_idx (dim_vector (n_dims, 1), 0);
02699
02700
02701
02702 octave_idx_type m = 1;
02703 for (int i = 2; i < n_dims; i++)
02704 m *= a_dims(i);
02705
02706 if (m == 1)
02707 {
02708 octave_idx_type rows = 0;
02709 octave_idx_type cols = 0;
02710
02711 switch (n_dims)
02712 {
02713 case 2:
02714 rows = a_dims(0);
02715 cols = a_dims(1);
02716
02717 for (octave_idx_type j = 0; j < rows; j++)
02718 {
02719 ra_idx(0) = j;
02720 for (octave_idx_type k = 0; k < cols; k++)
02721 {
02722 ra_idx(1) = k;
02723 os << " " << a.elem(ra_idx);
02724 }
02725 os << "\n";
02726 }
02727 break;
02728
02729 default:
02730 rows = a_dims(0);
02731
02732 for (octave_idx_type k = 0; k < rows; k++)
02733 {
02734 ra_idx(0) = k;
02735 os << " " << a.elem(ra_idx);
02736 }
02737 break;
02738 }
02739
02740 os << "\n";
02741 }
02742 else
02743 {
02744 octave_idx_type rows = a_dims(0);
02745 octave_idx_type cols = a_dims(1);
02746
02747 for (int i = 0; i < m; i++)
02748 {
02749 os << "\n(:,:,";
02750
02751 for (int j = 2; j < n_dims - 1; j++)
02752 os << ra_idx(j) + 1 << ",";
02753
02754 os << ra_idx(n_dims - 1) + 1 << ") = \n";
02755
02756 for (octave_idx_type j = 0; j < rows; j++)
02757 {
02758 ra_idx(0) = j;
02759
02760 for (octave_idx_type k = 0; k < cols; k++)
02761 {
02762 ra_idx(1) = k;
02763 os << " " << a.elem(ra_idx);
02764 }
02765
02766 os << "\n";
02767 }
02768
02769 os << "\n";
02770
02771 if (i != m - 1)
02772 increment_index (ra_idx, a_dims, 2);
02773 }
02774 }
02775 }
02776
02777 return os;
02778 }