diff src/DLD-FUNCTIONS/sub2ind.cc @ 9479:d9716e3ee0dd

supply optimized compiled sub2ind & ind2sub
author Jaroslav Hajek <highegg@gmail.com>
date Mon, 03 Aug 2009 15:52:40 +0200
parents
children a531dec450c4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/DLD-FUNCTIONS/sub2ind.cc	Mon Aug 03 15:52:40 2009 +0200
@@ -0,0 +1,212 @@
+/*
+
+Copyright (C) 2009 VZLU Prague
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "quit.h"
+
+#include "defun-dld.h"
+#include "error.h"
+#include "gripes.h"
+#include "oct-obj.h"
+
+
+static dim_vector 
+get_dim_vector (const octave_value& val,
+                const char *name)
+{
+  RowVector dimsv = val.row_vector_value (false, true);
+  dim_vector dv;
+  octave_idx_type n = dimsv.length ();
+
+  if (n < 2)
+    error ("%s: dimension vector must have at least 2 elements", name);
+  else
+    {
+      dv.resize (n);
+      for (octave_idx_type i = 0; i < dimsv.length (); i++)
+        {
+          octave_idx_type ii = static_cast<int> (dimsv(i));
+          if (ii == dimsv(i) && ii >= 0)
+            dv(i) = ii;
+          else
+            {
+              error ("%s: dimension vector must contain integers", name);
+              break;
+            }
+        }
+    }
+
+  return dv;
+}
+
+DEFUN_DLD (sub2ind, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Function File} {@var{ind} =} sub2ind (@var{dims}, @var{i}, @var{j})\n\
+@deftypefnx {Function File} {@var{ind} =} sub2ind (@var{dims}, @var{s1}, @var{s2}, @dots{}, @var{sN})\n\
+Convert subscripts into a linear index.\n\
+\n\
+The following example shows how to convert the two-dimensional\n\
+index @code{(2,3)} of a 3-by-3 matrix to a linear index.  The matrix\n\
+is linearly indexed moving from one column to next, filling up\n\
+all rows in each column.\n\
+\n\
+@example\n\
+@group\n\
+linear_index = sub2ind ([3, 3], 2, 3)\n\
+@result{} 8\n\
+@end group\n\
+@end example\n\
+@seealso{ind2sub}\n\
+@end deftypefn")
+{
+  int nargin = args.length ();
+  octave_value retval;
+
+  if (nargin < 3)
+    print_usage ();
+  else
+    {
+      dim_vector dv = get_dim_vector (args(0), "sub2ind");
+      Array<idx_vector> idxa (nargin - 1);
+      dim_vector idims;
+
+      if (! error_state)
+        {
+          dv = dv.redim (nargin - 1);
+          for (int j = 0; j < nargin - 1; j++)
+            {
+              if (args(j+1).is_numeric_type ())
+                {
+                  idxa(j) = args(j+1).index_vector ();
+                  if (error_state)
+                    break;
+                  else if (j > 0 && args(j+1).dims () != args(1).dims ())
+                    error ("sub2ind: all subscripts must be of the same size");
+                }
+              else
+                error ("sub2ind: subscripts must be numeric");
+
+              if (error_state)
+                break;
+            }
+        }
+
+      if (! error_state)
+        {
+          idx_vector idx = sub2ind (dv, idxa);
+          retval = idx;
+        }
+    }
+
+  return retval;
+}
+
+/*
+
+# Test input validation
+%!error <sub2ind: dimension vector .*> sub2ind([10 10.5], 1, 1);
+%!error <subscript indices .*> sub2ind([10 10], 1.5, 1);
+%!error <subscript indices .*> sub2ind([10 10], 1, 1.5);
+
+# Test evaluation
+%!shared s1, s2, s3, in
+%! s1 = [   1   1   1   1 ;   2   2   2   2 ];
+%! s2 = [   1   1   2   2 ;   1   1   2   2 ];
+%! s3 = [   1   2   1   2 ;   1   2   1   2 ];
+%! in = [   1 101  11 111 ;   2 102  12 112 ];
+%!assert (sub2ind([10 10 10], s1, s2, s3), in);
+%!shared
+
+# Test low index
+%!assert (sub2ind([10 10 10], 1, 1, 1), 1);
+%!error <subscript indices .*> sub2ind([10 10 10], 0, 1, 1);
+%!error <subscript indices .*> sub2ind([10 10 10], 1, 0, 1);
+%!error <subscript indices .*> sub2ind([10 10 10], 1, 1, 0);
+
+# Test high index
+%!assert (sub2ind([10 10 10], 10, 10, 10), 1000);
+%!error <sub2ind: index out of range> sub2ind([10 10 10], 11, 10, 10);
+%!error <sub2ind: index out of range> sub2ind([10 10 10], 10, 11, 10);
+%!error <sub2ind: index out of range> sub2ind([10 10 10], 10, 10, 11);
+
+# Test high index in the trailing dimensions
+%!assert (sub2ind([10, 1], 2, 1, 1), 2);
+%!error <sub2ind: index out of range> sub2ind([10, 1], 1, 2, 1);
+%!error <sub2ind: index out of range> sub2ind([10, 1], 1, 1, 2);
+%!assert (sub2ind([10 10], 2, 2, 1), 12);
+%!error <sub2ind: index out of range> sub2ind([10 10], 2, 1, 2);
+%!error <sub2ind: index out of range> sub2ind([10 10], 1, 2, 2);
+
+# Test handling of empty arguments
+%!assert (sub2ind([10 10], zeros(0,0), zeros(0,0)), zeros(0,0));
+%!assert (sub2ind([10 10], zeros(2,0), zeros(2,0)), zeros(2,0));
+%!assert (sub2ind([10 10], zeros(0,2), zeros(0,2)), zeros(0,2));
+%!error <sub2ind: all subscripts .* same size> sub2ind([10 10 10], zeros(0,2), zeros(2,0));
+
+# Test handling of arguments of different size
+%!error <sub2ind: all subscripts .* same size> sub2ind([10 10], ones(1,2), ones(1,3));
+%!error <sub2ind: all subscripts .* same size> sub2ind([10 10], ones(1,2), ones(2,1));
+
+*/
+
+DEFUN_DLD (ind2sub, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Function File} {[@var{s1}, @var{s2}, @dots{}, @var{sN}] =} ind2sub (@var{dims}, @var{ind})\n\
+Convert a linear index into subscripts.\n\
+\n\
+The following example shows how to convert the linear index @code{8}\n\
+in a 3-by-3 matrix into a subscript.  The matrix is linearly indexed\n\
+moving from one column to next, filling up all rows in each column.\n\
+@example\n\
+@group\n\
+[r, c] = ind2sub ([3, 3], 8)\n\
+@result{} r =  2\n\
+c =  3\n\
+@end group\n\
+@end example\n\
+@seealso{sub2ind}\n\
+@end deftypefn")
+{
+  int nargin = args.length ();
+  octave_value_list retval;
+
+  if (nargin != 2)
+    print_usage ();
+  else
+    {
+      dim_vector dv = get_dim_vector (args(0), "ind2sub");
+      idx_vector idx = args(1).index_vector ();
+      if (! error_state)
+        {
+          if (nargout > dv.length ())
+            dv = dv.redim (nargout);
+
+          Array<idx_vector> idxa = ind2sub (dv, idx); 
+          retval = Array<octave_value> (idxa);
+        }
+    }
+
+  return retval;
+}