diff src/DLD-FUNCTIONS/max.cc @ 9790:a5035bc7fbfb

rewrite dispatch part & slightly improve min,max,cummin,cummax
author Jaroslav Hajek <highegg@gmail.com>
date Mon, 09 Nov 2009 13:09:49 +0100
parents b4fdfee405b5
children 6e425f6be618
line wrap: on
line diff
--- a/src/DLD-FUNCTIONS/max.cc	Mon Nov 09 10:21:31 2009 +0100
+++ b/src/DLD-FUNCTIONS/max.cc	Mon Nov 09 13:09:49 2009 +0100
@@ -42,646 +42,236 @@
 #include "ov-re-sparse.h"
 #include "ov-cx-sparse.h"
 
-#define MINMAX_DOUBLE_SBODY(FCN) \
-{ \
-  if (nargout == 1 || nargout == 0) \
-    { \
-      if (arg1.is_real_type ()) \
-	{ \
-	  NDArray m = arg1.array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      NDArray n = m. FCN (dim); \
-	      retval(0) = n; \
-	    } \
-	} \
-      else if (arg1.is_complex_type ()) \
-	{ \
-	  ComplexNDArray m = arg1.complex_array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      ComplexNDArray n = m. FCN (dim); \
-	      retval(0) = n; \
-	    } \
-	} \
-      else \
-	gripe_wrong_type_arg (#FCN, arg1); \
-    } \
-  else if (nargout == 2) \
-    { \
-      Array<octave_idx_type> index; \
- \
-      if (arg1.is_real_type ()) \
-	{ \
-	  NDArray m = arg1.array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      NDArray n = m. FCN (index, dim);	\
-	      retval(0) = n; \
-	    } \
-	} \
-      else if (arg1.is_complex_type ()) \
-	{ \
-	  ComplexNDArray m = arg1.complex_array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      ComplexNDArray n = m. FCN (index, dim);	\
-	      retval(0) = n; \
-	    } \
-	} \
-      else \
-	gripe_wrong_type_arg (#FCN, arg1); \
- \
-      octave_idx_type len = index.numel (); \
- \
-      if (len > 0) \
-	retval(1) = octave_value (index, true, true);	\
-      else \
-	retval(1) = NDArray (); \
-    } \
+template <class ArrayType>
+static octave_value_list
+do_minmax_red_op (const octave_value& arg,
+                  int nargout, int dim, bool ismin)
+{
+  octave_value_list retval;
+  ArrayType array = octave_value_extract<ArrayType> (arg);
+
+  if (error_state)
+    return retval;
+
+  if (nargout == 2)
+    {
+      retval.resize (2);
+      Array<octave_idx_type> idx;
+      if (ismin)
+        retval(0) = array.min (idx, dim);
+      else
+        retval(0) = array.max (idx, dim);
+
+      retval(1) = octave_value (idx, true, true);
+    }
+  else
+    {
+      if (ismin)
+        retval(0) = array.min (dim);
+      else
+        retval(0) = array.max (dim);
+    }
+
+  return retval;
 }
 
-#define MINMAX_DOUBLE_BODY(FCN) \
-{ \
-  bool single_arg = (nargin == 1) || (arg2.is_empty() && nargin == 3);	\
-  if (single_arg) \
-    MINMAX_DOUBLE_SBODY (FCN) \
-  else \
-    { \
-      int arg1_is_scalar = arg1.is_scalar_type (); \
-      int arg2_is_scalar = arg2.is_scalar_type (); \
- \
-      int arg1_is_complex = arg1.is_complex_type (); \
-      int arg2_is_complex = arg2.is_complex_type (); \
- \
-      if (arg1_is_scalar) \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      Complex c1 = arg1.complex_value (); \
-	      ComplexNDArray m2 = arg2.complex_array_value (); \
-	      if (! error_state) \
-		{ \
-		  ComplexNDArray result = FCN (c1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	  else \
-	    { \
-	      double d1 = arg1.double_value (); \
-	      NDArray m2 = arg2.array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  NDArray result = FCN (d1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-      else if (arg2_is_scalar) \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      ComplexNDArray m1 = arg1.complex_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  Complex c2 = arg2.complex_value (); \
-		  ComplexNDArray result = FCN (m1, c2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	  else \
-	    { \
-	      NDArray m1 = arg1.array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  double d2 = arg2.double_value (); \
-		  NDArray result = FCN (m1, d2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-      else \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      ComplexNDArray m1 = arg1.complex_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  ComplexNDArray m2 = arg2.complex_array_value (); \
- \
-		  if (! error_state) \
-		    { \
-		      ComplexNDArray result = FCN (m1, m2); \
-		      if (! error_state) \
-			retval(0) = result; \
-		    } \
-		} \
-	    } \
-	  else \
-	    { \
-	      NDArray m1 = arg1.array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  NDArray m2 = arg2.array_value (); \
- \
-		  if (! error_state) \
-		    { \
-		      NDArray result = FCN (m1, m2); \
-		      if (! error_state) \
-			retval(0) = result; \
-		    } \
-		} \
-	    } \
-	} \
-    } \
-}
+template <class ArrayType>
+static octave_value
+do_minmax_bin_op (const octave_value& argx, const octave_value& argy,
+                  bool ismin)
+{
+  typedef typename ArrayType::element_type ScalarType;
+
+  octave_value retval;
+
+  if (argx.is_scalar_type () == 1)
+    {
+      ScalarType x = octave_value_extract<ScalarType> (argx);
+      ArrayType y = octave_value_extract<ArrayType> (argy);
 
-#define MINMAX_SINGLE_SBODY(FCN) \
-{ \
-  if (nargout == 1 || nargout == 0) \
-    { \
-      if (arg1.is_real_type ()) \
-	{ \
-	  FloatNDArray m = arg1.float_array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      FloatNDArray n = m. FCN (dim); \
-	      retval(0) = n; \
-	    } \
-	} \
-      else if (arg1.is_complex_type ()) \
-	{ \
-	  FloatComplexNDArray m = arg1.float_complex_array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      FloatComplexNDArray n = m. FCN (dim); \
-	      retval(0) = n; \
-	    } \
-	} \
-      else \
-	gripe_wrong_type_arg (#FCN, arg1); \
-    } \
-  else if (nargout == 2) \
-    { \
-      Array<octave_idx_type> index; \
- \
-      if (arg1.is_real_type ()) \
-	{ \
-	  FloatNDArray m = arg1.float_array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      FloatNDArray n = m. FCN (index, dim);	\
-	      retval(0) = n; \
-	    } \
-	} \
-      else if (arg1.is_complex_type ()) \
-	{ \
-	  FloatComplexNDArray m = arg1.float_complex_array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      FloatComplexNDArray n = m. FCN (index, dim);	\
-	      retval(0) = n; \
-	    } \
-	} \
-      else \
-	gripe_wrong_type_arg (#FCN, arg1); \
- \
-      octave_idx_type len = index.numel (); \
- \
-      if (len > 0) \
-	retval(1) = octave_value (index, true, true);	\
-      else \
-	retval(1) = NDArray (); \
-    } \
+      if (error_state)
+        ;
+      else if (ismin)
+        retval = min (x, y);
+      else
+        retval = max (x, y);
+    }
+  else if (argy.is_scalar_type () == 1)
+    {
+      ArrayType x = octave_value_extract<ArrayType> (argx);
+      ScalarType y = octave_value_extract<ScalarType> (argy);
+
+      if (error_state)
+        ;
+      else if (ismin)
+        retval = min (x, y);
+      else
+        retval = max (x, y);
+    }
+  else
+    {
+      ArrayType x = octave_value_extract<ArrayType> (argx);
+      ArrayType y = octave_value_extract<ArrayType> (argy);
+
+      if (error_state)
+        ;
+      else if (ismin)
+        retval = min (x, y);
+      else
+        retval = max (x, y);
+    }
+
+  return retval;
 }
 
-#define MINMAX_SINGLE_BODY(FCN) \
-{ \
-  bool single_arg = (nargin == 1) || (arg2.is_empty() && nargin == 3);	\
-  if (single_arg) \
-    MINMAX_SINGLE_SBODY(FCN) \
-  else \
-    { \
-      int arg1_is_scalar = arg1.is_scalar_type (); \
-      int arg2_is_scalar = arg2.is_scalar_type (); \
- \
-      int arg1_is_complex = arg1.is_complex_type (); \
-      int arg2_is_complex = arg2.is_complex_type (); \
- \
-      if (arg1_is_scalar) \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      FloatComplex c1 = arg1.float_complex_value (); \
-	      FloatComplexNDArray m2 = arg2.float_complex_array_value (); \
-	      if (! error_state) \
-		{ \
-		  FloatComplexNDArray result = FCN (c1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	  else \
-	    { \
-	      float d1 = arg1.float_value (); \
-	      FloatNDArray m2 = arg2.float_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  FloatNDArray result = FCN (d1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-      else if (arg2_is_scalar) \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      FloatComplexNDArray m1 = arg1.float_complex_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  FloatComplex c2 = arg2.float_complex_value (); \
-		  FloatComplexNDArray result = FCN (m1, c2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	  else \
-	    { \
-	      FloatNDArray m1 = arg1.float_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  float d2 = arg2.float_value (); \
-		  FloatNDArray result = FCN (m1, d2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-      else \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      FloatComplexNDArray m1 = arg1.float_complex_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  FloatComplexNDArray m2 = arg2.float_complex_array_value (); \
- \
-		  if (! error_state) \
-		    { \
-		      FloatComplexNDArray result = FCN (m1, m2); \
-		      if (! error_state) \
-			retval(0) = result; \
-		    } \
-		} \
-	    } \
-	  else \
-	    { \
-	      FloatNDArray m1 = arg1.float_array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  FloatNDArray m2 = arg2.float_array_value (); \
- \
-		  if (! error_state) \
-		    { \
-		      FloatNDArray result = FCN (m1, m2); \
-		      if (! error_state) \
-			retval(0) = result; \
-		    } \
-		} \
-	    } \
-	} \
-    } \
-}
+static octave_value_list
+do_minmax_body (const octave_value_list& args,
+                int nargout, bool ismin)
+{
+  octave_value_list retval;
+
+  const char *func = ismin ? "min" : "max";
+
+  int nargin = args.length ();
 
-#define MINMAX_INT_SBODY(FCN, TYP) \
-{ \
-  if (nargout == 1 || nargout == 0) \
-    { \
-      TYP ## NDArray m = arg1. TYP ## _array_value (); \
- \
-      if (! error_state) \
-	{ \
-	  TYP ## NDArray n = m. FCN (dim); \
-	  retval(0) = n; \
-	} \
-    } \
-  else if (nargout == 2) \
-    { \
-      Array<octave_idx_type> index; \
- \
-      TYP ## NDArray m = arg1. TYP ## _array_value (); \
- \
-      if (! error_state) \
-        { \
-	  TYP ## NDArray n = m. FCN (index, dim);	\
-	  retval(0) = n; \
-	} \
- \
-      octave_idx_type len = index.numel (); \
- \
-      if (len > 0) \
-	retval(1) = octave_value (index, true, true);	\
-      else \
-	retval(1) = NDArray (); \
-    } \
-}
+  if (nargin == 3 || nargin == 1)
+    {
+      octave_value arg = args(0);
+      int dim = -1;
+      if (nargin == 3)
+        {
+          dim = args(2).int_value (true) - 1;
+          if (error_state || dim < 0)
+            {
+              error ("%s: invalid dimension", func);
+              return retval;
+            }
 
-#define MINMAX_INT_BODY(FCN, TYP) \
- { \
-  bool single_arg = (nargin == 1) || (arg2.is_empty() && nargin == 3);	\
-  if (single_arg) \
-    MINMAX_INT_SBODY (FCN, TYP) \
-  else \
-    { \
-      int arg1_is_scalar = arg1.is_scalar_type (); \
-      int arg2_is_scalar = arg2.is_scalar_type (); \
- \
-      if (arg1_is_scalar) \
-	{ \
-	  octave_ ## TYP d1 = arg1. TYP ## _scalar_value (); \
-	  TYP ## NDArray m2 = arg2. TYP ## _array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      TYP ## NDArray result = FCN (d1, m2); \
-	      if (! error_state) \
-		retval(0) = result; \
-	    } \
-	} \
-      else if (arg2_is_scalar) \
-	{ \
-	  TYP ## NDArray m1 = arg1. TYP ## _array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      octave_ ## TYP d2 = arg2. TYP ## _scalar_value (); \
-	      TYP ## NDArray result = FCN (m1, d2); \
-	      if (! error_state) \
-		retval(0) = result; \
-	    } \
-	} \
-      else \
-	{ \
-	  TYP ## NDArray m1 = arg1. TYP ## _array_value (); \
- \
-	  if (! error_state) \
-	    { \
-	      TYP ## NDArray m2 = arg2. TYP ## _array_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  TYP ## NDArray result = FCN (m1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-    } \
-}
+          if (! args(1).is_empty ())
+            warning ("%s: second argument is ignored");
+        }
 
-#define MINMAX_SPARSE_BODY(FCN) \
-{ \
-  bool single_arg = (nargin == 1) || arg2.is_empty();	\
- \
-  if (single_arg && (nargout == 1 || nargout == 0)) \
-    { \
-      if (arg1.is_real_type ()) \
-	retval(0) = arg1.sparse_matrix_value () .FCN (dim); \
-      else if (arg1.is_complex_type ()) \
-	retval(0) = arg1.sparse_complex_matrix_value () .FCN (dim); \
-      else \
-	gripe_wrong_type_arg (#FCN, arg1); \
-    } \
-  else if (single_arg && nargout == 2) \
-    { \
-      Array2<octave_idx_type> index; \
- \
-      if (arg1.is_real_type ()) \
-	retval(0) = arg1.sparse_matrix_value () .FCN (index, dim); \
-      else if (arg1.is_complex_type ()) \
-	retval(0) = arg1.sparse_complex_matrix_value () .FCN (index, dim); \
-      else \
-	gripe_wrong_type_arg (#FCN, arg1); \
- \
-      octave_idx_type len = index.numel (); \
- \
-      if (len > 0) \
-	retval(1) = octave_value (index, true, true);	\
-      else \
-	retval(1) = NDArray (); \
-    } \
-  else \
-    { \
-      int arg1_is_scalar = arg1.is_scalar_type (); \
-      int arg2_is_scalar = arg2.is_scalar_type (); \
- \
-      int arg1_is_complex = arg1.is_complex_type (); \
-      int arg2_is_complex = arg2.is_complex_type (); \
- \
-      if (arg1_is_scalar) \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      Complex c1 = arg1.complex_value (); \
-	      \
-	      SparseComplexMatrix m2 = arg2.sparse_complex_matrix_value (); \
-	      \
-	      if (! error_state) \
-		{ \
-		  SparseComplexMatrix result = FCN (c1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	  else \
-	    { \
-	      double d1 = arg1.double_value (); \
-	      SparseMatrix m2 = arg2.sparse_matrix_value (); \
-	      \
-	      if (! error_state) \
-		{ \
-		  SparseMatrix result = FCN (d1, m2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-      else if (arg2_is_scalar) \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      SparseComplexMatrix m1 = arg1.sparse_complex_matrix_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  Complex c2 = arg2.complex_value (); \
-		  SparseComplexMatrix result = FCN (m1, c2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	  else \
-	    { \
-	      SparseMatrix m1 = arg1.sparse_matrix_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  double d2 = arg2.double_value (); \
-		  SparseMatrix result = FCN (m1, d2); \
-		  if (! error_state) \
-		    retval(0) = result; \
-		} \
-	    } \
-	} \
-      else \
-	{ \
-	  if (arg1_is_complex || arg2_is_complex) \
-	    { \
-	      SparseComplexMatrix m1 = arg1.sparse_complex_matrix_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  SparseComplexMatrix m2 = arg2.sparse_complex_matrix_value (); \
- \
-		  if (! error_state) \
-		    { \
-		      SparseComplexMatrix result = FCN (m1, m2); \
-		      if (! error_state) \
-			retval(0) = result; \
-		    } \
-		} \
-	    } \
-	  else \
-	    { \
-	      SparseMatrix m1 = arg1.sparse_matrix_value (); \
- \
-	      if (! error_state) \
-		{ \
-		  SparseMatrix m2 = arg2.sparse_matrix_value (); \
- \
-		  if (! error_state) \
-		    { \
-		      SparseMatrix result = FCN (m1, m2); \
-		      if (! error_state) \
-			retval(0) = result; \
-		    } \
-		} \
-	    } \
-	} \
-    } \
+      switch (arg.builtin_type ())
+        {
+        case btyp_double:
+          {
+            if (arg.is_range () && (dim == -1 || dim == 1))
+              {
+                Range range = arg.range_value ();
+                if (range.nelem () == 0)
+                  {
+                    retval(0) = arg;
+                    if (nargout > 1)
+                      retval(1) = arg;
+                  }
+                else if (ismin)
+                  {
+                    retval(0) = range.min ();
+                    if (nargout > 1)
+                      retval(1) = static_cast<double> (range.inc () < 0 ? range.nelem () : 1);
+                  }
+                else
+                  {
+                    retval(0) = range.max ();
+                    if (nargout > 1)
+                      retval(1) = static_cast<double> (range.inc () >= 0 ? range.nelem () : 1);
+                  }
+              }
+            else if (arg.is_sparse_type ())
+              retval = do_minmax_red_op<SparseMatrix> (arg, nargout, dim, ismin);
+            else
+              retval = do_minmax_red_op<NDArray> (arg, nargout, dim, ismin);
+            break;
+          }
+        case btyp_complex:
+          {
+            if (arg.is_sparse_type ())
+              retval = do_minmax_red_op<SparseComplexMatrix> (arg, nargout, dim, ismin);
+            else
+              retval = do_minmax_red_op<ComplexNDArray> (arg, nargout, dim, ismin);
+            break;
+          }
+        case btyp_float:
+          retval = do_minmax_red_op<FloatNDArray> (arg, nargout, dim, ismin);
+          break;
+        case btyp_float_complex:
+          retval = do_minmax_red_op<FloatComplexNDArray> (arg, nargout, dim, ismin);
+          break;
+#define MAKE_INT_BRANCH(X) \
+        case btyp_ ## X: \
+          retval = do_minmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \
+          break;
+        MAKE_INT_BRANCH (int8);
+        MAKE_INT_BRANCH (int16);
+        MAKE_INT_BRANCH (int32);
+        MAKE_INT_BRANCH (int64);
+        MAKE_INT_BRANCH (uint8);
+        MAKE_INT_BRANCH (uint16);
+        MAKE_INT_BRANCH (uint32);
+        MAKE_INT_BRANCH (uint64);
+#undef MAKE_INT_BRANCH
+        default:
+          gripe_wrong_type_arg (func, arg);
+      }
+    }
+  else if (nargin == 2)
+    {
+      octave_value argx = args(0), argy = args(1);
+      builtin_type_t xtyp = argx.builtin_type (), ytyp = argy.builtin_type ();
+      builtin_type_t rtyp = btyp_mixed_numeric (xtyp, ytyp);
+
+      switch (rtyp)
+        {
+        case btyp_double:
+          {
+            if ((argx.is_sparse_type () 
+                 && (argy.is_sparse_type () || argy.is_scalar_type ()))
+                || (argy.is_sparse_type () && argx.is_scalar_type ()))
+              retval = do_minmax_bin_op<SparseMatrix> (argx, argy, ismin);
+            else
+              retval = do_minmax_bin_op<NDArray> (argx, argy, ismin);
+            break;
+          }
+        case btyp_complex:
+          {
+            if ((argx.is_sparse_type () 
+                 && (argy.is_sparse_type () || argy.is_scalar_type ()))
+                || (argy.is_sparse_type () && argx.is_scalar_type ()))
+              retval = do_minmax_bin_op<SparseComplexMatrix> (argx, argy, ismin);
+            else
+              retval = do_minmax_bin_op<ComplexNDArray> (argx, argy, ismin);
+            break;
+          }
+        case btyp_float:
+          retval = do_minmax_bin_op<FloatNDArray> (argx, argy, ismin);
+          break;
+        case btyp_float_complex:
+          retval = do_minmax_bin_op<FloatComplexNDArray> (argx, argy, ismin);
+          break;
+#define MAKE_INT_BRANCH(X) \
+        case btyp_ ## X: \
+          retval = do_minmax_bin_op<X ## NDArray> (argx, argy, ismin); \
+          break;
+        MAKE_INT_BRANCH (int8);
+        MAKE_INT_BRANCH (int16);
+        MAKE_INT_BRANCH (int32);
+        MAKE_INT_BRANCH (int64);
+        MAKE_INT_BRANCH (uint8);
+        MAKE_INT_BRANCH (uint16);
+        MAKE_INT_BRANCH (uint32);
+        MAKE_INT_BRANCH (uint64);
+#undef MAKE_INT_BRANCH
+        default:
+          error ("%s: cannot compute %s (%s, %s)", func, func,
+                 argx.type_name ().c_str (), argy.type_name ().c_str ());
+        }
+    }
+  else
+    print_usage ();
+
+  return retval;
 }
 
-
-#define MINMAX_BODY(FCN) \
- \
-  octave_value_list retval;  \
- \
-  int nargin = args.length (); \
- \
-  if (nargin < 1 || nargin > 3 || nargout > 2) \
-    { \
-      print_usage (); \
-      return retval; \
-    } \
- \
-  octave_value arg1; \
-  octave_value arg2; \
-  octave_value arg3; \
- \
-  switch (nargin) \
-    { \
-    case 3: \
-      arg3 = args(2); \
- \
-    case 2: \
-      arg2 = args(1); \
- \
-    case 1: \
-      arg1 = args(0); \
-      break; \
- \
-    default: \
-      panic_impossible (); \
-      break; \
-    } \
- \
-  int dim; \
-  dim_vector dv = arg1.dims (); \
-  if (error_state) \
-    { \
-      gripe_wrong_type_arg (#FCN, arg1);  \
-      return retval; \
-    } \
- \
-  if (nargin == 3) \
-    { \
-      dim = arg3.nint_value () - 1;  \
-      if (dim < 0 || dim >= dv.length ()) \
-        { \
-	  error ("%s: invalid dimension", #FCN); \
-	  return retval; \
-	} \
-    } \
-  else \
-    { \
-      dim = 0; \
-      while ((dim < dv.length ()) && (dv (dim) <= 1)) \
-	dim++; \
-      if (dim == dv.length ()) \
-	dim = 0; \
-    } \
- \
-  if (arg1.is_integer_type ()) \
-    { \
-      if (arg1.is_uint8_type ()) \
-        MINMAX_INT_BODY (FCN, uint8) \
-      else if (arg1.is_uint16_type ()) \
-        MINMAX_INT_BODY (FCN, uint16) \
-      else if (arg1.is_uint32_type ()) \
-        MINMAX_INT_BODY (FCN, uint32) \
-      else if (arg1.is_uint64_type ()) \
-        MINMAX_INT_BODY (FCN, uint64) \
-      else if (arg1.is_int8_type ()) \
-        MINMAX_INT_BODY (FCN, int8) \
-      else if (arg1.is_int16_type ()) \
-        MINMAX_INT_BODY (FCN, int16) \
-      else if (arg1.is_int32_type ()) \
-        MINMAX_INT_BODY (FCN, int32) \
-      else if (arg1.is_int64_type ()) \
-        MINMAX_INT_BODY (FCN, int64) \
-    } \
-  else if (arg1.is_sparse_type ()) \
-    MINMAX_SPARSE_BODY (FCN) \
-  else if (arg1.is_single_type ()) \
-    MINMAX_SINGLE_BODY (FCN) \
-  else \
-    MINMAX_DOUBLE_BODY (FCN) \
- \
- return retval;
-
 DEFUN_DLD (min, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn  {Loadable Function} {} min (@var{x})\n\
@@ -728,7 +318,7 @@
 @seealso{max, cummin, cummax}\n\
 @end deftypefn")
 {
-  MINMAX_BODY (min);
+  return do_minmax_body (args, nargout, true);
 }
 
 /*
@@ -804,7 +394,7 @@
 @seealso{min, cummax, cummin}\n\
 @end deftypefn")
 {
-  MINMAX_BODY (max);
+  return do_minmax_body (args, nargout, false);
 }
 
 /* 
@@ -835,86 +425,99 @@
 
 */
 
-#define CUMMINMAX_BODY(FCN) \
- \
-  octave_value_list retval;  \
- \
-  int nargin = args.length (); \
- \
-  if (nargin < 1 || nargin > 2 || nargout > 2) \
-    { \
-      print_usage (); \
-      return retval; \
-    } \
- \
-  octave_value arg1; \
-  octave_value arg2; \
- \
-  switch (nargin) \
-    { \
-    case 2: \
-      arg2 = args(1); \
- \
-    case 1: \
-      arg1 = args(0); \
-      break; \
- \
-    default: \
-      panic_impossible (); \
-      break; \
-    } \
- \
-  int dim; \
-  dim_vector dv = arg1.dims (); \
-  if (error_state) \
-    { \
-      gripe_wrong_type_arg (#FCN, arg1);  \
-      return retval; \
-    } \
- \
-  if (nargin == 2) \
-    { \
-      dim = arg2.nint_value () - 1;  \
-      if (dim < 0 || dim >= dv.length ()) \
-        { \
-	  error ("%s: invalid dimension", #FCN); \
-	  return retval; \
-	} \
-    } \
-  else \
-    { \
-      dim = 0; \
-      while ((dim < dv.length ()) && (dv (dim) <= 1)) \
-	dim++; \
-      if (dim == dv.length ()) \
-	dim = 0; \
-    } \
- \
-  if (arg1.is_integer_type ()) \
-    { \
-      if (arg1.is_uint8_type ()) \
-        MINMAX_INT_SBODY (FCN, uint8) \
-      else if (arg1.is_uint16_type ()) \
-        MINMAX_INT_SBODY (FCN, uint16) \
-      else if (arg1.is_uint32_type ()) \
-        MINMAX_INT_SBODY (FCN, uint32) \
-      else if (arg1.is_uint64_type ()) \
-        MINMAX_INT_SBODY (FCN, uint64) \
-      else if (arg1.is_int8_type ()) \
-        MINMAX_INT_SBODY (FCN, int8) \
-      else if (arg1.is_int16_type ()) \
-        MINMAX_INT_SBODY (FCN, int16) \
-      else if (arg1.is_int32_type ()) \
-        MINMAX_INT_SBODY (FCN, int32) \
-      else if (arg1.is_int64_type ()) \
-        MINMAX_INT_SBODY (FCN, int64) \
-    } \
-  else if (arg1.is_single_type ()) \
-    MINMAX_SINGLE_SBODY (FCN) \
-  else \
-    MINMAX_DOUBLE_SBODY (FCN) \
- \
- return retval;
+template <class ArrayType>
+static octave_value_list
+do_cumminmax_red_op (const octave_value& arg,
+                     int nargout, int dim, bool ismin)
+{
+  octave_value_list retval;
+  ArrayType array = octave_value_extract<ArrayType> (arg);
+
+  if (error_state)
+    return retval;
+
+  if (nargout == 2)
+    {
+      retval.resize (2);
+      Array<octave_idx_type> idx;
+      if (ismin)
+        retval(0) = array.cummin (idx, dim);
+      else
+        retval(0) = array.cummax (idx, dim);
+
+      retval(1) = octave_value (idx, true, true);
+    }
+  else
+    {
+      if (ismin)
+        retval(0) = array.cummin (dim);
+      else
+        retval(0) = array.cummax (dim);
+    }
+
+  return retval;
+}
+
+static octave_value_list
+do_cumminmax_body (const octave_value_list& args,
+                   int nargout, bool ismin)
+{
+  octave_value_list retval;
+
+  const char *func = ismin ? "cummin" : "cummax";
+
+  int nargin = args.length ();
+
+  if (nargin == 1 || nargin == 2)
+    {
+      octave_value arg = args(0);
+      int dim = -1;
+      if (nargin == 2)
+        {
+          dim = args(1).int_value (true) - 1;
+          if (error_state || dim < 0)
+            {
+              error ("%s: invalid dimension", func);
+              return retval;
+            }
+        }
+
+      switch (arg.builtin_type ())
+        {
+        case btyp_double:
+          retval = do_cumminmax_red_op<NDArray> (arg, nargout, dim, ismin);
+          break;
+        case btyp_complex:
+          retval = do_cumminmax_red_op<ComplexNDArray> (arg, nargout, dim, ismin);
+          break;
+        case btyp_float:
+          retval = do_cumminmax_red_op<FloatNDArray> (arg, nargout, dim, ismin);
+          break;
+        case btyp_float_complex:
+          retval = do_cumminmax_red_op<FloatComplexNDArray> (arg, nargout, dim, ismin);
+          break;
+#define MAKE_INT_BRANCH(X) \
+        case btyp_ ## X: \
+          retval = do_cumminmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \
+          break;
+        MAKE_INT_BRANCH (int8);
+        MAKE_INT_BRANCH (int16);
+        MAKE_INT_BRANCH (int32);
+        MAKE_INT_BRANCH (int64);
+        MAKE_INT_BRANCH (uint8);
+        MAKE_INT_BRANCH (uint16);
+        MAKE_INT_BRANCH (uint32);
+        MAKE_INT_BRANCH (uint64);
+#undef MAKE_INT_BRANCH
+        default:
+          gripe_wrong_type_arg (func, arg);
+      }
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
 
 DEFUN_DLD (cummin, args, nargout,
   "-*- texinfo -*-\n\
@@ -955,7 +558,7 @@
 @seealso{cummax, min, max}\n\
 @end deftypefn")
 {
-  CUMMINMAX_BODY (cummin);
+  return do_cumminmax_body (args, nargout, true);
 }
 
 DEFUN_DLD (cummax, args, nargout,
@@ -996,7 +599,7 @@
 @seealso{cummin, max, min}\n\
 @end deftypefn")
 {
-  CUMMINMAX_BODY (cummax);
+  return do_cumminmax_body (args, nargout, false);
 }
 
 /*