Mercurial > octave
changeset 30902:972959edc3ff
Allow sub2ind() to accept indices outside the size of the input subscripts (bug #62184)
* NEWS.8.md: Announce change in Matlab Compatibility section.
* sub2ind.cc: Add '#include "utility"' for access to std::swap.
* sub2ind.cc (Fsub2ind): Check nargout to figure out ndims of output.
For special case of vector (1-dimension), put in code to guarantee a
row vector output. Add BIST tests for bug #62184. Remove input
validation BIST which no longer applies.
* Array-util.cc (ind2sub): Remove input validation requiring index to
be within range of subscript size. Adjust code to put all remaining
elements in the final output dimension.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 05 Apr 2022 15:12:34 -0700 |
parents | f6c74e01e294 |
children | 062e00e903a5 |
files | etc/NEWS.8.md libinterp/corefcn/sub2ind.cc liboctave/array/Array-util.cc |
diffstat | 3 files changed, 31 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/etc/NEWS.8.md Tue Apr 05 13:54:18 2022 -0700 +++ b/etc/NEWS.8.md Tue Apr 05 15:12:34 2022 -0700 @@ -17,6 +17,9 @@ ### Matlab compatibility +- `sub2ind` now supports index values outside of the size specified by + the subscripts. + - `cylinder` now accepts a scalar for the radius argument. - `clock` now has an optional second output `ISDST` which indicates if
--- a/libinterp/corefcn/sub2ind.cc Tue Apr 05 13:54:18 2022 -0700 +++ b/libinterp/corefcn/sub2ind.cc Tue Apr 05 15:12:34 2022 -0700 @@ -27,6 +27,8 @@ # include "config.h" #endif +#include <utility> + #include "Array-util.h" #include "oct-locbuf.h" #include "quit.h" @@ -260,12 +262,20 @@ octave_value_list retval; - // Redimension to provided number of subscripts. + int nd = (nargout == 0) ? 1 : nargout; + dim_vector dv = get_dim_vector (args(0), "ind2sub").redim (nargout); + // Redim for 1 will give us a column vector but we want a row vector. + if (nd == 1) + std::swap (dv(0), dv(1)); + try { retval = Array<octave_value> (ind2sub (dv, args(1).index_vector ())); + + if (nd == 1) + retval(0) = retval(1); } catch (const index_exception& ie) { @@ -310,8 +320,18 @@ %! r = ind2sub ([2, 2, 2], 1:8); %! assert (r, 1:8); +## Indexing beyond specified size (bug #62184) +%!assert <*62184> (ind2sub (1, 2), 2) +%!assert <*62184> (ind2sub ([3,3], 10), 10) +%!test <*62184> +%! [r,c] = ind2sub ([3,3], 10); +%! assert ([r, c], [1, 4]); +%!test <*62184> +%! [r,c,p] = ind2sub ([3,3], 10); +%! assert ([r, c, p], [1, 1, 2]); + +## Test input validation %!error <DIMS must contain integers> ind2sub ([2, -2], 3) -%!error <index out of range> ind2sub ([2, 2, 2], 1:9) %!error <invalid index> ind2sub ([2, 2, 2], -1:8) */
--- a/liboctave/array/Array-util.cc Tue Apr 05 13:54:18 2022 -0700 +++ b/liboctave/array/Array-util.cc Tue Apr 05 15:12:34 2022 -0700 @@ -623,17 +623,16 @@ Array<octave::idx_vector> retval (dim_vector (n, 1)); octave_idx_type numel = dv.numel (); - if (idx.extent (numel) > numel) - (*current_liboctave_error_handler) ("ind2sub: index out of range"); - if (idx.is_scalar ()) { octave_idx_type k = idx(0); - for (octave_idx_type j = 0; j < n; j++) + for (octave_idx_type j = 0; j < n-1; j++) { retval(j) = k % dv(j); k /= dv(j); } + + retval(n-1) = idx(0) < numel ? k % dv(n-1) : k; } else { @@ -646,11 +645,13 @@ for (octave_idx_type i = 0; i < len; i++) { octave_idx_type k = idx(i); - for (octave_idx_type j = 0; j < n; j++) + for (octave_idx_type j = 0; j < n-1; j++) { rdata[j](i) = k % dv(j); k /= dv(j); } + + rdata[n-1](i) = idx(i) < numel ? k % dv(n-1) : k; } for (octave_idx_type j = 0; j < n; j++)