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
find.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
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 "quit.h"
28 
29 #include "defun.h"
30 #include "error.h"
31 #include "errwarn.h"
32 #include "ovl.h"
33 
34 // Find at most N_TO_FIND nonzero elements in NDA. Search forward if
35 // DIRECTION is 1, backward if it is -1. NARGOUT is the number of
36 // output arguments. If N_TO_FIND is -1, find all nonzero elements.
37 
38 template <typename T>
41  octave_idx_type n_to_find, int direction)
42 {
43  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
44 
46  if (n_to_find >= 0)
47  idx = nda.find (n_to_find, direction == -1);
48  else
49  idx = nda.find ();
50 
51  // The maximum element is always at the end.
52  octave_idx_type iext = idx.is_empty () ? 0 : idx.xelem (idx.numel () - 1) + 1;
53 
54  switch (nargout)
55  {
56  default:
57  case 3:
58  retval(2) = Array<T> (nda.index (idx_vector (idx)));
59  // Fall through!
60 
61  case 2:
62  {
63  Array<octave_idx_type> jdx (idx.dims ());
64  octave_idx_type n = idx.numel ();
65  octave_idx_type nr = nda.rows ();
66  for (octave_idx_type i = 0; i < n; i++)
67  {
68  jdx.xelem (i) = idx.xelem (i) / nr;
69  idx.xelem (i) %= nr;
70  }
71  iext = -1;
72  retval(1) = idx_vector (jdx, -1);
73  }
74  // Fall through!
75 
76  case 1:
77  case 0:
78  retval(0) = idx_vector (idx, iext);
79  break;
80  }
81 
82  return retval;
83 }
84 
85 template <typename T>
88  octave_idx_type n_to_find, int direction)
89 {
90  nargout = std::min (nargout, 5);
91  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
92 
93  octave_idx_type nr = v.rows ();
94  octave_idx_type nc = v.cols ();
95  octave_idx_type nz = v.nnz ();
96 
97  // Search in the default range.
98  octave_idx_type start_nc = -1;
99  octave_idx_type end_nc = -1;
100  octave_idx_type count;
101 
102  // Search for the range to search
103  if (n_to_find < 0)
104  {
105  start_nc = 0;
106  end_nc = nc;
107  n_to_find = nz;
108  count = nz;
109  }
110  else if (direction > 0)
111  {
112  for (octave_idx_type j = 0; j < nc; j++)
113  {
114  OCTAVE_QUIT;
115  if (v.cidx (j) == 0 && v.cidx (j+1) != 0)
116  start_nc = j;
117  if (v.cidx (j+1) >= n_to_find)
118  {
119  end_nc = j + 1;
120  break;
121  }
122  }
123  }
124  else
125  {
126  for (octave_idx_type j = nc; j > 0; j--)
127  {
128  OCTAVE_QUIT;
129  if (v.cidx (j) == nz && v.cidx (j-1) != nz)
130  end_nc = j;
131  if (nz - v.cidx (j-1) >= n_to_find)
132  {
133  start_nc = j - 1;
134  break;
135  }
136  }
137  }
138 
139  count = (n_to_find > v.cidx (end_nc) - v.cidx (start_nc) ?
140  v.cidx (end_nc) - v.cidx (start_nc) : n_to_find);
141 
142  octave_idx_type result_nr;
143  octave_idx_type result_nc;
144 
145  // Default case is to return a column vector, however, if the original
146  // argument was a row vector, then force return of a row vector.
147  if (nr == 1)
148  {
149  result_nr = 1;
150  result_nc = count;
151  }
152  else
153  {
154  result_nr = count;
155  result_nc = 1;
156  }
157 
158  Matrix idx (result_nr, result_nc);
159 
160  Matrix i_idx (result_nr, result_nc);
161  Matrix j_idx (result_nr, result_nc);
162 
163  Array<T> val (dim_vector (result_nr, result_nc));
164 
165  if (count > 0)
166  {
167  // Search for elements to return. Only search the region where there
168  // are elements to be found using the count that we want to find.
169  for (octave_idx_type j = start_nc, cx = 0; j < end_nc; j++)
170  for (octave_idx_type i = v.cidx (j); i < v.cidx (j+1); i++)
171  {
172  OCTAVE_QUIT;
173  if (direction < 0 && i < nz - count)
174  continue;
175  i_idx(cx) = static_cast<double> (v.ridx (i) + 1);
176  j_idx(cx) = static_cast<double> (j + 1);
177  idx(cx) = j * nr + v.ridx (i) + 1;
178  val(cx) = v.data(i);
179  cx++;
180  if (cx == count)
181  break;
182  }
183  }
184  else
185  {
186  // No items found. Fixup return dimensions for Matlab compatibility.
187  // The behavior to match is documented in Array.cc (Array<T>::find).
188  if ((nr == 0 && nc == 0) || (nr == 1 && nc == 1))
189  {
190  idx.resize (0, 0);
191 
192  i_idx.resize (0, 0);
193  j_idx.resize (0, 0);
194 
195  val.resize (dim_vector (0, 0));
196  }
197  }
198 
199  switch (nargout)
200  {
201  case 0:
202  case 1:
203  retval(0) = idx;
204  break;
205 
206  case 5:
207  retval(4) = nc;
208  // Fall through
209 
210  case 4:
211  retval(3) = nr;
212  // Fall through
213 
214  case 3:
215  retval(2) = val;
216  // Fall through!
217 
218  case 2:
219  retval(1) = j_idx;
220  retval(0) = i_idx;
221  }
222 
223  return retval;
224 }
225 
228  octave_idx_type n_to_find, int direction)
229 {
230  // There are far fewer special cases to handle for a PermMatrix.
231  nargout = std::min (nargout, 5);
232  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
233 
234  octave_idx_type nr = v.rows ();
235  octave_idx_type nc = v.cols ();
236  octave_idx_type start_nc, count;
237 
238  // Determine the range to search.
239  if (n_to_find < 0 || n_to_find >= nc)
240  {
241  start_nc = 0;
242  count = nc;
243  }
244  else if (direction > 0)
245  {
246  start_nc = 0;
247  count = n_to_find;
248  }
249  else
250  {
251  start_nc = nc - n_to_find;
252  count = n_to_find;
253  }
254 
255  Matrix idx (count, 1);
256  Matrix i_idx (count, 1);
257  Matrix j_idx (count, 1);
258  // Every value is 1.
259  Array<double> val (dim_vector (count, 1), 1.0);
260 
261  if (count > 0)
262  {
263  const Array<octave_idx_type>& p = v.col_perm_vec ();
264  for (octave_idx_type k = 0; k < count; k++)
265  {
266  OCTAVE_QUIT;
267  const octave_idx_type j = start_nc + k;
268  const octave_idx_type i = p(j);
269  i_idx(k) = static_cast<double> (1+i);
270  j_idx(k) = static_cast<double> (1+j);
271  idx(k) = j * nc + i + 1;
272  }
273  }
274  else
275  {
276  // FIXME: Is this case even possible? A scalar permutation matrix seems
277  // to devolve to a scalar full matrix, at least from the Octave command
278  // line. Perhaps this function could be called internally from C++ with
279  // such a matrix.
280  // No items found. Fixup return dimensions for Matlab compatibility.
281  // The behavior to match is documented in Array.cc (Array<T>::find).
282  if ((nr == 0 && nc == 0) || (nr == 1 && nc == 1))
283  {
284  idx.resize (0, 0);
285 
286  i_idx.resize (0, 0);
287  j_idx.resize (0, 0);
288 
289  val.resize (dim_vector (0, 0));
290  }
291  }
292 
293  switch (nargout)
294  {
295  case 0:
296  case 1:
297  retval(0) = idx;
298  break;
299 
300  case 5:
301  retval(4) = nc;
302  // Fall through
303 
304  case 4:
305  retval(3) = nc;
306  // Fall through
307 
308  case 3:
309  retval(2) = val;
310  // Fall through!
311 
312  case 2:
313  retval(1) = j_idx;
314  retval(0) = i_idx;
315  }
316 
317  return retval;
318 }
319 
321  doc: /* -*- texinfo -*-
322 @deftypefn {} {@var{idx} =} find (@var{x})
323 @deftypefnx {} {@var{idx} =} find (@var{x}, @var{n})
324 @deftypefnx {} {@var{idx} =} find (@var{x}, @var{n}, @var{direction})
325 @deftypefnx {} {[i, j] =} find (@dots{})
326 @deftypefnx {} {[i, j, v] =} find (@dots{})
327 Return a vector of indices of nonzero elements of a matrix, as a row if
328 @var{x} is a row vector or as a column otherwise.
329 
330 To obtain a single index for each matrix element, Octave pretends that the
331 columns of a matrix form one long vector (like Fortran arrays are stored).
332 For example:
333 
334 @example
335 @group
336 find (eye (2))
337  @result{} [ 1; 4 ]
338 @end group
339 @end example
340 
341 If two inputs are given, @var{n} indicates the maximum number of elements to
342 find from the beginning of the matrix or vector.
343 
344 If three inputs are given, @var{direction} should be one of
345 @qcode{"first"} or @qcode{"last"}, requesting only the first or last
346 @var{n} indices, respectively. However, the indices are always returned in
347 ascending order.
348 
349 If two outputs are requested, @code{find} returns the row and column
350 indices of nonzero elements of a matrix. For example:
351 
352 @example
353 @group
354 [i, j] = find (2 * eye (2))
355  @result{} i = [ 1; 2 ]
356  @result{} j = [ 1; 2 ]
357 @end group
358 @end example
359 
360 If three outputs are requested, @code{find} also returns a vector
361 containing the nonzero values. For example:
362 
363 @example
364 @group
365 [i, j, v] = find (3 * eye (2))
366  @result{} i = [ 1; 2 ]
367  @result{} j = [ 1; 2 ]
368  @result{} v = [ 3; 3 ]
369 @end group
370 @end example
371 
372 Note that this function is particularly useful for sparse matrices, as
373 it extracts the nonzero elements as vectors, which can then be used to
374 create the original matrix. For example:
375 
376 @example
377 @group
378 sz = size (a);
379 [i, j, v] = find (a);
380 b = sparse (i, j, v, sz(1), sz(2));
381 @end group
382 @end example
383 @seealso{nonzeros}
384 @end deftypefn */)
385 {
386  int nargin = args.length ();
387 
388  if (nargin < 1 || nargin > 3)
389  print_usage ();
390 
391  // Setup the default options.
392  octave_idx_type n_to_find = -1;
393  if (nargin > 1)
394  {
395  double val = args(1).xscalar_value ("find: N must be an integer");
396 
397  if (val < 0 || (! octave::math::isinf (val)
398  && val != octave::math::round (val)))
399  error ("find: N must be a non-negative integer");
400  else if (! octave::math::isinf (val))
401  n_to_find = val;
402  }
403 
404  // Direction to do the searching (1 == forward, -1 == reverse).
405  int direction = 1;
406  if (nargin > 2)
407  {
408  direction = 0;
409 
410  std::string s_arg = args(2).string_value ();
411 
412  if (s_arg == "first")
413  direction = 1;
414  else if (s_arg == "last")
415  direction = -1;
416  else
417  error ("find: DIRECTION must be \"first\" or \"last\"");
418  }
419 
421 
422  octave_value arg = args(0);
423 
424  if (arg.is_bool_type ())
425  {
426  if (arg.is_sparse_type ())
427  {
429 
430  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
431  }
432  else if (nargout <= 1 && n_to_find == -1 && direction == 1)
433  {
434  // This case is equivalent to extracting indices from a logical
435  // matrix. Try to reuse the possibly cached index vector.
436 
437  // No need to catch index_exception, since arg is bool.
438  // Out-of-range errors have already set pos, and will be caught later.
439  retval(0) = arg.index_vector ().unmask ();
440  }
441  else
442  {
443  boolNDArray v = arg.bool_array_value ();
444 
445  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
446  }
447  }
448  else if (arg.is_integer_type ())
449  {
450 #define DO_INT_BRANCH(INTT) \
451  else if (arg.is_ ## INTT ## _type ()) \
452  { \
453  INTT ## NDArray v = arg.INTT ## _array_value (); \
454  \
455  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction); \
456  }
457 
458  if (false)
459  ;
460  DO_INT_BRANCH (int8)
464  DO_INT_BRANCH (uint8)
467  DO_INT_BRANCH (uint64)
468  else
469  panic_impossible ();
470  }
471  else if (arg.is_sparse_type ())
472  {
473  if (arg.is_real_type ())
474  {
476 
477  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
478  }
479  else if (arg.is_complex_type ())
480  {
482 
483  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
484  }
485  else
486  err_wrong_type_arg ("find", arg);
487  }
488  else if (arg.is_perm_matrix ())
489  {
490  PermMatrix P = arg.perm_matrix_value ();
491 
492  retval = find_nonzero_elem_idx (P, nargout, n_to_find, direction);
493  }
494  else if (arg.is_string ())
495  {
496  charNDArray chnda = arg.char_array_value ();
497 
498  retval = find_nonzero_elem_idx (chnda, nargout, n_to_find, direction);
499  }
500  else if (arg.is_single_type ())
501  {
502  if (arg.is_real_type ())
503  {
504  FloatNDArray nda = arg.float_array_value ();
505 
506  retval = find_nonzero_elem_idx (nda, nargout, n_to_find, direction);
507  }
508  else if (arg.is_complex_type ())
509  {
511 
512  retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
513  }
514  }
515  else if (arg.is_real_type ())
516  {
517  NDArray nda = arg.array_value ();
518 
519  retval = find_nonzero_elem_idx (nda, nargout, n_to_find, direction);
520  }
521  else if (arg.is_complex_type ())
522  {
523  ComplexNDArray cnda = arg.complex_array_value ();
524 
525  retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
526  }
527  else
528  err_wrong_type_arg ("find", arg);
529 
530  return retval;
531 }
532 
533 /*
534 %!assert (find (char ([0, 97])), 2)
535 %!assert (find ([1, 0, 1, 0, 1]), [1, 3, 5])
536 %!assert (find ([1; 0; 3; 0; 1]), [1; 3; 5])
537 %!assert (find ([0, 0, 2; 0, 3, 0; -1, 0, 0]), [3; 5; 7])
538 
539 %!test
540 %! [i, j, v] = find ([0, 0, 2; 0, 3, 0; -1, 0, 0]);
541 %!
542 %! assert (i, [3; 2; 1]);
543 %! assert (j, [1; 2; 3]);
544 %! assert (v, [-1; 3; 2]);
545 
546 %!assert (find (single ([1, 0, 1, 0, 1])), [1, 3, 5])
547 %!assert (find (single ([1; 0; 3; 0; 1])), [1; 3; 5])
548 %!assert (find (single ([0, 0, 2; 0, 3, 0; -1, 0, 0])), [3; 5; 7])
549 
550 %!test
551 %! [i, j, v] = find (single ([0, 0, 2; 0, 3, 0; -1, 0, 0]));
552 %!
553 %! assert (i, [3; 2; 1]);
554 %! assert (j, [1; 2; 3]);
555 %! assert (v, single ([-1; 3; 2]));
556 
557 %!test
558 %! pcol = [5 1 4 3 2];
559 %! P = eye (5) (:, pcol);
560 %! [i, j, v] = find (P);
561 %! [ifull, jfull, vfull] = find (full (P));
562 %! assert (i, ifull);
563 %! assert (j, jfull);
564 %! assert (all (v == 1));
565 
566 %!test
567 %! prow = [5 1 4 3 2];
568 %! P = eye (5) (prow, :);
569 %! [i, j, v] = find (P);
570 %! [ifull, jfull, vfull] = find (full (P));
571 %! assert (i, ifull);
572 %! assert (j, jfull);
573 %! assert (all (v == 1));
574 
575 %!assert (find ([2 0 1 0 5 0], 1), 1)
576 %!assert (find ([2 0 1 0 5 0], 2, "last"), [3, 5])
577 
578 %!assert (find ([2 0 1 0 5 0], Inf), [1, 3, 5])
579 %!assert (find ([2 0 1 0 5 0], Inf, "last"), [1, 3, 5])
580 
581 %!error find ()
582 */
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:812
bool is_empty(void) const
Definition: Array.h:575
octave_value_list find_nonzero_elem_idx(const Array< T > &nda, int nargout, octave_idx_type n_to_find, int direction)
Definition: find.cc:40
octave_idx_type cols(void) const
Definition: Sparse.h:272
charNDArray char_array_value(bool frc_str_conv=false) const
Definition: ov.h:831
bool is_real_type(void) const
Definition: ov.h:667
T * data(void)
Definition: Sparse.h:521
octave_idx_type rows(void) const
Definition: Sparse.h:271
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:145
octave_idx_type rows(void) const
Definition: PermMatrix.h:59
ar P
Definition: __luinc__.cc:49
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
OCTAVE_EXPORT octave_value_list uint16
Definition: ov.cc:1258
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
octave_idx_type cols(void) const
Definition: PermMatrix.h:60
for large enough k
Definition: lu.cc:606
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
bool is_perm_matrix(void) const
Definition: ov.h:575
octave_idx_type * cidx(void)
Definition: Sparse.h:543
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:825
octave_idx_type rows(void) const
Definition: Array.h:401
octave_value arg
Definition: pr-output.cc:3440
double round(double x)
Definition: lo-mappers.cc:333
octave_idx_type nnz(void) const
Actual number of nonzero terms.
Definition: Sparse.h:253
idx_vector index_vector(bool require_integers=false) const
Definition: ov.h:479
JNIEnv void * args
Definition: ov-java.cc:67
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:439
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:796
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 unmask(void) const
Definition: idx-vector.cc:1199
bool is_sparse_type(void) const
Definition: ov.h:682
bool is_bool_type(void) const
Definition: ov.h:661
OCTAVE_EXPORT octave_value_list uint32
Definition: ov.cc:1258
const Array< octave_idx_type > & col_perm_vec(void) const
Definition: PermMatrix.h:79
int nargin
Definition: graphics.cc:10115
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:816
bool is_string(void) const
Definition: ov.h:578
OCTAVE_EXPORT octave_value_list int16
Definition: ov.cc:1302
SparseBoolMatrix sparse_bool_matrix_value(bool warn=false) const
Definition: ov.h:841
bool is_complex_type(void) const
Definition: ov.h:670
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1028
octave_value retval
Definition: data.cc:6294
#define panic_impossible()
Definition: error.h:40
OCTAVE_EXPORT octave_value_list int32
Definition: ov.cc:1258
Definition: dMatrix.h:37
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:838
#define DO_INT_BRANCH(INTT)
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:156
bool isinf(double x)
Definition: lo-mappers.cc:387
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:112
T & xelem(octave_idx_type n)
Definition: Array.h:455
OCTAVE_EXPORT octave_value_list int64
Definition: ov.cc:1258
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:126
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:793
octave_idx_type * ridx(void)
Definition: Sparse.h:530
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
Array< octave_idx_type > find(octave_idx_type n=-1, bool backward=false) const
Find indices of (at most n) nonzero elements.
Definition: Array.cc:2246
PermMatrix perm_matrix_value(void) const
Definition: ov.h:857
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:834
bool is_single_type(void) const
Definition: ov.h:627
#define OCTAVE_QUIT
Definition: quit.h:212
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
Array< T > index(const idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:718
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:205
bool is_integer_type(void) const
Definition: ov.h:664