changeset 6002:c5d0490aad55

[project @ 2006-09-26 19:45:42 by jwe]
author jwe
date Tue, 26 Sep 2006 19:45:43 +0000
parents d45cb743ff2e
children 7f8e4f5e2eb7
files src/ChangeLog src/DLD-FUNCTIONS/find.cc
diffstat 2 files changed, 97 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Sep 26 16:28:15 2006 +0000
+++ b/src/ChangeLog	Tue Sep 26 19:45:43 2006 +0000
@@ -1,3 +1,8 @@
+2006-05-17  Bill Denney  <bill@givebillmoney.com>
+
+	* DLD-FUNCTIONS/find.cc (find_nonzero_elem_idx, Ffind):
+	Handle direction and limit on number of elements to find.
+
 2006-09-26  John W. Eaton  <jwe@octave.org>
 
 	* error.cc (warning_1): Call error_2, not error.
--- a/src/DLD-FUNCTIONS/find.cc	Tue Sep 26 16:28:15 2006 +0000
+++ b/src/DLD-FUNCTIONS/find.cc	Tue Sep 26 19:45:43 2006 +0000
@@ -32,26 +32,56 @@
 #include "gripes.h"
 #include "oct-obj.h"
 
-inline double real (double x) { return x; }
+// Find at most N_TO_FIND nonzero elements in NDA.  Search forward if
+// DIRECTION is 1, backward if it is -1.  NARGOUT is the number of
+// output arguments.  If N_TO_FIND is -1, find all nonzero elements.
 
 template <typename T>
 octave_value_list
-find_nonzero_elem_idx (const T& nda, int nargout)
+find_nonzero_elem_idx (const T& nda, int nargout, octave_idx_type n_to_find,
+		       int direction)
 {
-  octave_value_list retval (((nargout == 0) ? 1 : nargout), Matrix ());
+  octave_value_list retval ((nargout == 0 ? 1 : nargout), Matrix ());
 
   octave_idx_type count = 0;
 
   octave_idx_type nel = nda.nelem ();
 
-  for (octave_idx_type i = 0; i < nel; i++)
+  // Set the starting element to the correct value based on the
+  // direction to search.
+  octave_idx_type k = 0;
+  if (direction == -1)
+    k = nel - 1;
+
+  // Search in the default range.
+  octave_idx_type start_el = -1;
+  octave_idx_type end_el = -1;
+
+  // Search for the number of elements to return.
+  while (k < nel && k > -1 && n_to_find != count)
     {
       OCTAVE_QUIT;
 
-      if (nda(i) != 0.0)
-	count++;
+      if (nda(k) != 0.0)
+	{
+	  end_el = k;
+	  if (start_el == -1)
+	    start_el = k;
+	  count++;
+	}
+      k = k + direction;
     }
 
+  // Reverse the range if we're looking backward.
+  if (direction == -1)
+    {
+      octave_idx_type tmp_el = start_el;
+      start_el = end_el;
+      end_el = tmp_el;
+    }
+  // Fix an off by one error.
+  end_el++;
+
   // If the original argument was a row vector, force a row vector of
   // the overall indices to be returned.  But see below for scalar
   // case...
@@ -85,7 +115,10 @@
       octave_idx_type i = 0;
       octave_idx_type j = 0;
 
-      for (octave_idx_type k = 0; k < nel; k++)
+      // Search for elements to return.  Only search the region where
+      // there are elements to be found using the count that we want
+      // to find.
+      for (k = start_el; k < end_el; k++)
 	{
 	  OCTAVE_QUIT;
 
@@ -145,13 +178,17 @@
   return retval;
 }
 
-template octave_value_list find_nonzero_elem_idx (const NDArray&, int);
+template octave_value_list find_nonzero_elem_idx (const NDArray&, int,
+						  octave_idx_type, int);
 
-template octave_value_list find_nonzero_elem_idx (const ComplexNDArray&, int);
+template octave_value_list find_nonzero_elem_idx (const ComplexNDArray&, int,
+						  octave_idx_type, int);
 
 DEFUN_DLD (find, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Loadable Function} {} find (@var{x})\n\
+@deftypefnx {Loadable Function} {} find (@var{x}, @var{n})\n\
+@deftypefnx {Loadable Function} {} find (@var{x}, @var{n}, @var{direction})\n\
 Return a vector of indices of nonzero elements of a matrix.  To obtain a\n\
 single index for each matrix element, Octave pretends that the columns\n\
 of a matrix form one long vector (like Fortran arrays are stored).  For\n\
@@ -186,18 +223,60 @@
      @result{} v = [ 3; 3 ]\n\
 @end group\n\
 @end example\n\
+\n\
+If two inputs are given, @var{n} indicates the number of elements to\n\
+find from the beginning of the matrix or vector.\n\
+\n\
+If three inputs are given, @var{direction} should be one of \"first\" or\n\
+\"last\" indicating that it should start counting found elements from the\n\
+first or last element.\n\
 @end deftypefn")
 {
   octave_value_list retval;
 
   int nargin = args.length ();
 
-  if (nargin != 1 || nargout > 3)
+  if (nargin > 3 || nargin < 1)
     {
       print_usage ();
       return retval;
     }
 
+  // Setup the default options.
+  octave_idx_type n_to_find = -1;
+  if (nargin > 1)
+    {
+      n_to_find = args(1).int_value ();
+      if (error_state)
+	{
+	  error ("find: expecting second argument to be an integer");
+	  return retval;
+	}
+    }
+
+  // Direction to do the searching (1 == forward, -1 == reverse).
+  int direction = 1;
+  if (nargin > 2)
+    {
+      direction = 0;
+
+      std::string s_arg = args(2).string_value ();
+
+      if (! error_state)
+	{
+	  if (s_arg == "first")
+	    direction = 1;
+	  else if (s_arg == "last")
+	    direction = -1;
+	}
+
+      if (direction == 0)
+	{
+	  error ("find: expecting third argument to be \"first\" or \"last\"");
+	  return retval;
+	}
+    }
+
   octave_value arg = args(0);
 
   if (arg.is_real_type ())
@@ -205,21 +284,21 @@
       NDArray nda = arg.array_value ();
 
       if (! error_state)
-	retval = find_nonzero_elem_idx (nda, nargout);
+	retval = find_nonzero_elem_idx (nda, nargout, n_to_find, direction);
     }
   else if (arg.is_complex_type ())
     {
       ComplexNDArray cnda = arg.complex_array_value ();
 
       if (! error_state)
-	retval = find_nonzero_elem_idx (cnda, nargout);
+	retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
     }
   else if (arg.is_string ())
     {
       charNDArray cnda = arg.char_array_value ();
 
       if (! error_state)
-	retval = find_nonzero_elem_idx (cnda, nargout);
+	retval = find_nonzero_elem_idx (cnda, nargout, n_to_find, direction);
     }
   else
     {