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
max.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 Copyright (C) 2009 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include "lo-ieee.h"
29 #include "lo-mappers.h"
30 #include "lo-math.h"
31 #include "dNDArray.h"
32 #include "CNDArray.h"
33 #include "quit.h"
34 
35 #include "defun.h"
36 #include "error.h"
37 #include "gripes.h"
38 #include "oct-obj.h"
39 
40 #include "ov-cx-mat.h"
41 #include "ov-re-sparse.h"
42 #include "ov-cx-sparse.h"
43 
44 template <class ArrayType>
45 static octave_value_list
47  int nargout, int dim, bool ismin)
48 {
49  octave_value_list retval;
50  ArrayType array = octave_value_extract<ArrayType> (arg);
51 
52  if (error_state)
53  return retval;
54 
55  if (nargout == 2)
56  {
57  retval.resize (2);
59  if (ismin)
60  retval(0) = array.min (idx, dim);
61  else
62  retval(0) = array.max (idx, dim);
63 
64  retval(1) = octave_value (idx, true, true);
65  }
66  else
67  {
68  if (ismin)
69  retval(0) = array.min (dim);
70  else
71  retval(0) = array.max (dim);
72  }
73 
74  return retval;
75 }
76 
77 // Matlab returns double arrays for min/max operations on character
78 // arrays, so we specialize here to get that behavior. Other possible
79 // solutions are to convert the argument to double here and call the
80 // code for double, but that could waste memory, or to have the
81 // underlying charNDArray::min/max functions return NDArray instead of
82 // charNDArray, but that is inconsistent with the way other min/max
83 // functions work.
84 
85 template <>
88  int nargout, int dim, bool ismin)
89 {
90  octave_value_list retval;
92 
93  if (error_state)
94  return retval;
95 
96  if (nargout == 2)
97  {
98  retval.resize (2);
100  if (ismin)
101  retval(0) = NDArray (array.min (idx, dim));
102  else
103  retval(0) = NDArray (array.max (idx, dim));
104 
105  retval(1) = octave_value (idx, true, true);
106  }
107  else
108  {
109  if (ismin)
110  retval(0) = NDArray (array.min (dim));
111  else
112  retval(0) = NDArray (array.max (dim));
113  }
114 
115  return retval;
116 }
117 
118 // Specialization for bool arrays.
119 template <>
122  int nargout, int dim, bool ismin)
123 {
124  octave_value_list retval;
125 
126  if (nargout <= 1)
127  {
128  // This case can be handled using any/all.
129  boolNDArray array = arg.bool_array_value ();
130 
131  if (array.is_empty ())
132  retval(0) = array;
133  else if (ismin)
134  retval(0) = array.all (dim);
135  else
136  retval(0) = array.any (dim);
137  }
138  else
139  {
140  // any/all don't have indexed versions, so do it via a conversion.
141  retval = do_minmax_red_op<int8NDArray> (arg, nargout, dim, ismin);
142  if (! error_state)
143  retval(0) = retval(0).bool_array_value ();
144  }
145 
146  return retval;
147 }
148 
149 template <class ArrayType>
150 static octave_value
151 do_minmax_bin_op (const octave_value& argx, const octave_value& argy,
152  bool ismin)
153 {
154  typedef typename ArrayType::element_type ScalarType;
155 
156  octave_value retval;
157 
158  if (argx.is_scalar_type () == 1)
159  {
160  ScalarType x = octave_value_extract<ScalarType> (argx);
161  ArrayType y = octave_value_extract<ArrayType> (argy);
162 
163  if (error_state)
164  ;
165  else if (ismin)
166  retval = min (x, y);
167  else
168  retval = max (x, y);
169  }
170  else if (argy.is_scalar_type () == 1)
171  {
172  ArrayType x = octave_value_extract<ArrayType> (argx);
173  ScalarType y = octave_value_extract<ScalarType> (argy);
174 
175  if (error_state)
176  ;
177  else if (ismin)
178  retval = min (x, y);
179  else
180  retval = max (x, y);
181  }
182  else
183  {
184  ArrayType x = octave_value_extract<ArrayType> (argx);
185  ArrayType y = octave_value_extract<ArrayType> (argy);
186 
187  if (error_state)
188  ;
189  else if (ismin)
190  retval = min (x, y);
191  else
192  retval = max (x, y);
193  }
194 
195  return retval;
196 }
197 
198 // Matlab returns double arrays for min/max operations on character
199 // arrays, so we specialize here to get that behavior. Other possible
200 // solutions are to convert the arguments to double here and call the
201 // code for double, but that could waste a lot of memory, or to have the
202 // underlying charNDArray::min/max functions return NDArray instead of
203 // charNDArray, but that is inconsistent with the way other min/max
204 // functions work.
205 
206 template <>
209  const octave_value& argy, bool ismin)
210 {
211  octave_value retval;
212 
213  if (argx.is_scalar_type () == 1)
214  {
215  char x = octave_value_extract<char> (argx);
217 
218  if (error_state)
219  ;
220  else if (ismin)
221  retval = NDArray (min (x, y));
222  else
223  retval = NDArray (max (x, y));
224  }
225  else if (argy.is_scalar_type () == 1)
226  {
228  char y = octave_value_extract<char> (argy);
229 
230  if (error_state)
231  ;
232  else if (ismin)
233  retval = NDArray (min (x, y));
234  else
235  retval = NDArray (max (x, y));
236  }
237  else
238  {
241 
242  if (error_state)
243  ;
244  else if (ismin)
245  retval = NDArray (min (x, y));
246  else
247  retval = NDArray (max (x, y));
248  }
249 
250  return retval;
251 }
252 
253 static octave_value_list
255  int nargout, bool ismin)
256 {
257  octave_value_list retval;
258 
259  const char *func = ismin ? "min" : "max";
260 
261  int nargin = args.length ();
262 
263  if (nargin == 3 || nargin == 1)
264  {
265  octave_value arg = args(0);
266  int dim = -1;
267  if (nargin == 3)
268  {
269  dim = args(2).int_value (true) - 1;
270  if (error_state || dim < 0)
271  {
272  error ("%s: DIM must be a valid dimension", func);
273  return retval;
274  }
275 
276  if (! args(1).is_empty ())
277  warning ("%s: second argument is ignored", func);
278  }
279 
280  switch (arg.builtin_type ())
281  {
282  case btyp_double:
283  {
284  if (arg.is_range () && (dim == -1 || dim == 1))
285  {
286  Range range = arg.range_value ();
287  if (range.nelem () == 0)
288  {
289  retval(0) = arg;
290  if (nargout > 1)
291  retval(1) = arg;
292  }
293  else if (ismin)
294  {
295  retval(0) = range.min ();
296  if (nargout > 1)
297  retval(1) = static_cast<double>
298  (range.inc () < 0 ? range.nelem () : 1);
299  }
300  else
301  {
302  retval(0) = range.max ();
303  if (nargout > 1)
304  retval(1) = static_cast<double>
305  (range.inc () >= 0 ? range.nelem () : 1);
306  }
307  }
308  else if (arg.is_sparse_type ())
309  retval = do_minmax_red_op<SparseMatrix> (arg, nargout, dim,
310  ismin);
311  else
312  retval = do_minmax_red_op<NDArray> (arg, nargout, dim, ismin);
313  break;
314  }
315  case btyp_complex:
316  {
317  if (arg.is_sparse_type ())
318  retval = do_minmax_red_op<SparseComplexMatrix> (arg, nargout, dim,
319  ismin);
320  else
321  retval = do_minmax_red_op<ComplexNDArray> (arg, nargout, dim,
322  ismin);
323  break;
324  }
325  case btyp_float:
326  retval = do_minmax_red_op<FloatNDArray> (arg, nargout, dim, ismin);
327  break;
328  case btyp_float_complex:
329  retval = do_minmax_red_op<FloatComplexNDArray> (arg, nargout, dim,
330  ismin);
331  break;
332  case btyp_char:
333  retval = do_minmax_red_op<charNDArray> (arg, nargout, dim, ismin);
334  break;
335 #define MAKE_INT_BRANCH(X) \
336  case btyp_ ## X: \
337  retval = do_minmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \
338  break;
339  MAKE_INT_BRANCH (int8);
340  MAKE_INT_BRANCH (int16);
341  MAKE_INT_BRANCH (int32);
342  MAKE_INT_BRANCH (int64);
343  MAKE_INT_BRANCH (uint8);
344  MAKE_INT_BRANCH (uint16);
345  MAKE_INT_BRANCH (uint32);
346  MAKE_INT_BRANCH (uint64);
347 #undef MAKE_INT_BRANCH
348  case btyp_bool:
349  retval = do_minmax_red_op<boolNDArray> (arg, nargout, dim, ismin);
350  break;
351  default:
352  gripe_wrong_type_arg (func, arg);
353  }
354  }
355  else if (nargin == 2)
356  {
357  octave_value argx = args(0), argy = args(1);
358  builtin_type_t xtyp = argx.builtin_type (), ytyp = argy.builtin_type ();
359  builtin_type_t rtyp;
360  if (xtyp == btyp_char && ytyp == btyp_char)
361  rtyp = btyp_char;
362  else
363  rtyp = btyp_mixed_numeric (xtyp, ytyp);
364 
365  switch (rtyp)
366  {
367  case btyp_double:
368  {
369  if ((argx.is_sparse_type ()
370  && (argy.is_sparse_type () || argy.is_scalar_type ()))
371  || (argy.is_sparse_type () && argx.is_scalar_type ()))
372  retval = do_minmax_bin_op<SparseMatrix> (argx, argy, ismin);
373  else
374  retval = do_minmax_bin_op<NDArray> (argx, argy, ismin);
375  break;
376  }
377  case btyp_complex:
378  {
379  if ((argx.is_sparse_type ()
380  && (argy.is_sparse_type () || argy.is_scalar_type ()))
381  || (argy.is_sparse_type () && argx.is_scalar_type ()))
382  retval = do_minmax_bin_op<SparseComplexMatrix> (argx, argy,
383  ismin);
384  else
385  retval = do_minmax_bin_op<ComplexNDArray> (argx, argy, ismin);
386  break;
387  }
388  case btyp_float:
389  retval = do_minmax_bin_op<FloatNDArray> (argx, argy, ismin);
390  break;
391  case btyp_float_complex:
392  retval = do_minmax_bin_op<FloatComplexNDArray> (argx, argy, ismin);
393  break;
394  case btyp_char:
395  retval = do_minmax_bin_op<charNDArray> (argx, argy, ismin);
396  break;
397 #define MAKE_INT_BRANCH(X) \
398  case btyp_ ## X: \
399  retval = do_minmax_bin_op<X ## NDArray> (argx, argy, ismin); \
400  break;
401  MAKE_INT_BRANCH (int8);
402  MAKE_INT_BRANCH (int16);
403  MAKE_INT_BRANCH (int32);
404  MAKE_INT_BRANCH (int64);
405  MAKE_INT_BRANCH (uint8);
406  MAKE_INT_BRANCH (uint16);
407  MAKE_INT_BRANCH (uint32);
408  MAKE_INT_BRANCH (uint64);
409 #undef MAKE_INT_BRANCH
410  default:
411  error ("%s: cannot compute %s (%s, %s)", func, func,
412  argx.type_name ().c_str (), argy.type_name ().c_str ());
413  }
414  }
415  else
416  print_usage ();
417 
418  return retval;
419 }
420 
421 DEFUN (min, args, nargout,
422  "-*- texinfo -*-\n\
423 @deftypefn {Built-in Function} {} min (@var{x})\n\
424 @deftypefnx {Built-in Function} {} min (@var{x}, @var{y})\n\
425 @deftypefnx {Built-in Function} {} min (@var{x}, [], @var{dim})\n\
426 @deftypefnx {Built-in Function} {} min (@var{x}, @var{y}, @var{dim})\n\
427 @deftypefnx {Built-in Function} {[@var{w}, @var{iw}] =} min (@var{x})\n\
428 For a vector argument, return the minimum value. For a matrix\n\
429 argument, return the minimum value from each column, as a row\n\
430 vector, or over the dimension @var{dim} if defined, in which case @var{y} \n\
431 should be set to the empty matrix (it's ignored otherwise). For two matrices\n\
432 (or a matrix and scalar), return the pair-wise minimum.\n\
433 Thus,\n\
434 \n\
435 @example\n\
436 min (min (@var{x}))\n\
437 @end example\n\
438 \n\
439 @noindent\n\
440 returns the smallest element of @var{x}, and\n\
441 \n\
442 @example\n\
443 @group\n\
444 min (2:5, pi)\n\
445  @result{} 2.0000 3.0000 3.1416 3.1416\n\
446 @end group\n\
447 @end example\n\
448 \n\
449 @noindent\n\
450 compares each element of the range @code{2:5} with @code{pi}, and\n\
451 returns a row vector of the minimum values.\n\
452 \n\
453 For complex arguments, the magnitude of the elements are used for\n\
454 comparison.\n\
455 \n\
456 If called with one input and two output arguments,\n\
457 @code{min} also returns the first index of the\n\
458 minimum value(s). Thus,\n\
459 \n\
460 @example\n\
461 @group\n\
462 [x, ix] = min ([1, 3, 0, 2, 0])\n\
463  @result{} x = 0\n\
464  ix = 3\n\
465 @end group\n\
466 @end example\n\
467 @seealso{max, cummin, cummax}\n\
468 @end deftypefn")
469 {
470  return do_minmax_body (args, nargout, true);
471 }
472 
473 /*
474 %!assert (min ([1, 4, 2, 3]), 1)
475 %!assert (min ([1; -10; 5; -2]), -10)
476 %!assert (min ([4, i; -2, 2]), [-2, i])
477 %!assert (min (char(42)), 42)
478 %!assert (min (char(21), char(3)), 3)
479 %!assert (min([char(21), char(3)]), 3)
480 %!assert (min([char(100) char(3)], [char(42) char(42)]), [42 3])
481 
482 %!test
483 %! x = reshape (1:8, [2,2,2]);
484 %! assert (max (x, [], 1), reshape ([2, 4, 6, 8], [1,2,2]));
485 %! assert (max (x, [], 2), reshape ([3, 4, 7, 8], [2,1,2]));
486 %! [y, i] = max (x, [], 3);
487 %! assert (ndims (y), 2);
488 %! assert (y, [5, 7; 6, 8]);
489 %! assert (ndims (i), 2);
490 %! assert (i, [2, 2; 2, 2]);
491 
492 %!error min ()
493 %!error min (1, 2, 3, 4)
494 */
495 
496 DEFUN (max, args, nargout,
497  "-*- texinfo -*-\n\
498 @deftypefn {Built-in Function} {} max (@var{x})\n\
499 @deftypefnx {Built-in Function} {} max (@var{x}, @var{y})\n\
500 @deftypefnx {Built-in Function} {} max (@var{x}, [], @var{dim})\n\
501 @deftypefnx {Built-in Function} {} max (@var{x}, @var{y}, @var{dim})\n\
502 @deftypefnx {Built-in Function} {[@var{w}, @var{iw}] =} max (@var{x})\n\
503 For a vector argument, return the maximum value. For a matrix\n\
504 argument, return the maximum value from each column, as a row\n\
505 vector, or over the dimension @var{dim} if defined, in which case @var{y} \n\
506 should be set to the empty matrix (it's ignored otherwise). For two matrices\n\
507 (or a matrix and scalar), return the pair-wise maximum.\n\
508 Thus,\n\
509 \n\
510 @example\n\
511 max (max (@var{x}))\n\
512 @end example\n\
513 \n\
514 @noindent\n\
515 returns the largest element of the matrix @var{x}, and\n\
516 \n\
517 @example\n\
518 @group\n\
519 max (2:5, pi)\n\
520  @result{} 3.1416 3.1416 4.0000 5.0000\n\
521 @end group\n\
522 @end example\n\
523 \n\
524 @noindent\n\
525 compares each element of the range @code{2:5} with @code{pi}, and\n\
526 returns a row vector of the maximum values.\n\
527 \n\
528 For complex arguments, the magnitude of the elements are used for\n\
529 comparison.\n\
530 \n\
531 If called with one input and two output arguments,\n\
532 @code{max} also returns the first index of the\n\
533 maximum value(s). Thus,\n\
534 \n\
535 @example\n\
536 @group\n\
537 [x, ix] = max ([1, 3, 5, 2, 5])\n\
538  @result{} x = 5\n\
539  ix = 3\n\
540 @end group\n\
541 @end example\n\
542 @seealso{min, cummax, cummin}\n\
543 @end deftypefn")
544 {
545  return do_minmax_body (args, nargout, false);
546 }
547 
548 /*
549 %!assert (max ([1, 4, 2, 3]), 4)
550 %!assert (max ([1; -10; 5; -2]), 5)
551 %!assert (max ([4, i 4.999; -2, 2, 3+4i]), [4, 2, 3+4i])
552 
553 %!test
554 %! x = reshape (1:8, [2,2,2]);
555 %! assert (min (x, [], 1), reshape ([1, 3, 5, 7], [1,2,2]));
556 %! assert (min (x, [], 2), reshape ([1, 2, 5, 6], [2,1,2]));
557 %! [y, i] = min (x, [], 3);
558 %! assert (ndims(y), 2);
559 %! assert (y, [1, 3; 2, 4]);
560 %! assert (ndims(i), 2);
561 %! assert (i, [1, 1; 1, 1]);
562 
563 %!error max ()
564 %!error max (1, 2, 3, 4)
565 */
566 
567 template <class ArrayType>
568 static octave_value_list
570  int nargout, int dim, bool ismin)
571 {
572  octave_value_list retval;
573  ArrayType array = octave_value_extract<ArrayType> (arg);
574 
575  if (error_state)
576  return retval;
577 
578  if (nargout == 2)
579  {
580  retval.resize (2);
582  if (ismin)
583  retval(0) = array.cummin (idx, dim);
584  else
585  retval(0) = array.cummax (idx, dim);
586 
587  retval(1) = octave_value (idx, true, true);
588  }
589  else
590  {
591  if (ismin)
592  retval(0) = array.cummin (dim);
593  else
594  retval(0) = array.cummax (dim);
595  }
596 
597  return retval;
598 }
599 
600 static octave_value_list
602  int nargout, bool ismin)
603 {
604  octave_value_list retval;
605 
606  const char *func = ismin ? "cummin" : "cummax";
607 
608  int nargin = args.length ();
609 
610  if (nargin == 1 || nargin == 2)
611  {
612  octave_value arg = args(0);
613  int dim = -1;
614  if (nargin == 2)
615  {
616  dim = args(1).int_value (true) - 1;
617  if (error_state || dim < 0)
618  {
619  error ("%s: DIM must be a valid dimension", func);
620  return retval;
621  }
622  }
623 
624  switch (arg.builtin_type ())
625  {
626  case btyp_double:
627  retval = do_cumminmax_red_op<NDArray> (arg, nargout, dim, ismin);
628  break;
629  case btyp_complex:
630  retval = do_cumminmax_red_op<ComplexNDArray> (arg, nargout, dim,
631  ismin);
632  break;
633  case btyp_float:
634  retval = do_cumminmax_red_op<FloatNDArray> (arg, nargout, dim, ismin);
635  break;
636  case btyp_float_complex:
637  retval = do_cumminmax_red_op<FloatComplexNDArray> (arg, nargout, dim,
638  ismin);
639  break;
640 #define MAKE_INT_BRANCH(X) \
641  case btyp_ ## X: \
642  retval = do_cumminmax_red_op<X ## NDArray> (arg, nargout, dim, \
643  ismin); \
644  break;
645  MAKE_INT_BRANCH (int8);
646  MAKE_INT_BRANCH (int16);
647  MAKE_INT_BRANCH (int32);
648  MAKE_INT_BRANCH (int64);
649  MAKE_INT_BRANCH (uint8);
650  MAKE_INT_BRANCH (uint16);
651  MAKE_INT_BRANCH (uint32);
652  MAKE_INT_BRANCH (uint64);
653 #undef MAKE_INT_BRANCH
654  case btyp_bool:
655  {
656  retval = do_cumminmax_red_op<int8NDArray> (arg, nargout, dim,
657  ismin);
658  if (retval.length () > 0)
659  retval(0) = retval(0).bool_array_value ();
660  break;
661  }
662  default:
663  gripe_wrong_type_arg (func, arg);
664  }
665  }
666  else
667  print_usage ();
668 
669  return retval;
670 }
671 
672 DEFUN (cummin, args, nargout,
673  "-*- texinfo -*-\n\
674 @deftypefn {Built-in Function} {} cummin (@var{x})\n\
675 @deftypefnx {Built-in Function} {} cummin (@var{x}, @var{dim})\n\
676 @deftypefnx {Built-in Function} {[@var{w}, @var{iw}] =} cummin (@var{x})\n\
677 Return the cumulative minimum values along dimension @var{dim}.\n\
678 \n\
679 If @var{dim} is unspecified it defaults to column-wise operation. For\n\
680 example:\n\
681 \n\
682 @example\n\
683 @group\n\
684 cummin ([5 4 6 2 3 1])\n\
685  @result{} 5 4 4 2 2 1\n\
686 @end group\n\
687 @end example\n\
688 \n\
689 If called with two output arguments the index of the minimum value is also\n\
690 returned.\n\
691 \n\
692 @example\n\
693 @group\n\
694 [w, iw] = cummin ([5 4 6 2 3 1])\n\
695 @result{}\n\
696 w = 5 4 4 2 2 1\n\
697 iw = 1 2 2 4 4 6\n\
698 @end group\n\
699 @end example\n\
700 \n\
701 @seealso{cummax, min, max}\n\
702 @end deftypefn")
703 {
704  return do_cumminmax_body (args, nargout, true);
705 }
706 
707 /*
708 %!assert (cummin ([1, 4, 2, 3]), [1 1 1 1])
709 %!assert (cummin ([1; -10; 5; -2]), [1; -10; -10; -10])
710 %!assert (cummin ([4, i; -2, 2]), [4, i; -2, i])
711 
712 %!test
713 %! x = reshape (1:8, [2,2,2]);
714 %! assert (cummin (x, 1), reshape ([1 1 3 3 5 5 7 7], [2,2,2]));
715 %! assert (cummin (x, 2), reshape ([1 2 1 2 5 6 5 6], [2,2,2]));
716 %! [w, iw] = cummin (x, 3);
717 %! assert (ndims (w), 3);
718 %! assert (w, repmat ([1 3; 2 4], [1 1 2]));
719 %! assert (ndims (iw), 3);
720 %! assert (iw, ones (2,2,2));
721 
722 %!error cummin ()
723 %!error cummin (1, 2, 3)
724 */
725 
726 DEFUN (cummax, args, nargout,
727  "-*- texinfo -*-\n\
728 @deftypefn {Built-in Function} {} cummax (@var{x})\n\
729 @deftypefnx {Built-in Function} {} cummax (@var{x}, @var{dim})\n\
730 @deftypefnx {Built-in Function} {[@var{w}, @var{iw}] =} cummax (@dots{})\n\
731 Return the cumulative maximum values along dimension @var{dim}.\n\
732 \n\
733 If @var{dim} is unspecified it defaults to column-wise operation. For\n\
734 example:\n\
735 \n\
736 @example\n\
737 @group\n\
738 cummax ([1 3 2 6 4 5])\n\
739  @result{} 1 3 3 6 6 6\n\
740 @end group\n\
741 @end example\n\
742 \n\
743 If called with two output arguments the index of the maximum value is also\n\
744 returned.\n\
745 \n\
746 @example\n\
747 @group\n\
748 [w, iw] = cummax ([1 3 2 6 4 5])\n\
749 @result{}\n\
750 w = 1 3 3 6 6 6\n\
751 iw = 1 2 2 4 4 4\n\
752 @end group\n\
753 @end example\n\
754 \n\
755 @seealso{cummin, max, min}\n\
756 @end deftypefn")
757 {
758  return do_cumminmax_body (args, nargout, false);
759 }
760 
761 /*
762 %!assert (cummax ([1, 4, 2, 3]), [1 4 4 4])
763 %!assert (cummax ([1; -10; 5; -2]), [1; 1; 5; 5])
764 %!assert (cummax ([4, i 4.9, -2, 2, 3+4i]), [4, 4, 4.9, 4.9, 4.9, 3+4i])
765 
766 %!test
767 %! x = reshape (8:-1:1, [2,2,2]);
768 %! assert (cummax (x, 1), reshape ([8 8 6 6 4 4 2 2], [2,2,2]));
769 %! assert (cummax (x, 2), reshape ([8 7 8 7 4 3 4 3], [2,2,2]));
770 %! [w, iw] = cummax (x, 3);
771 %! assert (ndims (w), 3);
772 %! assert (w, repmat ([8 6; 7 5], [1 1 2]));
773 %! assert (ndims (iw), 3);
774 %! assert (iw, ones (2,2,2));
775 
776 %!error cummax ()
777 %!error cummax (1, 2, 3)
778 */
779