GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
find.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 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
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 "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.isempty () ? 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  OCTAVE_FALLTHROUGH;
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  OCTAVE_FALLTHROUGH;
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 
116  if (v.cidx (j) == 0 && v.cidx (j+1) != 0)
117  start_nc = j;
118  if (v.cidx (j+1) >= n_to_find)
119  {
120  end_nc = j + 1;
121  break;
122  }
123  }
124  }
125  else
126  {
127  for (octave_idx_type j = nc; j > 0; j--)
128  {
129  octave_quit ();
130 
131  if (v.cidx (j) == nz && v.cidx (j-1) != nz)
132  end_nc = j;
133  if (nz - v.cidx (j-1) >= n_to_find)
134  {
135  start_nc = j - 1;
136  break;
137  }
138  }
139  }
140 
141  count = (n_to_find > v.cidx (end_nc) - v.cidx (start_nc) ?
142  v.cidx (end_nc) - v.cidx (start_nc) : n_to_find);
143 
144  octave_idx_type result_nr;
145  octave_idx_type result_nc;
146 
147  // Default case is to return a column vector, however, if the original
148  // argument was a row vector, then force return of a row vector.
149  if (nr == 1)
150  {
151  result_nr = 1;
152  result_nc = count;
153  }
154  else
155  {
156  result_nr = count;
157  result_nc = 1;
158  }
159 
160  Matrix idx (result_nr, result_nc);
161 
162  Matrix i_idx (result_nr, result_nc);
163  Matrix j_idx (result_nr, result_nc);
164 
165  Array<T> val (dim_vector (result_nr, result_nc));
166 
167  if (count > 0)
168  {
169  // Search for elements to return. Only search the region where there
170  // are elements to be found using the count that we want to find.
171  for (octave_idx_type j = start_nc, cx = 0; j < end_nc; j++)
172  for (octave_idx_type i = v.cidx (j); i < v.cidx (j+1); i++)
173  {
174  octave_quit ();
175 
176  if (direction < 0 && i < nz - count)
177  continue;
178  i_idx(cx) = static_cast<double> (v.ridx (i) + 1);
179  j_idx(cx) = static_cast<double> (j + 1);
180  idx(cx) = j * nr + v.ridx (i) + 1;
181  val(cx) = v.data(i);
182  cx++;
183  if (cx == count)
184  break;
185  }
186  }
187  else
188  {
189  // No items found. Fixup return dimensions for Matlab compatibility.
190  // The behavior to match is documented in Array.cc (Array<T>::find).
191  if ((nr == 0 && nc == 0) || (nr == 1 && nc == 1))
192  {
193  idx.resize (0, 0);
194 
195  i_idx.resize (0, 0);
196  j_idx.resize (0, 0);
197 
198  val.resize (dim_vector (0, 0));
199  }
200  }
201 
202  switch (nargout)
203  {
204  case 0:
205  case 1:
206  retval(0) = idx;
207  break;
208 
209  case 5:
210  retval(4) = nc;
211  OCTAVE_FALLTHROUGH;
212 
213  case 4:
214  retval(3) = nr;
215  OCTAVE_FALLTHROUGH;
216 
217  case 3:
218  retval(2) = val;
219  OCTAVE_FALLTHROUGH;
220 
221  case 2:
222  retval(1) = j_idx;
223  retval(0) = i_idx;
224  }
225 
226  return retval;
227 }
228 
231  octave_idx_type n_to_find, int direction)
232 {
233  // There are far fewer special cases to handle for a PermMatrix.
234  nargout = std::min (nargout, 5);
235  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
236 
237  octave_idx_type nr = v.rows ();
238  octave_idx_type nc = v.cols ();
239  octave_idx_type start_nc, count;
240 
241  // Determine the range to search.
242  if (n_to_find < 0 || n_to_find >= nc)
243  {
244  start_nc = 0;
245  count = nc;
246  }
247  else if (direction > 0)
248  {
249  start_nc = 0;
250  count = n_to_find;
251  }
252  else
253  {
254  start_nc = nc - n_to_find;
255  count = n_to_find;
256  }
257 
258  Matrix idx (count, 1);
259  Matrix i_idx (count, 1);
260  Matrix j_idx (count, 1);
261  // Every value is 1.
262  Array<double> val (dim_vector (count, 1), 1.0);
263 
264  if (count > 0)
265  {
266  const Array<octave_idx_type>& p = v.col_perm_vec ();
267  for (octave_idx_type k = 0; k < count; k++)
268  {
269  octave_quit ();
270 
271  const octave_idx_type j = start_nc + k;
272  const octave_idx_type i = p(j);
273  i_idx(k) = static_cast<double> (1+i);
274  j_idx(k) = static_cast<double> (1+j);
275  idx(k) = j * nc + i + 1;
276  }
277  }
278  else
279  {
280  // FIXME: Is this case even possible? A scalar permutation matrix seems
281  // to devolve to a scalar full matrix, at least from the Octave command
282  // line. Perhaps this function could be called internally from C++ with
283  // such a matrix.
284  // No items found. Fixup return dimensions for Matlab compatibility.
285  // The behavior to match is documented in Array.cc (Array<T>::find).
286  if ((nr == 0 && nc == 0) || (nr == 1 && nc == 1))
287  {
288  idx.resize (0, 0);
289 
290  i_idx.resize (0, 0);
291  j_idx.resize (0, 0);
292 
293  val.resize (dim_vector (0, 0));
294  }
295  }
296 
297  switch (nargout)
298  {
299  case 0:
300  case 1:
301  retval(0) = idx;
302  break;
303 
304  case 5:
305  retval(4) = nc;
306  OCTAVE_FALLTHROUGH;
307 
308  case 4:
309  retval(3) = nc;
310  OCTAVE_FALLTHROUGH;
311 
312  case 3:
313  retval(2) = val;
314  OCTAVE_FALLTHROUGH;
315 
316  case 2:
317  retval(1) = j_idx;
318  retval(0) = i_idx;
319  }
320 
321  return retval;
322 }
323 
324 DEFUN (find, args, nargout,
325  doc: /* -*- texinfo -*-
326 @deftypefn {} {@var{idx} =} find (@var{x})
327 @deftypefnx {} {@var{idx} =} find (@var{x}, @var{n})
328 @deftypefnx {} {@var{idx} =} find (@var{x}, @var{n}, @var{direction})
329 @deftypefnx {} {[i, j] =} find (@dots{})
330 @deftypefnx {} {[i, j, v] =} find (@dots{})
331 Return a vector of indices of nonzero elements of a matrix, as a row if
332 @var{x} is a row vector or as a column otherwise.
333 
334 To obtain a single index for each matrix element, Octave pretends that the
335 columns of a matrix form one long vector (like Fortran arrays are stored).
336 For example:
337 
338 @example
339 @group
340 find (eye (2))
341  @result{} [ 1; 4 ]
342 @end group
343 @end example
344 
345 If two inputs are given, @var{n} indicates the maximum number of elements to
346 find from the beginning of the matrix or vector.
347 
348 If three inputs are given, @var{direction} should be one of
349 @qcode{"first"} or @qcode{"last"}, requesting only the first or last
350 @var{n} indices, respectively. However, the indices are always returned in
351 ascending order.
352 
353 If two outputs are requested, @code{find} returns the row and column
354 indices of nonzero elements of a matrix. For example:
355 
356 @example
357 @group
358 [i, j] = find (2 * eye (2))
359  @result{} i = [ 1; 2 ]
360  @result{} j = [ 1; 2 ]
361 @end group
362 @end example
363 
364 If three outputs are requested, @code{find} also returns a vector
365 containing the nonzero values. For example:
366 
367 @example
368 @group
369 [i, j, v] = find (3 * eye (2))
370  @result{} i = [ 1; 2 ]
371  @result{} j = [ 1; 2 ]
372  @result{} v = [ 3; 3 ]
373 @end group
374 @end example
375 
376 Note that this function is particularly useful for sparse matrices, as
377 it extracts the nonzero elements as vectors, which can then be used to
378 create the original matrix. For example:
379 
380 @example
381 @group
382 sz = size (a);
383 [i, j, v] = find (a);
384 b = sparse (i, j, v, sz(1), sz(2));
385 @end group
386 @end example
387 @seealso{nonzeros}
388 @end deftypefn */)
389 {
390  int nargin = args.length ();
391 
393  print_usage ();
394 
395  // Setup the default options.
396  octave_idx_type n_to_find = -1;
397  if (nargin > 1)
398  {
399  double val = args(1).xscalar_value ("find: N must be an integer");
400 
401  if (val < 0 || (! octave::math::isinf (val)
402  && val != octave::math::round (val)))
403  error ("find: N must be a non-negative integer");
404  else if (! octave::math::isinf (val))
405  n_to_find = val;
406  }
407 
408  // Direction to do the searching (1 == forward, -1 == reverse).
409  int direction = 1;
410  if (nargin > 2)
411  {
412  direction = 0;
413 
414  std::string s_arg = args(2).string_value ();
415 
416  if (s_arg == "first")
417  direction = 1;
418  else if (s_arg == "last")
419  direction = -1;
420  else
421  error (R"(find: DIRECTION must be "first" or "last")");
422  }
423 
425 
426  octave_value arg = args(0);
427 
428  if (arg.islogical ())
429  {
430  if (arg.issparse ())
431  {
433 
434  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
435  }
436  else if (nargout <= 1 && n_to_find == -1 && direction == 1)
437  {
438  // This case is equivalent to extracting indices from a logical
439  // matrix. Try to reuse the possibly cached index vector.
440 
441  // No need to catch index_exception, since arg is bool.
442  // Out-of-range errors have already set pos, and will be
443  // caught later.
444 
446 
447  dim_vector dv = result.dims ();
448 
449  retval(0) = (dv.all_zero () || dv.isvector ()
450  ? result : result.reshape (dv.as_column ()));
451  }
452  else
453  {
455 
456  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
457  }
458  }
459  else if (arg.isinteger ())
460  {
461 #define DO_INT_BRANCH(INTT) \
462  else if (arg.is_ ## INTT ## _type ()) \
463  { \
464  INTT ## NDArray v = arg.INTT ## _array_value (); \
465  \
466  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction); \
467  }
468 
469  if (false)
470  ;
471  DO_INT_BRANCH (int8)
472  DO_INT_BRANCH (int16)
473  DO_INT_BRANCH (int32)
474  DO_INT_BRANCH (int64)
475  DO_INT_BRANCH (uint8)
476  DO_INT_BRANCH (uint16)
477  DO_INT_BRANCH (uint32)
478  DO_INT_BRANCH (uint64)
479  else
480  panic_impossible ();
481  }
482  else if (arg.issparse ())
483  {
484  if (arg.isreal ())
485  {
487 
488  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
489  }
490  else if (arg.iscomplex ())
491  {
493 
494  retval = find_nonzero_elem_idx (v, nargout, n_to_find, direction);
495  }
496  else
497  err_wrong_type_arg ("find", arg);
498  }
499  else if (arg.is_perm_matrix ())
500  {
502 
503  retval = find_nonzero_elem_idx (P, nargout, n_to_find, direction);
504  }
505  else if (arg.is_string ())
506  {
507  charNDArray chnda = arg.char_array_value ();
508 
509  retval = find_nonzero_elem_idx (chnda, nargout, n_to_find, direction);
510  }
511  else if (arg.is_single_type ())
512  {
513  if (arg.isreal ())
514  {
516 
517  retval = find_nonzero_elem_idx (nda, nargout, n_to_find, direction);
518  }
519  else if (arg.iscomplex ())
520  {
522 
523  retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
524  }
525  }
526  else if (arg.isreal ())
527  {
528  NDArray nda = arg.array_value ();
529 
530  retval = find_nonzero_elem_idx (nda, nargout, n_to_find, direction);
531  }
532  else if (arg.iscomplex ())
533  {
535 
536  retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
537  }
538  else
539  err_wrong_type_arg ("find", arg);
540 
541  return retval;
542 }
543 
544 /*
545 %!assert (find (char ([0, 97])), 2)
546 %!assert (find ([1, 0, 1, 0, 1]), [1, 3, 5])
547 %!assert (find ([1; 0; 3; 0; 1]), [1; 3; 5])
548 %!assert (find ([0, 0, 2; 0, 3, 0; -1, 0, 0]), [3; 5; 7])
549 
550 %!assert <*53603> (find (ones (1,1,2) > 0), [1;2])
551 %!assert <*53603> (find (ones (1,1,1,3) > 0), [1;2;3])
552 
553 %!test
554 %! [i, j, v] = find ([0, 0, 2; 0, 3, 0; -1, 0, 0]);
555 %!
556 %! assert (i, [3; 2; 1]);
557 %! assert (j, [1; 2; 3]);
558 %! assert (v, [-1; 3; 2]);
559 
560 %!assert (find (single ([1, 0, 1, 0, 1])), [1, 3, 5])
561 %!assert (find (single ([1; 0; 3; 0; 1])), [1; 3; 5])
562 %!assert (find (single ([0, 0, 2; 0, 3, 0; -1, 0, 0])), [3; 5; 7])
563 
564 %!test
565 %! [i, j, v] = find (single ([0, 0, 2; 0, 3, 0; -1, 0, 0]));
566 %!
567 %! assert (i, [3; 2; 1]);
568 %! assert (j, [1; 2; 3]);
569 %! assert (v, single ([-1; 3; 2]));
570 
571 %!test
572 %! pcol = [5 1 4 3 2];
573 %! P = eye (5) (:, pcol);
574 %! [i, j, v] = find (P);
575 %! [ifull, jfull, vfull] = find (full (P));
576 %! assert (i, ifull);
577 %! assert (j, jfull);
578 %! assert (all (v == 1));
579 
580 %!test
581 %! prow = [5 1 4 3 2];
582 %! P = eye (5) (prow, :);
583 %! [i, j, v] = find (P);
584 %! [ifull, jfull, vfull] = find (full (P));
585 %! assert (i, ifull);
586 %! assert (j, jfull);
587 %! assert (all (v == 1));
588 
589 %!assert <*53655> (find (false), zeros (0, 0))
590 %!assert <*53655> (find ([false, false]), zeros (1, 0))
591 %!assert <*53655> (find ([false; false]), zeros (0, 1))
592 %!assert <*53655> (find ([false, false; false, false]), zeros (0, 1))
593 
594 %!assert (find ([2 0 1 0 5 0], 1), 1)
595 %!assert (find ([2 0 1 0 5 0], 2, "last"), [3, 5])
596 
597 %!assert (find ([2 0 1 0 5 0], Inf), [1, 3, 5])
598 %!assert (find ([2 0 1 0 5 0], Inf, "last"), [1, 3, 5])
599 
600 %!error find ()
601 */
octave_idx_type rows(void) const
Definition: Array.h:404
T * data(void)
Definition: Sparse.h:486
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 rows(void) const
Definition: PermMatrix.h:53
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:148
bool islogical(void) const
Definition: ov.h:696
bool isempty(void) const
Definition: Array.h:565
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
octave_idx_type * cidx(void)
Definition: Sparse.h:508
for large enough k
Definition: lu.cc:617
#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
bool isinf(double x)
Definition: lo-mappers.h:225
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:442
bool is_perm_matrix(void) const
Definition: ov.h:574
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:843
octave_value arg
Definition: pr-output.cc:3244
charNDArray char_array_value(bool frc_str_conv=false) const
Definition: ov.h:878
octave_idx_type nnz(void) const
Actual number of nonzero terms.
Definition: Sparse.h:240
Array< T > index(const idx_vector &i) const
Indexing without resizing.
Definition: Array.cc:697
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
bool is_single_type(void) const
Definition: ov.h:651
bool isinteger(void) const
Definition: ov.h:687
bool issparse(void) const
Definition: ov.h:730
octave_value retval
Definition: data.cc:6246
#define panic_impossible()
Definition: error.h:40
octave_idx_type * ridx(void)
Definition: Sparse.h:495
Definition: dMatrix.h:36
bool all_zero(void) const
Definition: dim-vector.h:327
#define DO_INT_BRANCH(INTT)
FloatComplexNDArray float_complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:863
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:162
With real return the complex result
Definition: data.cc:3260
const Array< octave_idx_type > & col_perm_vec(void) const
Definition: PermMatrix.h:77
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:885
static octave_idx_type find(octave_idx_type i, octave_idx_type *pp)
Definition: colamd.cc:103
T & xelem(octave_idx_type n)
Definition: Array.h:458
octave_idx_type cols(void) const
Definition: Sparse.h:259
bool isreal(void) const
Definition: ov.h:703
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:125
boolNDArray bool_array_value(bool warn=false) const
Definition: ov.h:872
p
Definition: lu.cc:138
bool isvector(void) const
Definition: dim-vector.h:422
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:881
idx_vector unmask(void) const
Definition: idx-vector.cc:1203
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:2227
double round(double x)
Definition: lo-mappers.h:145
args.length() nargin
Definition: file-io.cc:589
bool iscomplex(void) const
Definition: ov.h:710
for i
Definition: data.cc:5264
SparseBoolMatrix sparse_bool_matrix_value(bool warn=false) const
Definition: ov.h:888
PermMatrix perm_matrix_value(void) const
Definition: ov.h:904
bool is_string(void) const
Definition: ov.h:577
octave_idx_type cols(void) const
Definition: PermMatrix.h:54
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
ComplexNDArray complex_array_value(bool frc_str_conv=false) const
Definition: ov.h:859
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 as_column(void) const
Definition: dim-vector.h:406
dim_vector dv
Definition: sub2ind.cc:263
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:840
octave_idx_type rows(void) const
Definition: Sparse.h:258
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:204