GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
sub2ind.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2009-2017 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 the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 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 <http://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. Consider
80 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).is_numeric_type ())
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 
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. Consider
204 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.
264 
265  try
266  {
267  retval = Array<octave_value> (ind2sub (dv, args(1).index_vector ()));
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 */
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
void set_pos_if_unset(octave_idx_type nd_arg, octave_idx_type dim_arg)
bool is_numeric_type(void) const
Definition: ov.h:679
void resize(int n, int fill_value=0)
Definition: dim-vector.h:316
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
std::string idx(void) const
i e
Definition: data.cc:2724
virtual std::string message(void) const
static dim_vector get_dim_vector(const octave_value &val, const char *name)
Definition: sub2ind.cc:38
void set_var(const std::string &var_arg="")
idx_vector index_vector(bool require_integers=false) const
Definition: ov.h:479
JNIEnv void * args
Definition: ov-java.cc:67
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
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:935
idx_vector sub2ind(const dim_vector &dv, const Array< idx_vector > &idxa)
Definition: Array-util.cc:534
virtual const char * err_id(void) const =0
void error_with_id(const char *id, const char *fmt,...)
Definition: error.cc:615
octave_value_list retval
Definition: sub2ind.cc:256
int nargin
Definition: graphics.cc:10115
dim_vector redim(int n) const
Definition: dim-vector.cc:275
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
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:126
Array< idx_vector > ind2sub(const dim_vector &dv, const idx_vector &idx)
Definition: Array-util.cc:619
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
RowVector row_vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
Definition: ov.cc:1782
virtual std::string details(void) const =0
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:854
dim_vector dv
Definition: sub2ind.cc:263