# HG changeset patch # User John W. Eaton # Date 1649196754 25200 # Node ID 972959edc3ffe65b89f1d49bc1737d361947e764 # Parent f6c74e01e294520f73577b56e15baa9645f4edf7 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. diff -r f6c74e01e294 -r 972959edc3ff etc/NEWS.8.md --- 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 diff -r f6c74e01e294 -r 972959edc3ff libinterp/corefcn/sub2ind.cc --- 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 + #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 (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 ind2sub ([2, -2], 3) -%!error ind2sub ([2, 2, 2], 1:9) %!error ind2sub ([2, 2, 2], -1:8) */ diff -r f6c74e01e294 -r 972959edc3ff liboctave/array/Array-util.cc --- 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 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++)