GNU Octave  3.8.0
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-2013 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 #ifdef 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 "gripes.h"
32 #include "oct-obj.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>
40 find_nonzero_elem_idx (const Array<T>& nda, int nargout,
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.length (), nr = nda.rows ();
65  for (octave_idx_type i = 0; i < n; i++)
66  {
67  jdx.xelem (i) = idx.xelem (i) / nr;
68  idx.xelem (i) %= nr;
69  }
70  iext = -1;
71  retval(1) = idx_vector (jdx, -1);
72  }
73  // Fall through!
74 
75  case 1:
76  case 0:
77  retval(0) = idx_vector (idx, iext);
78  break;
79  }
80 
81  return retval;
82 }
83 
84 template <typename T>
86 find_nonzero_elem_idx (const Sparse<T>& v, int nargout,
87  octave_idx_type n_to_find, int direction)
88 {
89  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
90 
91 
92  octave_idx_type nc = v.cols ();
93  octave_idx_type nr = v.rows ();
94  octave_idx_type nz = v.nnz ();
95 
96  // Search in the default range.
97  octave_idx_type start_nc = -1;
98  octave_idx_type end_nc = -1;
99  octave_idx_type count;
100 
101  // Search for the range to search
102  if (n_to_find < 0)
103  {
104  start_nc = 0;
105  end_nc = nc;
106  n_to_find = nz;
107  count = nz;
108  }
109  else if (direction > 0)
110  {
111  for (octave_idx_type j = 0; j < nc; j++)
112  {
113  OCTAVE_QUIT;
114  if (v.cidx (j) == 0 && v.cidx (j+1) != 0)
115  start_nc = j;
116  if (v.cidx (j+1) >= n_to_find)
117  {
118  end_nc = j + 1;
119  break;
120  }
121  }
122  }
123  else
124  {
125  for (octave_idx_type j = nc; j > 0; j--)
126  {
127  OCTAVE_QUIT;
128  if (v.cidx (j) == nz && v.cidx (j-1) != nz)
129  end_nc = j;
130  if (nz - v.cidx (j-1) >= n_to_find)
131  {
132  start_nc = j - 1;
133  break;
134  }
135  }
136  }
137 
138  count = (n_to_find > v.cidx (end_nc) - v.cidx (start_nc) ?
139  v.cidx (end_nc) - v.cidx (start_nc) : n_to_find);
140 
141  // If the original argument was a row vector, force a row vector of
142  // the overall indices to be returned. But see below for scalar
143  // case...
144 
145  octave_idx_type result_nr = count;
146  octave_idx_type result_nc = 1;
147 
148  bool scalar_arg = false;
149 
150  if (v.rows () == 1)
151  {
152  result_nr = 1;
153  result_nc = count;
154 
155  scalar_arg = (v.columns () == 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
168  // there are elements to be found using the count that we want
169  // to find.
170  for (octave_idx_type j = start_nc, cx = 0; j < end_nc; j++)
171  for (octave_idx_type i = v.cidx (j); i < v.cidx (j+1); i++ )
172  {
173  OCTAVE_QUIT;
174  if (direction < 0 && i < nz - count)
175  continue;
176  i_idx(cx) = static_cast<double> (v.ridx (i) + 1);
177  j_idx(cx) = static_cast<double> (j + 1);
178  idx(cx) = j * nr + v.ridx (i) + 1;
179  val(cx) = v.data(i);
180  cx++;
181  if (cx == count)
182  break;
183  }
184  }
185  else if (scalar_arg)
186  {
187  idx.resize (0, 0);
188 
189  i_idx.resize (0, 0);
190  j_idx.resize (0, 0);
191 
192  val.resize (dim_vector (0, 0));
193  }
194 
195  switch (nargout)
196  {
197  case 0:
198  case 1:
199  retval(0) = idx;
200  break;
201 
202  case 5:
203  retval(4) = nc;
204  // Fall through
205 
206  case 4:
207  retval(3) = nr;
208  // Fall through
209 
210  case 3:
211  retval(2) = val;
212  // Fall through!
213 
214  case 2:
215  retval(1) = j_idx;
216  retval(0) = i_idx;
217  break;
218 
219  default:
220  panic_impossible ();
221  break;
222  }
223 
224  return retval;
225 }
226 
228 find_nonzero_elem_idx (const PermMatrix& v, int nargout,
229  octave_idx_type n_to_find, int direction)
230 {
231  // There are far fewer special cases to handle for a PermMatrix.
232  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
233 
234  octave_idx_type nc = v.cols ();
235  octave_idx_type start_nc, count;
236 
237  // Determine the range to search.
238  if (n_to_find < 0 || n_to_find >= nc)
239  {
240  start_nc = 0;
241  n_to_find = nc;
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  bool scalar_arg = (v.rows () == 1 && v.cols () == 1);
256 
257  Matrix idx (count, 1);
258  Matrix i_idx (count, 1);
259  Matrix j_idx (count, 1);
260  // Every value is 1.
261  Array<double> val (dim_vector (count, 1), 1.0);
262 
263  if (count > 0)
264  {
265  const octave_idx_type* p = v.data ();
266  if (v.is_col_perm ())
267  {
268  for (octave_idx_type k = 0; k < count; k++)
269  {
270  OCTAVE_QUIT;
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  for (octave_idx_type k = 0; k < count; k++)
281  {
282  OCTAVE_QUIT;
283  const octave_idx_type i = start_nc + k;
284  const octave_idx_type j = p[i];
285  // Scatter into the index arrays according to
286  // j adjusted by the start point.
287  const octave_idx_type koff = j - start_nc;
288  i_idx(koff) = static_cast<double> (1+i);
289  j_idx(koff) = static_cast<double> (1+j);
290  idx(koff) = j * nc + i + 1;
291  }
292  }
293  }
294  else if (scalar_arg)
295  {
296  // Same odd compatibility case as the other overrides.
297  idx.resize (0, 0);
298  i_idx.resize (0, 0);
299  j_idx.resize (0, 0);
300  val.resize (dim_vector (0, 0));
301  }
302 
303  switch (nargout)
304  {
305  case 0:
306  case 1:
307  retval(0) = idx;
308  break;
309 
310  case 5:
311  retval(4) = nc;
312  // Fall through
313 
314  case 4:
315  retval(3) = nc;
316  // Fall through
317 
318  case 3:
319  retval(2) = val;
320  // Fall through!
321 
322  case 2:
323  retval(1) = j_idx;
324  retval(0) = i_idx;
325  break;
326 
327  default:
328  panic_impossible ();
329  break;
330  }
331 
332  return retval;
333 }
334 
335 DEFUN (find, args, nargout,
336  "-*- texinfo -*-\n\
337 @deftypefn {Built-in Function} {@var{idx} =} find (@var{x})\n\
338 @deftypefnx {Built-in Function} {@var{idx} =} find (@var{x}, @var{n})\n\
339 @deftypefnx {Built-in Function} {@var{idx} =} find (@var{x}, @var{n}, @var{direction})\n\
340 @deftypefnx {Built-in Function} {[i, j] =} find (@dots{})\n\
341 @deftypefnx {Built-in Function} {[i, j, v] =} find (@dots{})\n\
342 Return a vector of indices of nonzero elements of a matrix, as a row if\n\
343 @var{x} is a row vector or as a column otherwise. To obtain a single index\n\
344 for each matrix element, Octave pretends that the columns of a matrix form\n\
345 one long vector (like Fortran arrays are stored). For example:\n\
346 \n\
347 @example\n\
348 @group\n\
349 find (eye (2))\n\
350  @result{} [ 1; 4 ]\n\
351 @end group\n\
352 @end example\n\
353 \n\
354 If two outputs are requested, @code{find} returns the row and column\n\
355 indices of nonzero elements of a matrix. For example:\n\
356 \n\
357 @example\n\
358 @group\n\
359 [i, j] = find (2 * eye (2))\n\
360  @result{} i = [ 1; 2 ]\n\
361  @result{} j = [ 1; 2 ]\n\
362 @end group\n\
363 @end example\n\
364 \n\
365 If three outputs are requested, @code{find} also returns a vector\n\
366 containing the nonzero values. For example:\n\
367 \n\
368 @example\n\
369 @group\n\
370 [i, j, v] = find (3 * eye (2))\n\
371  @result{} i = [ 1; 2 ]\n\
372  @result{} j = [ 1; 2 ]\n\
373  @result{} v = [ 3; 3 ]\n\
374 @end group\n\
375 @end example\n\
376 \n\
377 If two inputs are given, @var{n} indicates the maximum number of\n\
378 elements to find from the beginning of the matrix or vector.\n\
379 \n\
380 If three inputs are given, @var{direction} should be one of\n\
381 @qcode{\"first\"} or @qcode{\"last\"}, requesting only the first or last\n\
382 @var{n} indices, respectively. However, the indices are always returned in\n\
383 ascending order.\n\
384 \n\
385 Note that this function is particularly useful for sparse matrices, as\n\
386 it extracts the non-zero elements as vectors, which can then be used to\n\
387 create the original matrix. For example:\n\
388 \n\
389 @example\n\
390 @group\n\
391 sz = size (a);\n\
392 [i, j, v] = find (a);\n\
393 b = sparse (i, j, v, sz(1), sz(2));\n\
394 @end group\n\
395 @end example\n\
396 @seealso{nonzeros}\n\
397 @end deftypefn")
398 {
399  octave_value_list retval;
400 
401  int nargin = args.length ();
402 
403  if (nargin > 3 || nargin < 1)
404  {
405  print_usage ();
406  return retval;
407  }
408 
409  // Setup the default options.
410  octave_idx_type n_to_find = -1;
411  if (nargin > 1)
412  {
413  double val = args(1).scalar_value ();
414 
415  if (error_state || (val < 0 || (! xisinf (val) && val != xround (val))))
416  {
417  error ("find: N must be a non-negative integer");
418  return retval;
419  }
420  else if (! xisinf (val))
421  n_to_find = val;
422  }
423 
424  // Direction to do the searching (1 == forward, -1 == reverse).
425  int direction = 1;
426  if (nargin > 2)
427  {
428  direction = 0;
429 
430  std::string s_arg = args(2).string_value ();
431 
432  if (! error_state)
433  {
434  if (s_arg == "first")
435  direction = 1;
436  else if (s_arg == "last")
437  direction = -1;
438  }
439 
440  if (direction == 0)
441  {
442  error ("find: DIRECTION must be \"first\" or \"last\"");
443  return retval;
444  }
445  }
446 
447  octave_value arg = args(0);
448 
449  if (arg.is_bool_type ())
450  {
451  if (arg.is_sparse_type ())
452  {
454 
455  if (! error_state)
456  retval = find_nonzero_elem_idx (v, nargout,
457  n_to_find, direction);
458  }
459  else if (nargout <= 1 && n_to_find == -1 && direction == 1)
460  {
461  // This case is equivalent to extracting indices from a logical
462  // matrix. Try to reuse the possibly cached index vector.
463  retval(0) = arg.index_vector ().unmask ();
464  }
465  else
466  {
467  boolNDArray v = arg.bool_array_value ();
468 
469  if (! error_state)
470  retval = find_nonzero_elem_idx (v, nargout,
471  n_to_find, direction);
472  }
473  }
474  else if (arg.is_integer_type ())
475  {
476 #define DO_INT_BRANCH(INTT) \
477  else if (arg.is_ ## INTT ## _type ()) \
478  { \
479  INTT ## NDArray v = arg.INTT ## _array_value (); \
480  \
481  if (! error_state) \
482  retval = find_nonzero_elem_idx (v, nargout, \
483  n_to_find, direction);\
484  }
485 
486  if (false)
487  ;
488  DO_INT_BRANCH (int8)
489  DO_INT_BRANCH (int16)
490  DO_INT_BRANCH (int32)
491  DO_INT_BRANCH (int64)
492  DO_INT_BRANCH (uint8)
493  DO_INT_BRANCH (uint16)
494  DO_INT_BRANCH (uint32)
495  DO_INT_BRANCH (uint64)
496  else
497  panic_impossible ();
498  }
499  else if (arg.is_sparse_type ())
500  {
501  if (arg.is_real_type ())
502  {
504 
505  if (! error_state)
506  retval = find_nonzero_elem_idx (v, nargout,
507  n_to_find, direction);
508  }
509  else if (arg.is_complex_type ())
510  {
512 
513  if (! error_state)
514  retval = find_nonzero_elem_idx (v, nargout,
515  n_to_find, direction);
516  }
517  else
518  gripe_wrong_type_arg ("find", arg);
519  }
520  else if (arg.is_perm_matrix ())
521  {
522  PermMatrix P = arg.perm_matrix_value ();
523 
524  if (! error_state)
525  retval = find_nonzero_elem_idx (P, nargout, n_to_find, direction);
526  }
527  else if (arg.is_string ())
528  {
529  charNDArray chnda = arg.char_array_value ();
530 
531  if (! error_state)
532  retval = find_nonzero_elem_idx (chnda, nargout, n_to_find, direction);
533  }
534  else if (arg.is_single_type ())
535  {
536  if (arg.is_real_type ())
537  {
538  FloatNDArray nda = arg.float_array_value ();
539 
540  if (! error_state)
541  retval = find_nonzero_elem_idx (nda, nargout, n_to_find,
542  direction);
543  }
544  else if (arg.is_complex_type ())
545  {
547 
548  if (! error_state)
549  retval = find_nonzero_elem_idx (cnda, nargout, n_to_find,
550  direction);
551  }
552  }
553  else if (arg.is_real_type ())
554  {
555  NDArray nda = arg.array_value ();
556 
557  if (! error_state)
558  retval = find_nonzero_elem_idx (nda, nargout, n_to_find, direction);
559  }
560  else if (arg.is_complex_type ())
561  {
562  ComplexNDArray cnda = arg.complex_array_value ();
563 
564  if (! error_state)
565  retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
566  }
567  else
568  gripe_wrong_type_arg ("find", arg);
569 
570  return retval;
571 }
572 
573 /*
574 %!assert (find (char ([0, 97])), 2)
575 %!assert (find ([1, 0, 1, 0, 1]), [1, 3, 5])
576 %!assert (find ([1; 0; 3; 0; 1]), [1; 3; 5])
577 %!assert (find ([0, 0, 2; 0, 3, 0; -1, 0, 0]), [3; 5; 7])
578 
579 %!test
580 %! [i, j, v] = find ([0, 0, 2; 0, 3, 0; -1, 0, 0]);
581 %!
582 %! assert (i, [3; 2; 1]);
583 %! assert (j, [1; 2; 3]);
584 %! assert (v, [-1; 3; 2]);
585 
586 %!assert (find (single ([1, 0, 1, 0, 1])), [1, 3, 5])
587 %!assert (find (single ([1; 0; 3; 0; 1])), [1; 3; 5])
588 %!assert (find (single ([0, 0, 2; 0, 3, 0; -1, 0, 0])), [3; 5; 7])
589 
590 %!test
591 %! [i, j, v] = find (single ([0, 0, 2; 0, 3, 0; -1, 0, 0]));
592 %!
593 %! assert (i, [3; 2; 1]);
594 %! assert (j, [1; 2; 3]);
595 %! assert (v, single ([-1; 3; 2]));
596 
597 %!test
598 %! pcol = [5 1 4 3 2];
599 %! P = eye (5) (:, pcol);
600 %! [i, j, v] = find (P);
601 %! [ifull, jfull, vfull] = find (full (P));
602 %! assert (i, ifull);
603 %! assert (j, jfull);
604 %! assert (all (v == 1));
605 
606 %!test
607 %! prow = [5 1 4 3 2];
608 %! P = eye (5) (prow, :);
609 %! [i, j, v] = find (P);
610 %! [ifull, jfull, vfull] = find (full (P));
611 %! assert (i, ifull);
612 %! assert (j, jfull);
613 %! assert (all (v == 1));
614 
615 %!assert (find ([2 0 1 0 5 0], 1), 1)
616 %!assert (find ([2 0 1 0 5 0], 2, "last"), [3, 5])
617 
618 %!assert (find ([2 0 1 0 5 0], Inf), [1, 3, 5])
619 %!assert (find ([2 0 1 0 5 0], Inf, "last"), [1, 3, 5])
620 
621 %!error find ()
622 */