diff --git a/liboctave/array/Array.cc b/liboctave/array/Array.cc --- a/liboctave/array/Array.cc +++ b/liboctave/array/Array.cc @@ -717,6 +717,30 @@ template Array Array::index (const idx_vector& i) const { + // Colon: + // + // object | index | result orientation + // ---------+----------+------------------- + // anything | colon | column vector + // + // Logical (mask): + // + // object | index | result orientation + // ---------+----------+------------------- + // vector | anything | indexed object + // ---------+----------+------------------- + // array | vector | index + // | other | column vector + // + // Numeric: + // + // object | index | result orientation + // ---------+----------+------------------- + // vector | vector | indexed object + // | other | same size as index + // ---------+----------+------------------- + // array | anything | same size as index + octave_idx_type n = numel (); Array retval; @@ -730,46 +754,74 @@ Array::index (const idx_vector& i) co if (i.extent (n) != n) octave::err_index_out_of_range (1, 1, i.extent (n), n, dimensions); // throws - // FIXME: this is the only place where orig_dimensions are used. - dim_vector rd = i.orig_dimensions (); - octave_idx_type il = i.length (n); - - // FIXME: this is for Matlab compatibility. Matlab 2007 given - // - // b = ones (3,1) - // - // yields the following: - // - // b(zeros (0,0)) gives [] - // b(zeros (1,0)) gives zeros (0,1) - // b(zeros (0,1)) gives zeros (0,1) - // b(zeros (0,m)) gives zeros (0,m) - // b(zeros (m,0)) gives zeros (m,0) - // b(1:2) gives ones (2,1) - // b(ones (2)) gives ones (2) etc. - // - // As you can see, the behavior is weird, but the tests end up pretty - // simple. Nah, I don't want to suggest that this is ad hoc :) - - if (ndims () == 2 && n != 1 && rd.is_vector ()) + dim_vector result_dims; + octave_idx_type idx_len = i.length (); + + if (i.is_logical_index ()) { - if (columns () == 1) - rd = dim_vector (il, 1); - else if (rows () == 1) - rd = dim_vector (1, il); + result_dims = i.orig_mask_dims (); + + if (n != 1 && is_nd_vector ()) + { + // result is vector oriented as indexed object + + dim_vector dv = dims (); + + int nd = dv.ndims (); + int dim = dv.first_non_singleton (); + + result_dims = dim_vector::make_nd_vector (nd, dim, idx_len); + } + else + { + if (idx_len != 1 && result_dims.is_nd_vector ()) + { + // result is vector oriented as index + + int nd = result_dims.ndims (); + int dim = result_dims.first_non_singleton (); + + result_dims = dim_vector::make_nd_vector (nd, dim, idx_len); + } + else + { + // result is column vector + + result_dims = dim_vector (idx_len, 1); + } + } + } + else + { + result_dims = i.orig_dimensions (); + + if (n != 1 && is_nd_vector ()) + { + if (idx_len != 1 && result_dims.is_nd_vector ()) + { + // result is vector oriented as indexed object + + dim_vector dv = dims (); + + int nd = dv.ndims (); + int dim = dv.first_non_singleton (); + + result_dims = dim_vector::make_nd_vector (nd, dim, idx_len); + } + } } octave_idx_type l, u; - if (il != 0 && i.is_cont_range (n, l, u)) + if (idx_len != 0 && i.is_cont_range (n, l, u)) // If suitable, produce a shallow slice. - retval = Array (*this, rd, l, u); + retval = Array (*this, result_dims, l, u); else { // Don't use resize here to avoid useless initialization for POD // types. - retval = Array (rd); - - if (il != 0) + retval = Array (result_dims); + + if (idx_len != 0) i.index (data (), n, retval.fortran_vec ()); } } diff --git a/liboctave/array/Array.h b/liboctave/array/Array.h --- a/liboctave/array/Array.h +++ b/liboctave/array/Array.h @@ -576,6 +576,8 @@ public: bool is_vector (void) const { return dimensions.is_vector (); } + bool is_nd_vector (void) const { return dimensions.is_nd_vector (); } + Array transpose (void) const; Array hermitian (T (*fcn) (const T&) = 0) const; diff --git a/liboctave/array/dim-vector.h b/liboctave/array/dim-vector.h --- a/liboctave/array/dim-vector.h +++ b/liboctave/array/dim-vector.h @@ -459,6 +459,39 @@ public: return (ndims () == 2 && (elem (0) == 1 || elem (1) == 1)); } + bool is_nd_vector (void) const + { + int num_non_one = 0; + + for (int i = 0; i < ndims (); i++) + { + if (elem (i) != 1) + num_non_one++; + } + + return num_non_one == 1; + } + + static dim_vector make_nd_vector (int n_dims, int dim, octave_idx_type n) + { + if (dim >= n_dims) + (*current_liboctave_error_handler) + ("dim_vector::make_nd_vector: dim >= ndims"); + + if (n < 0) + (*current_liboctave_error_handler) + ("dim_vector::make_nd_vector: n < 0"); + + dim_vector retval = alloc (n_dims); + + for (int i = 0; i < n_dims; i++) + retval.elem (i) = 1; + + retval.elem (dim) = n; + + return retval; + } + int first_non_singleton (int def = 0) const { for (int i = 0; i < ndims (); i++) diff --git a/liboctave/array/idx-vector.cc b/liboctave/array/idx-vector.cc --- a/liboctave/array/idx-vector.cc +++ b/liboctave/array/idx-vector.cc @@ -390,6 +390,8 @@ idx_vector::idx_vector_rep::idx_vector_r const dim_vector dv = bnda.dims (); + set_orig_mask_dims (dv); + if (! dv.all_zero ()) orig_dims = ((dv.ndims () == 2 && dv(0) == 1) ? dim_vector (1, len) : dim_vector (len, 1)); @@ -416,6 +418,8 @@ idx_vector::idx_vector_rep::idx_vector_r { const dim_vector dv = bnda.dims (); + set_orig_mask_dims (dv); + if (! dv.all_zero ()) orig_dims = ((dv.ndims () == 2 && dv(0) == 1) ? dim_vector (1, len) : dim_vector (len, 1)); @@ -661,6 +665,8 @@ idx_vector::idx_mask_rep::idx_mask_rep ( const dim_vector dv = bnda.dims (); + set_orig_mask_dims (dv); + if (! dv.all_zero ()) orig_dims = ((dv.ndims () == 2 && dv(0) == 1) ? dim_vector (1, len) : dim_vector (len, 1)); diff --git a/liboctave/array/idx-vector.h b/liboctave/array/idx-vector.h --- a/liboctave/array/idx-vector.h +++ b/liboctave/array/idx-vector.h @@ -72,7 +72,9 @@ private: class OCTAVE_API idx_base_rep { public: - idx_base_rep (void) : count (1), err (false) { } + idx_base_rep (void) + : count (1), orig_mask_dv (), logical_idx (false), err (false) + { } // No copying! @@ -113,8 +115,20 @@ private: virtual Array as_array (void); + dim_vector orig_mask_dims (void) const { return orig_mask_dv; } + + void set_orig_mask_dims (const dim_vector& dv) + { + orig_mask_dv = dv; + logical_idx = true; + } + + bool is_logical_index (void) const { return logical_idx; } + octave::refcount count; + dim_vector orig_mask_dv; + bool logical_idx; bool err; }; @@ -1044,6 +1058,10 @@ public: octave_idx_type max (void) const { return extent (1) - 1; } + dim_vector orig_mask_dims (void) const { return rep->orig_mask_dims (); } + + bool is_logical_index (void) const { return rep->is_logical_index (); } + private: idx_base_rep *rep;