GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
sub2ind.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2009-2018 VZLU Prague
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include "Array-util.h"
28 #include "oct-locbuf.h"
29 #include "quit.h"
30 
31 #include "defun.h"
32 #include "error.h"
33 #include "errwarn.h"
34 #include "ovl.h"
35 
36 
37 static dim_vector
38 get_dim_vector (const octave_value& val, const char *name)
39 {
40  RowVector dimsv = val.row_vector_value (false, true);
41  dim_vector dv;
42  octave_idx_type n = dimsv.numel ();
43 
44  if (n < 1)
45  error ("%s: dimension vector DIMS must not be empty", name);
46 
47  dv.resize (std::max (n, static_cast<octave_idx_type> (2)));
48  dv(1) = 1;
49  for (octave_idx_type i = 0; i < n; i++)
50  {
51  octave_idx_type ii = dimsv(i);
52  if (ii == dimsv(i) && ii >= 0)
53  dv(i) = ii;
54  else
55  error ("%s: dimension vector DIMS must contain integers", name);
56  }
57 
58  return dv;
59 }
60 
61 DEFUN (sub2ind, args, ,
62  doc: /* -*- texinfo -*-
63 @deftypefn {} {@var{ind} =} sub2ind (@var{dims}, @var{i}, @var{j})
64 @deftypefnx {} {@var{ind} =} sub2ind (@var{dims}, @var{s1}, @var{s2}, @dots{}, @var{sN})
65 Convert subscripts to linear indices.
66 
67 The input @var{dims} is a dimension vector where each element is the size of
68 the array in the respective dimension (@pxref{XREFsize,,size}). The remaining
69 inputs are scalars or vectors of subscripts to be converted.
70 
71 The output vector @var{ind} contains the converted linear indices.
72 
73 Background: Array elements can be specified either by a linear index which
74 starts at 1 and runs through the number of elements in the array, or they may
75 be specified with subscripts for the row, column, page, etc. The functions
76 @code{ind2sub} and @code{sub2ind} interconvert between the two forms.
77 
78 The linear index traverses dimension 1 (rows), then dimension 2 (columns), then
79 dimension 3 (pages), etc.@: until it has numbered all of the elements.
80 Consider the following 3-by-3 matrices:
81 
82 @example
83 @group
84 [(1,1), (1,2), (1,3)] [1, 4, 7]
85 [(2,1), (2,2), (2,3)] ==> [2, 5, 8]
86 [(3,1), (3,2), (3,3)] [3, 6, 9]
87 @end group
88 @end example
89 
90 @noindent
91 The left matrix contains the subscript tuples for each matrix element. The
92 right matrix shows the linear indices for the same matrix.
93 
94 The following example shows how to convert the two-dimensional indices
95 @code{(2,1)} and @code{(2,3)} of a 3-by-3 matrix to linear indices with a
96 single call to @code{sub2ind}.
97 
98 @example
99 @group
100 s1 = [2, 2];
101 s2 = [1, 3];
102 ind = sub2ind ([3, 3], s1, s2)
103  @result{} ind = 2 8
104 @end group
105 @end example
106 @seealso{ind2sub, size}
107 @end deftypefn */)
108 {
109  int nargin = args.length ();
110 
111  if (nargin < 2)
112  print_usage ();
113 
114  dim_vector dv = get_dim_vector (args(0), "sub2ind").redim (nargin - 1);
115  Array<idx_vector> idxa (dim_vector (nargin-1, 1));
116 
117  for (int j = 0; j < nargin - 1; j++)
118  {
119  if (! args(j+1).isnumeric ())
120  error ("sub2ind: subscripts must be numeric");
121 
122  try
123  {
124  idxa(j) = args(j+1).index_vector ();
125 
126  if (j > 0 && args(j+1).dims () != args(1).dims ())
127  error ("sub2ind: all subscripts must be of the same size");
128  }
129  catch (octave::index_exception& e)
130  {
131  e.set_pos_if_unset (nargin-1, j+1);
132  e.set_var ();
133  std::string msg = e.message ();
134  error_with_id (e.err_id (), msg.c_str ());
135  }
136  }
137 
138  return ovl (sub2ind (dv, idxa));
139 }
140 
141 /*
142 ## Test evaluation
143 %!test
144 %! s1 = [ 1 1 1 1 ; 2 2 2 2 ];
145 %! s2 = [ 1 1 2 2 ; 1 1 2 2 ];
146 %! s3 = [ 1 2 1 2 ; 1 2 1 2 ];
147 %! in = [ 1 101 11 111 ; 2 102 12 112 ];
148 %! assert (sub2ind ([10 10 10], s1, s2, s3), in);
149 
150 # Test low index
151 %!assert (sub2ind ([10 10 10], 1, 1, 1), 1)
152 %!error <index \(0,_,_\)> sub2ind ([10 10 10], 0, 1, 1)
153 %!error <index \(_,0,_\)> sub2ind ([10 10 10], 1, 0, 1)
154 %!error <index \(_,_,0\)> sub2ind ([10 10 10], 1, 1, 0)
155 
156 # Test high index
157 %!assert (sub2ind ([10 10 10], 10, 10, 10), 1000)
158 %!error <index \(11,_,_\): out of bound 10> sub2ind ([10 10 10], 11, 10, 10)
159 %!error <index \(_,11,_\): out of bound 10> sub2ind ([10 10 10], 10, 11, 10)
160 %!error <index \(_,_,11\): out of bound 10> sub2ind ([10 10 10], 10, 10, 11)
161 
162 # Test high index in the trailing dimensions
163 %!assert (sub2ind ([10, 1], 2, 1, 1), 2)
164 %!error <index \(_,2,_\): out of bound 1> sub2ind ([10, 1], 1, 2, 1)
165 %!error <index \(_,_,2\): out of bound 1> sub2ind ([10, 1], 1, 1, 2)
166 %!assert (sub2ind ([10 10], 2, 2, 1), 12)
167 %!error <index \(_,_,2\): out of bound 1> sub2ind ([10 10], 2, 1, 2)
168 %!error <index \(_,_,2\): out of bound 1> sub2ind ([10 10], 1, 2, 2)
169 
170 # Test handling of empty arguments
171 %!assert (sub2ind ([10 10], zeros (0,0), zeros (0,0)), zeros (0,0))
172 %!assert (sub2ind ([10 10], zeros (2,0), zeros (2,0)), zeros (2,0))
173 %!assert (sub2ind ([10 10], zeros (0,2), zeros (0,2)), zeros (0,2))
174 %!error <all subscripts .* same size> sub2ind ([10 10 10], zeros (0,2), zeros (2,0))
175 
176 # Test handling of arguments of different size
177 %!error <all subscripts .* same size> sub2ind ([10 10], ones (1,2), ones (1,3))
178 %!error <all subscripts .* same size> sub2ind ([10 10], ones (1,2), ones (2,1))
179 
180 ## Test input validation
181 %!error <dimension vector> sub2ind ([10 10.5], 1, 1)
182 %!error <index \(1.5,_\)> sub2ind ([10 10], 1.5, 1)
183 %!error <index \(_,1.5\)> sub2ind ([10 10], 1, 1.5)
184 */
185 
186 DEFUN (ind2sub, args, nargout,
187  doc: /* -*- texinfo -*-
188 @deftypefn {} {[@var{s1}, @var{s2}, @dots{}, @var{sN}] =} ind2sub (@var{dims}, @var{ind})
189 Convert linear indices to subscripts.
190 
191 The input @var{dims} is a dimension vector where each element is the size of
192 the array in the respective dimension (@pxref{XREFsize,,size}). The second
193 input @var{ind} contains linear indies to be converted.
194 
195 The outputs @var{s1}, @dots{}, @var{sN} contain the converted subscripts.
196 
197 Background: Array elements can be specified either by a linear index which
198 starts at 1 and runs through the number of elements in the array, or they may
199 be specified with subscripts for the row, column, page, etc. The functions
200 @code{ind2sub} and @code{sub2ind} interconvert between the two forms.
201 
202 The linear index traverses dimension 1 (rows), then dimension 2 (columns), then
203 dimension 3 (pages), etc.@: until it has numbered all of the elements.
204 Consider the following 3-by-3 matrices:
205 
206 @example
207 @group
208 [1, 4, 7] [(1,1), (1,2), (1,3)]
209 [2, 5, 8] ==> [(2,1), (2,2), (2,3)]
210 [3, 6, 9] [(3,1), (3,2), (3,3)]
211 @end group
212 @end example
213 
214 @noindent
215 The left matrix contains the linear indices for each matrix element. The right
216 matrix shows the subscript tuples for the same matrix.
217 
218 The following example shows how to convert the two-dimensional indices
219 @code{(2,1)} and @code{(2,3)} of a 3-by-3 matrix to linear indices with a
220 single call to @code{sub2ind}.
221 
222 The following example shows how to convert the linear indices @code{2} and
223 @code{8} in a 3-by-3 matrix into subscripts.
224 
225 @example
226 @group
227 ind = [2, 8];
228 [r, c] = ind2sub ([3, 3], ind)
229  @result{} r = 2 2
230  @result{} c = 1 3
231 @end group
232 @end example
233 
234 If the number of output subscripts exceeds the number of dimensions, the
235 exceeded dimensions are set to @code{1}. On the other hand, if fewer
236 subscripts than dimensions are provided, the exceeding dimensions are merged
237 into the final requested dimension. For clarity, consider the following
238 examples:
239 
240 @example
241 @group
242 ind = [2, 8];
243 dims = [3, 3];
244 ## same as dims = [3, 3, 1]
245 [r, c, s] = ind2sub (dims, ind)
246  @result{} r = 2 2
247  @result{} c = 1 3
248  @result{} s = 1 1
249 ## same as dims = [9]
250 r = ind2sub (dims, ind)
251  @result{} r = 2 8
252 @end group
253 @end example
254 @seealso{ind2sub, size}
255 @end deftypefn */)
256 {
257  if (args.length () != 2)
258  print_usage ();
259 
261 
262  // Redimension to provided number of subscripts.
263  dim_vector dv = get_dim_vector (args(0), "ind2sub").redim (nargout);
264 
265  try
266  {
268  }
269  catch (const octave::index_exception& e)
270  {
271  error ("ind2sub: Invalid index %s. %s", e.idx ().c_str (),
272  e.details ().c_str ());
273  }
274 
275  return retval;
276 }
277 
278 /*
279 ## Examples
280 %!test
281 %! [r, c] = ind2sub ([3, 3], [2, 8]);
282 %! assert (r, [2, 2]);
283 %! assert (c, [1, 3]);
284 
285 %!test
286 %! [r, c, s] = ind2sub ([3, 3], [2, 8]);
287 %! assert (r, [2, 2]);
288 %! assert (c, [1, 3]);
289 %! assert (s, [1, 1]);
290 %! [r, c, s] = ind2sub ([3, 3, 1], [2, 8]);
291 %! assert (r, [2, 2]);
292 %! assert (c, [1, 3]);
293 %! assert (s, [1, 1]);
294 
295 %!test
296 %! r = ind2sub ([3, 3], [2, 8]);
297 %! assert (r, [2, 8]);
298 %! r = ind2sub (9, [2, 8]);
299 %! assert (r, [2, 8]);
300 
301 ## 3-dimensional test
302 %!test
303 %! [r, c, s] = ind2sub ([2, 2, 2], 1:8);
304 %! assert (r, [1, 2, 1, 2, 1, 2, 1, 2]);
305 %! assert (c, [1, 1, 2, 2, 1, 1, 2, 2]);
306 %! assert (s, [1, 1, 1, 1, 2, 2, 2, 2]);
307 %! [r, c] = ind2sub ([2, 2, 2], 1:8);
308 %! assert (r, [1, 2, 1, 2, 1, 2, 1, 2]);
309 %! assert (c, [1, 1, 2, 2, 3, 3, 4, 4]);
310 %! r = ind2sub ([2, 2, 2], 1:8);
311 %! assert (r, 1:8);
312 
313 %!error <DIMS must contain integers> ind2sub ([2, -2], 3);
314 %!error <index out of range> ind2sub ([2, 2, 2], 1:9);
315 %!error <Invalid index> ind2sub ([2, 2, 2], -1:8);
316 */
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
idx_vector index_vector(bool require_integers=false) const
Definition: ov.h:462
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
void resize(int n, int fill_value=0)
Definition: dim-vector.h:310
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
void error(const char *fmt,...)
Definition: error.cc:578
i e
Definition: data.cc:2591
OCTAVE_EXPORT octave_value_list isnumeric
Definition: data.cc:3157
static dim_vector get_dim_vector(const octave_value &val, const char *name)
Definition: sub2ind.cc:38
nd deftypefn *std::string name
Definition: sysdep.cc:647
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:997
idx_vector sub2ind(const dim_vector &dv, const Array< idx_vector > &idxa)
Definition: Array-util.cc:533
void error_with_id(const char *id, const char *fmt,...)
Definition: error.cc:623
octave_value_list retval
Definition: sub2ind.cc:256
the exceeded dimensions are set to if fewer subscripts than dimensions are the exceeding dimensions are merged into the final requested dimension For consider the following dims
Definition: sub2ind.cc:255
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:233
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:125
Array< idx_vector > ind2sub(const dim_vector &dv, const idx_vector &idx)
Definition: Array-util.cc:618
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
dim_vector dv
Definition: sub2ind.cc:263