changeset 8777:724c0f46d9d4

implement cummin/cummax functions
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 17 Feb 2009 11:26:29 +0100
parents d23c33ec6bd3
children 09ab0cc57ba6
files liboctave/CNDArray.cc liboctave/CNDArray.h liboctave/ChangeLog liboctave/dNDArray.cc liboctave/dNDArray.h liboctave/fCNDArray.cc liboctave/fCNDArray.h liboctave/fNDArray.cc liboctave/fNDArray.h liboctave/intNDArray.cc liboctave/intNDArray.h liboctave/mx-inlines.cc src/ChangeLog src/DLD-FUNCTIONS/max.cc
diffstat 14 files changed, 561 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/CNDArray.cc
+++ b/liboctave/CNDArray.cc
@@ -714,6 +714,30 @@
   return do_mx_minmax_op<ComplexNDArray> (*this, idx_arg, dim, mx_inline_min);
 }
 
+ComplexNDArray
+ComplexNDArray::cummax (int dim) const
+{
+  return do_mx_cumminmax_op<ComplexNDArray> (*this, dim, mx_inline_cummax);
+}
+
+ComplexNDArray
+ComplexNDArray::cummax (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<ComplexNDArray> (*this, idx_arg, dim, mx_inline_cummax);
+}
+
+ComplexNDArray
+ComplexNDArray::cummin (int dim) const
+{
+  return do_mx_cumminmax_op<ComplexNDArray> (*this, dim, mx_inline_cummin);
+}
+
+ComplexNDArray
+ComplexNDArray::cummin (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<ComplexNDArray> (*this, idx_arg, dim, mx_inline_cummin);
+}
+
 NDArray
 ComplexNDArray::abs (void) const
 {
--- a/liboctave/CNDArray.h
+++ b/liboctave/CNDArray.h
@@ -85,6 +85,12 @@
   ComplexNDArray max (ArrayN<octave_idx_type>& index, int dim = 0) const;
   ComplexNDArray min (int dim = 0) const;
   ComplexNDArray min (ArrayN<octave_idx_type>& index, int dim = 0) const;
+
+  ComplexNDArray cummax (int dim = 0) const;
+  ComplexNDArray cummax (ArrayN<octave_idx_type>& index, int dim = 0) const;
+  ComplexNDArray cummin (int dim = 0) const;
+  ComplexNDArray cummin (ArrayN<octave_idx_type>& index, int dim = 0) const;
+
   ComplexNDArray& insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
   ComplexNDArray& insert (const ComplexNDArray& a, octave_idx_type r, octave_idx_type c);
   ComplexNDArray& insert (const ComplexNDArray& a, const Array<octave_idx_type>& ra_idx);
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,28 @@
+2009-02-17  Jaroslav Hajek  <highegg@gmail.com>
+
+	* mx-inlines.cc (OP_CUMMINMAX_FCN, OP_CUMMINMAX_FCN2,
+	OP_CUMMINMAX_FCNN): New macros.
+	(mx_inline_cummax, mx_inline_cummin, do_mx_cumminmax_op):
+	New overloaded template functions.
+
+	* dNDArray.cc (NDArray::cummin, NDArray::cummax): New methods.
+	* dNDArray.h: Declare them.
+
+	* fNDArray.cc (FloatNDArray::cummin, FloatNDArray::cummax): New
+	methods.
+	* fNDArray.h: Declare them.
+
+	* CNDArray.cc (ComplexNDArray::cummin, ComplexNDArray::cummax): New
+	methods.
+	* CNDArray.h: Declare them.
+
+	* fCNDArray.cc (FloatComplexNDArray::cummin,
+	FloatComplexNDArray::cummax): New methods.
+	* fCNDArray.h: Declare them.
+
+	* intNDArray.cc (intNDArray::cummin, intNDArray::cummax): New methods.
+	* intNDArray.h: Declare them.
+
 2009-02-17  Jaroslav Hajek  <highegg@gmail.com>
 
 	* mx-inlines.cc (OP_MINMAX_FCN): Correct behaviour with NaNs.
--- a/liboctave/dNDArray.cc
+++ b/liboctave/dNDArray.cc
@@ -754,6 +754,30 @@
 }
 
 NDArray
+NDArray::cummax (int dim) const
+{
+  return do_mx_cumminmax_op<NDArray> (*this, dim, mx_inline_cummax);
+}
+
+NDArray
+NDArray::cummax (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<NDArray> (*this, idx_arg, dim, mx_inline_cummax);
+}
+
+NDArray
+NDArray::cummin (int dim) const
+{
+  return do_mx_cumminmax_op<NDArray> (*this, dim, mx_inline_cummin);
+}
+
+NDArray
+NDArray::cummin (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<NDArray> (*this, idx_arg, dim, mx_inline_cummin);
+}
+
+NDArray
 NDArray::concat (const NDArray& rb, const Array<octave_idx_type>& ra_idx)
 {
   if (rb.numel () > 0)
--- a/liboctave/dNDArray.h
+++ b/liboctave/dNDArray.h
@@ -97,6 +97,11 @@
   NDArray min (int dim = 0) const;
   NDArray min (ArrayN<octave_idx_type>& index, int dim = 0) const;
   
+  NDArray cummax (int dim = 0) const;
+  NDArray cummax (ArrayN<octave_idx_type>& index, int dim = 0) const;
+  NDArray cummin (int dim = 0) const;
+  NDArray cummin (ArrayN<octave_idx_type>& index, int dim = 0) const;
+
   NDArray& insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
   NDArray& insert (const NDArray& a, const Array<octave_idx_type>& ra_idx);
 
--- a/liboctave/fCNDArray.cc
+++ b/liboctave/fCNDArray.cc
@@ -709,6 +709,30 @@
   return do_mx_minmax_op<FloatComplexNDArray> (*this, idx_arg, dim, mx_inline_min);
 }
 
+FloatComplexNDArray
+FloatComplexNDArray::cummax (int dim) const
+{
+  return do_mx_cumminmax_op<FloatComplexNDArray> (*this, dim, mx_inline_cummax);
+}
+
+FloatComplexNDArray
+FloatComplexNDArray::cummax (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<FloatComplexNDArray> (*this, idx_arg, dim, mx_inline_cummax);
+}
+
+FloatComplexNDArray
+FloatComplexNDArray::cummin (int dim) const
+{
+  return do_mx_cumminmax_op<FloatComplexNDArray> (*this, dim, mx_inline_cummin);
+}
+
+FloatComplexNDArray
+FloatComplexNDArray::cummin (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<FloatComplexNDArray> (*this, idx_arg, dim, mx_inline_cummin);
+}
+
 FloatNDArray
 FloatComplexNDArray::abs (void) const
 {
--- a/liboctave/fCNDArray.h
+++ b/liboctave/fCNDArray.h
@@ -85,6 +85,12 @@
   FloatComplexNDArray max (ArrayN<octave_idx_type>& index, int dim = 0) const;
   FloatComplexNDArray min (int dim = 0) const;
   FloatComplexNDArray min (ArrayN<octave_idx_type>& index, int dim = 0) const;
+
+  FloatComplexNDArray cummax (int dim = 0) const;
+  FloatComplexNDArray cummax (ArrayN<octave_idx_type>& index, int dim = 0) const;
+  FloatComplexNDArray cummin (int dim = 0) const;
+  FloatComplexNDArray cummin (ArrayN<octave_idx_type>& index, int dim = 0) const;
+
   FloatComplexNDArray& insert (const NDArray& a, octave_idx_type r, octave_idx_type c);
   FloatComplexNDArray& insert (const FloatComplexNDArray& a, octave_idx_type r, octave_idx_type c);
   FloatComplexNDArray& insert (const FloatComplexNDArray& a, const Array<octave_idx_type>& ra_idx);
--- a/liboctave/fNDArray.cc
+++ b/liboctave/fNDArray.cc
@@ -709,6 +709,30 @@
 }
 
 FloatNDArray
+FloatNDArray::cummax (int dim) const
+{
+  return do_mx_cumminmax_op<FloatNDArray> (*this, dim, mx_inline_cummax);
+}
+
+FloatNDArray
+FloatNDArray::cummax (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<FloatNDArray> (*this, idx_arg, dim, mx_inline_cummax);
+}
+
+FloatNDArray
+FloatNDArray::cummin (int dim) const
+{
+  return do_mx_cumminmax_op<FloatNDArray> (*this, dim, mx_inline_cummin);
+}
+
+FloatNDArray
+FloatNDArray::cummin (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<FloatNDArray> (*this, idx_arg, dim, mx_inline_cummin);
+}
+
+FloatNDArray
 FloatNDArray::concat (const FloatNDArray& rb, const Array<octave_idx_type>& ra_idx)
 {
   if (rb.numel () > 0)
--- a/liboctave/fNDArray.h
+++ b/liboctave/fNDArray.h
@@ -94,6 +94,11 @@
   FloatNDArray min (int dim = 0) const;
   FloatNDArray min (ArrayN<octave_idx_type>& index, int dim = 0) const;
   
+  FloatNDArray cummax (int dim = 0) const;
+  FloatNDArray cummax (ArrayN<octave_idx_type>& index, int dim = 0) const;
+  FloatNDArray cummin (int dim = 0) const;
+  FloatNDArray cummin (ArrayN<octave_idx_type>& index, int dim = 0) const;
+
   FloatNDArray& insert (const FloatNDArray& a, octave_idx_type r, octave_idx_type c);
   FloatNDArray& insert (const FloatNDArray& a, const Array<octave_idx_type>& ra_idx);
 
--- a/liboctave/intNDArray.cc
+++ b/liboctave/intNDArray.cc
@@ -237,6 +237,34 @@
   return do_mx_minmax_op<intNDArray<T> > (*this, idx_arg, dim, mx_inline_min);
 }
 
+template <class T>
+intNDArray<T>
+intNDArray<T>::cummax (int dim) const
+{
+  return do_mx_cumminmax_op<intNDArray<T> > (*this, dim, mx_inline_cummax);
+}
+
+template <class T>
+intNDArray<T>
+intNDArray<T>::cummax (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<intNDArray<T> > (*this, idx_arg, dim, mx_inline_cummax);
+}
+
+template <class T>
+intNDArray<T>
+intNDArray<T>::cummin (int dim) const
+{
+  return do_mx_cumminmax_op<intNDArray<T> > (*this, dim, mx_inline_cummin);
+}
+
+template <class T>
+intNDArray<T>
+intNDArray<T>::cummin (ArrayN<octave_idx_type>& idx_arg, int dim) const
+{
+  return do_mx_cumminmax_op<intNDArray<T> > (*this, idx_arg, dim, mx_inline_cummin);
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/liboctave/intNDArray.h
+++ b/liboctave/intNDArray.h
@@ -78,6 +78,11 @@
   intNDArray min (int dim = 0) const;
   intNDArray min (ArrayN<octave_idx_type>& index, int dim = 0) const;
   
+  intNDArray cummax (int dim = 0) const;
+  intNDArray cummax (ArrayN<octave_idx_type>& index, int dim = 0) const;
+  intNDArray cummin (int dim = 0) const;
+  intNDArray cummin (ArrayN<octave_idx_type>& index, int dim = 0) const;
+  
   intNDArray sum (int dim) const;
 
   intNDArray abs (void) const;
--- a/liboctave/mx-inlines.cc
+++ b/liboctave/mx-inlines.cc
@@ -2,6 +2,8 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002,
               2003, 2004, 2005, 2006, 2007 John W. Eaton
+Copyright (C) 2009 Jaroslav Hajek
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -656,6 +658,186 @@
 OP_MINMAX_FCNN (mx_inline_min)
 OP_MINMAX_FCNN (mx_inline_max)
 
+#define OP_CUMMINMAX_FCN(F, OP) \
+template <class T> \
+void F (const T *v, T *r, octave_idx_type n) \
+{ \
+  if (! n) return; \
+  T tmp = v[0]; \
+  octave_idx_type i = 1, j = 0; \
+  if (xisnan (tmp)) \
+    { \
+      for (; i < n && xisnan (v[i]); i++) ; \
+      for (; j < i; j++) r[j] = tmp; \
+      if (i < n) tmp = v[i]; \
+    } \
+  for (; i < n; i++) \
+    if (v[i] OP tmp) \
+      { \
+        for (; j < i; j++) r[j] = tmp; \
+        tmp = v[i]; \
+      } \
+  for (; j < i; j++) r[j] = tmp; \
+} \
+template <class T> \
+void F (const T *v, T *r, octave_idx_type *ri, octave_idx_type n) \
+{ \
+  if (! n) return; \
+  T tmp = v[0]; octave_idx_type tmpi = 0; \
+  octave_idx_type i = 1, j = 0; \
+  if (xisnan (tmp)) \
+    { \
+      for (; i < n && xisnan (v[i]); i++) ; \
+      for (; j < i; j++) { r[j] = tmp; ri[j] = tmpi; } \
+      if (i < n) { tmp = v[i]; tmpi = i; } \
+    } \
+  for (; i < n; i++) \
+    if (v[i] OP tmp) \
+      { \
+        for (; j < i; j++) { r[j] = tmp; ri[j] = tmpi; } \
+        tmp = v[i]; tmpi = i; \
+      } \
+  for (; j < i; j++) { r[j] = tmp; ri[j] = tmpi; } \
+}
+
+OP_CUMMINMAX_FCN (mx_inline_cummin, <)
+OP_CUMMINMAX_FCN (mx_inline_cummax, >)
+
+// Row reductions will be slightly complicated.  We will proceed with checks
+// for NaNs until we detect that no row will yield a NaN, in which case we
+// proceed to a faster code.
+
+#define OP_CUMMINMAX_FCN2(F, OP) \
+template <class T> \
+inline void \
+F (const T *v, T *r, octave_idx_type m, octave_idx_type n) \
+{ \
+  if (! n) return; \
+  bool nan = false; \
+  const T *r0; \
+  octave_idx_type j = 0; \
+  for (octave_idx_type i = 0; i < m; i++) \
+    {  \
+      r[i] = v[i]; \
+      if (xisnan (v[i])) nan = true;  \
+    } \
+  j++; v += m; r0 = r; r += m; \
+  while (nan && j < n) \
+    { \
+      nan = false; \
+      for (octave_idx_type i = 0; i < m; i++) \
+        {  \
+          if (xisnan (v[i])) \
+            { r[i] = r0[i]; nan = true; } \
+          else if (xisnan (r[i]) || v[i] OP r[i]) \
+            r[i] = v[i]; \
+        } \
+      j++; v += m; r0 = r; r += m; \
+    } \
+  while (j < n) \
+    { \
+      for (octave_idx_type i = 0; i < m; i++) \
+        if (v[i] OP r[i]) \
+          r[i] = v[i]; \
+        else \
+          r[i] = r0[i]; \
+      j++; v += m; r0 = r; r += m; \
+    } \
+} \
+template <class T> \
+inline void \
+F (const T *v, T *r, octave_idx_type *ri, \
+   octave_idx_type m, octave_idx_type n) \
+{ \
+  if (! n) return; \
+  bool nan = false; \
+  const T *r0; const octave_idx_type *r0i; \
+  octave_idx_type j = 0; \
+  for (octave_idx_type i = 0; i < m; i++) \
+    {  \
+      r[i] = v[i]; ri[i] = 0; \
+      if (xisnan (v[i])) nan = true;  \
+    } \
+  j++; v += m; r0 = r; r += m; r0i = ri; ri += m;  \
+  while (nan && j < n) \
+    { \
+      nan = false; \
+      for (octave_idx_type i = 0; i < m; i++) \
+        {  \
+          if (xisnan (v[i])) \
+            { r[i] = r0[i]; ri[i] = r0i[i]; nan = true; } \
+          else if (xisnan (r[i]) || v[i] OP r[i]) \
+            { r[i] = v[i]; ri[i] = j; }\
+        } \
+      j++; v += m; r0 = r; r += m; r0i = ri; ri += m;  \
+    } \
+  while (j < n) \
+    { \
+      for (octave_idx_type i = 0; i < m; i++) \
+        if (v[i] OP r[i]) \
+          { r[i] = v[i]; ri[i] = j; } \
+        else \
+          { r[i] = r0[i]; ri[i] = r0i[i]; } \
+      j++; v += m; r0 = r; r += m; r0i = ri; ri += m;  \
+    } \
+}
+
+OP_CUMMINMAX_FCN2 (mx_inline_cummin, <)
+OP_CUMMINMAX_FCN2 (mx_inline_cummax, >)
+
+#define OP_CUMMINMAX_FCNN(F) \
+template <class T> \
+inline void \
+F (const T *v, T *r, octave_idx_type l, \
+   octave_idx_type n, octave_idx_type u) \
+{ \
+  if (! n) return; \
+  if (l == 1) \
+    { \
+      for (octave_idx_type i = 0; i < u; i++) \
+        { \
+          F (v, r, n); \
+          v += n; r += n; \
+        } \
+    } \
+  else \
+    { \
+      for (octave_idx_type i = 0; i < u; i++) \
+        { \
+          F (v, r, l, n); \
+          v += l*n; \
+          r += l*n; \
+        } \
+    } \
+} \
+template <class T> \
+inline void \
+F (const T *v, T *r, octave_idx_type *ri, \
+   octave_idx_type l, octave_idx_type n, octave_idx_type u) \
+{ \
+  if (! n) return; \
+  if (l == 1) \
+    { \
+      for (octave_idx_type i = 0; i < u; i++) \
+        { \
+          F (v, r, ri, n); \
+          v += n; r += n; ri += n; \
+        } \
+    } \
+  else \
+    { \
+      for (octave_idx_type i = 0; i < u; i++) \
+        { \
+          F (v, r, ri, l, n); \
+          v += l*n; \
+          r += l*n; ri += l*n; \
+        } \
+    } \
+}
+
+OP_CUMMINMAX_FCNN (mx_inline_cummin)
+OP_CUMMINMAX_FCNN (mx_inline_cummax)
+
 // Assistant function
 
 inline void
@@ -777,6 +959,44 @@
   return ret;
 }
 
+template <class ArrayType>
+inline ArrayType
+do_mx_cumminmax_op (const ArrayType& src, int dim,
+                    void (*mx_cumminmax_op) (const typename ArrayType::element_type *, 
+                                             typename ArrayType::element_type *,
+                                             octave_idx_type, octave_idx_type, octave_idx_type))
+{
+  octave_idx_type l, n, u;
+  dim_vector dims = src.dims ();
+  get_extent_triplet (dims, dim, l, n, u);
+
+  ArrayType ret (dims);
+  mx_cumminmax_op (src.data (), ret.fortran_vec (), l, n, u);
+
+  return ret;
+}
+
+template <class ArrayType>
+inline ArrayType
+do_mx_cumminmax_op (const ArrayType& src, Array<octave_idx_type>& idx, int dim,
+                    void (*mx_cumminmax_op) (const typename ArrayType::element_type *, 
+                                             typename ArrayType::element_type *,
+                                             octave_idx_type *,
+                                             octave_idx_type, octave_idx_type, octave_idx_type))
+{
+  octave_idx_type l, n, u;
+  dim_vector dims = src.dims ();
+  get_extent_triplet (dims, dim, l, n, u);
+
+  ArrayType ret (dims);
+  if (idx.dims () != dims) idx = Array<octave_idx_type> (dims);
+
+  mx_cumminmax_op (src.data (), ret.fortran_vec (), idx.fortran_vec (),
+                   l, n, u);
+
+  return ret;
+}
+
 #endif
 
 /*
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
+2009-02-17  Jaroslav Hajek  <highegg@gmail.com>
+
+	* DLD-FUNCTIONS/max.cc (MINMAX_DOUBLE_SBODY): New macro.
+	(MINMAX_DOUBLE_BODY): Move part of code to MINMAX_DOUBLE_SBODY.
+	(MINMAX_SINGLE_SBODY): New macro.
+	(MINMAX_SINGLE_BODY): Move part of code to MINMAX_DOUBLE_SBODY.
+	(MINMAX_INT_SBODY): New macro.
+	(MINMAX_INT_BODY): Move part of code to MINMAX_DOUBLE_SBODY.
+	(CUMMINMAX_BODY): New macro.
+	(Fcummin, Fcummax): New DLD functions.
+
 2009-02-17  John W. Eaton  <jwe@octave.org>
 
 	* octave.gperf: Eliminate whitespace to allow gperf 2.7.2 to work.
--- a/src/DLD-FUNCTIONS/max.cc
+++ b/src/DLD-FUNCTIONS/max.cc
@@ -2,6 +2,7 @@
 
 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
               2005, 2006, 2007 John W. Eaton
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -41,11 +42,9 @@
 #include "ov-re-sparse.h"
 #include "ov-cx-sparse.h"
 
-#define MINMAX_DOUBLE_BODY(FCN) \
+#define MINMAX_DOUBLE_SBODY(FCN) \
 { \
-  bool single_arg = (nargin == 1) || (arg2.is_empty() && nargin == 3);	\
- \
-  if (single_arg && (nargout == 1 || nargout == 0)) \
+  if (nargout == 1 || nargout == 0) \
     { \
       if (arg1.is_real_type ()) \
 	{ \
@@ -70,7 +69,7 @@
       else \
 	gripe_wrong_type_arg (#FCN, arg1); \
     } \
-  else if (single_arg && nargout == 2) \
+  else if (nargout == 2) \
     { \
       ArrayN<octave_idx_type> index; \
  \
@@ -104,6 +103,13 @@
       else \
 	retval(1) = NDArray (); \
     } \
+}
+
+#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 (); \
@@ -203,11 +209,9 @@
     } \
 }
 
-#define MINMAX_SINGLE_BODY(FCN) \
+#define MINMAX_SINGLE_SBODY(FCN) \
 { \
-  bool single_arg = (nargin == 1) || (arg2.is_empty() && nargin == 3);	\
- \
-  if (single_arg && (nargout == 1 || nargout == 0)) \
+  if (nargout == 1 || nargout == 0) \
     { \
       if (arg1.is_real_type ()) \
 	{ \
@@ -232,7 +236,7 @@
       else \
 	gripe_wrong_type_arg (#FCN, arg1); \
     } \
-  else if (single_arg && nargout == 2) \
+  else if (nargout == 2) \
     { \
       ArrayN<octave_idx_type> index; \
  \
@@ -266,6 +270,13 @@
       else \
 	retval(1) = NDArray (); \
     } \
+}
+
+#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 (); \
@@ -365,12 +376,9 @@
     } \
 }
 
-
-#define MINMAX_INT_BODY(FCN, TYP) \
- { \
-  bool single_arg = (nargin == 1) || (arg2.is_empty() && nargin == 3);	\
- \
-  if (single_arg && (nargout == 1 || nargout == 0)) \
+#define MINMAX_INT_SBODY(FCN, TYP) \
+{ \
+  if (nargout == 1 || nargout == 0) \
     { \
       TYP ## NDArray m = arg1. TYP ## _array_value (); \
  \
@@ -380,7 +388,7 @@
 	  retval(0) = n; \
 	} \
     } \
-  else if (single_arg && nargout == 2) \
+  else if (nargout == 2) \
     { \
       ArrayN<octave_idx_type> index; \
  \
@@ -399,6 +407,13 @@
       else \
 	retval(1) = NDArray (); \
     } \
+}
+
+#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 (); \
@@ -818,6 +833,128 @@
 
 */
 
+#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; \
+    } \
+ \
+  dim_vector dv = arg1.dims (); \
+  if (error_state) \
+    { \
+      gripe_wrong_type_arg (#FCN, arg1);  \
+      return retval; \
+    } \
+ \
+  int 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;
+
+DEFUN_DLD (cummin, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Mapping Function} {} cummin (@var{x}, @var{dim})\n\
+@deftypefnx {Mapping Function} {[@var{w}, @var{iw}] =} cummin (@var{x})\n\
+@cindex Utility Functions\n\
+Return the cumulative minimum values. That means, the call\n\
+@example\n\
+  [@var{w}, @var{iw}] = cummin (@var{x}, @var{dim})}\n\
+@end example\n\
+\n\
+@noindent\n\
+is equivalent to the following code:\n\
+@example\n\
+  for i = 1:size (x, dim)\n\
+    [w(i), iw(i)] = min(x(:,@dots{},i,:,@dots{}), dim);\n\
+  endfor\n\
+@end example\n\
+\n\
+@noindent\n\
+but computed in a much faster manner.\n\
+The behaviour if @var{dim} or @var{iw} is unspecified is analogous\n\
+to @code{min}.\n\
+@end deftypefn")
+{
+  CUMMINMAX_BODY (cummin);
+}
+
+DEFUN_DLD (cummax, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Mapping Function} {} cummax (@var{x}, @var{dim})\n\
+@deftypefnx {Mapping Function} {[@var{w}, @var{iw}] =} cummax (@var{x})\n\
+@cindex Utility Functions\n\
+Return the cumulative maximum values. That means, the call\n\
+@example\n\
+  [@var{w}, @var{iw}] = cummax (@var{x}, @var{dim})}\n\
+@end example\n\
+\n\
+@noindent\n\
+is equivalent to the following code:\n\
+@example\n\
+  for i = 1:size (x, dim)\n\
+    [w(i), iw(i)] = max(x(:,@dots{},i,:,@dots{}), dim);\n\
+  endfor\n\
+@end example\n\
+\n\
+@noindent\n\
+but computed in a much faster manner.\n\
+The behaviour if @var{dim} or @var{iw} is unspecified is analogous\n\
+to @code{max}.\n\
+@end deftypefn")
+{
+  CUMMINMAX_BODY (cummax);
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***