max.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 Copyright (C) 2009 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include "lo-ieee.h"
00029 #include "lo-mappers.h"
00030 #include "lo-math.h"
00031 #include "dNDArray.h"
00032 #include "CNDArray.h"
00033 #include "quit.h"
00034 
00035 #include "defun-dld.h"
00036 #include "error.h"
00037 #include "gripes.h"
00038 #include "oct-obj.h"
00039 
00040 #include "ov-cx-mat.h"
00041 #include "ov-re-sparse.h"
00042 #include "ov-cx-sparse.h"
00043 
00044 template <class ArrayType>
00045 static octave_value_list
00046 do_minmax_red_op (const octave_value& arg,
00047                   int nargout, int dim, bool ismin)
00048 {
00049   octave_value_list retval;
00050   ArrayType array = octave_value_extract<ArrayType> (arg);
00051 
00052   if (error_state)
00053     return retval;
00054 
00055   if (nargout == 2)
00056     {
00057       retval.resize (2);
00058       Array<octave_idx_type> idx;
00059       if (ismin)
00060         retval(0) = array.min (idx, dim);
00061       else
00062         retval(0) = array.max (idx, dim);
00063 
00064       retval(1) = octave_value (idx, true, true);
00065     }
00066   else
00067     {
00068       if (ismin)
00069         retval(0) = array.min (dim);
00070       else
00071         retval(0) = array.max (dim);
00072     }
00073 
00074   return retval;
00075 }
00076 
00077 // Specialization for bool arrays.
00078 template <>
00079 octave_value_list
00080 do_minmax_red_op<boolNDArray> (const octave_value& arg,
00081                                int nargout, int dim, bool ismin)
00082 {
00083   octave_value_list retval;
00084 
00085   if (nargout <= 1)
00086     {
00087       // This case can be handled using any/all.
00088       boolNDArray array = arg.bool_array_value ();
00089 
00090       if (array.is_empty ())
00091         retval(0) = array;
00092       else if (ismin)
00093         retval(0) = array.all (dim);
00094       else
00095         retval(0) = array.any (dim);
00096     }
00097   else
00098     {
00099       // any/all don't have indexed versions, so do it via a conversion.
00100       retval = do_minmax_red_op<int8NDArray> (arg, nargout, dim, ismin);
00101       if (! error_state)
00102         retval(0) = retval(0).bool_array_value ();
00103     }
00104 
00105   return retval;
00106 }
00107 
00108 template <class ArrayType>
00109 static octave_value
00110 do_minmax_bin_op (const octave_value& argx, const octave_value& argy,
00111                   bool ismin)
00112 {
00113   typedef typename ArrayType::element_type ScalarType;
00114 
00115   octave_value retval;
00116 
00117   if (argx.is_scalar_type () == 1)
00118     {
00119       ScalarType x = octave_value_extract<ScalarType> (argx);
00120       ArrayType y = octave_value_extract<ArrayType> (argy);
00121 
00122       if (error_state)
00123         ;
00124       else if (ismin)
00125         retval = min (x, y);
00126       else
00127         retval = max (x, y);
00128     }
00129   else if (argy.is_scalar_type () == 1)
00130     {
00131       ArrayType x = octave_value_extract<ArrayType> (argx);
00132       ScalarType y = octave_value_extract<ScalarType> (argy);
00133 
00134       if (error_state)
00135         ;
00136       else if (ismin)
00137         retval = min (x, y);
00138       else
00139         retval = max (x, y);
00140     }
00141   else
00142     {
00143       ArrayType x = octave_value_extract<ArrayType> (argx);
00144       ArrayType y = octave_value_extract<ArrayType> (argy);
00145 
00146       if (error_state)
00147         ;
00148       else if (ismin)
00149         retval = min (x, y);
00150       else
00151         retval = max (x, y);
00152     }
00153 
00154   return retval;
00155 }
00156 
00157 static octave_value_list
00158 do_minmax_body (const octave_value_list& args,
00159                 int nargout, bool ismin)
00160 {
00161   octave_value_list retval;
00162 
00163   const char *func = ismin ? "min" : "max";
00164 
00165   int nargin = args.length ();
00166 
00167   if (nargin == 3 || nargin == 1)
00168     {
00169       octave_value arg = args(0);
00170       int dim = -1;
00171       if (nargin == 3)
00172         {
00173           dim = args(2).int_value (true) - 1;
00174           if (error_state || dim < 0)
00175             {
00176               error ("%s: DIM must be a valid dimension", func);
00177               return retval;
00178             }
00179 
00180           if (! args(1).is_empty ())
00181             warning ("%s: second argument is ignored", func);
00182         }
00183 
00184       switch (arg.builtin_type ())
00185         {
00186         case btyp_double:
00187           {
00188             if (arg.is_range () && (dim == -1 || dim == 1))
00189               {
00190                 Range range = arg.range_value ();
00191                 if (range.nelem () == 0)
00192                   {
00193                     retval(0) = arg;
00194                     if (nargout > 1)
00195                       retval(1) = arg;
00196                   }
00197                 else if (ismin)
00198                   {
00199                     retval(0) = range.min ();
00200                     if (nargout > 1)
00201                       retval(1) = static_cast<double> (range.inc () < 0 ? range.nelem () : 1);
00202                   }
00203                 else
00204                   {
00205                     retval(0) = range.max ();
00206                     if (nargout > 1)
00207                       retval(1) = static_cast<double> (range.inc () >= 0 ? range.nelem () : 1);
00208                   }
00209               }
00210             else if (arg.is_sparse_type ())
00211               retval = do_minmax_red_op<SparseMatrix> (arg, nargout, dim, ismin);
00212             else
00213               retval = do_minmax_red_op<NDArray> (arg, nargout, dim, ismin);
00214             break;
00215           }
00216         case btyp_complex:
00217           {
00218             if (arg.is_sparse_type ())
00219               retval = do_minmax_red_op<SparseComplexMatrix> (arg, nargout, dim, ismin);
00220             else
00221               retval = do_minmax_red_op<ComplexNDArray> (arg, nargout, dim, ismin);
00222             break;
00223           }
00224         case btyp_float:
00225           retval = do_minmax_red_op<FloatNDArray> (arg, nargout, dim, ismin);
00226           break;
00227         case btyp_float_complex:
00228           retval = do_minmax_red_op<FloatComplexNDArray> (arg, nargout, dim, ismin);
00229           break;
00230 #define MAKE_INT_BRANCH(X) \
00231         case btyp_ ## X: \
00232           retval = do_minmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \
00233           break;
00234         MAKE_INT_BRANCH (int8);
00235         MAKE_INT_BRANCH (int16);
00236         MAKE_INT_BRANCH (int32);
00237         MAKE_INT_BRANCH (int64);
00238         MAKE_INT_BRANCH (uint8);
00239         MAKE_INT_BRANCH (uint16);
00240         MAKE_INT_BRANCH (uint32);
00241         MAKE_INT_BRANCH (uint64);
00242 #undef MAKE_INT_BRANCH
00243         case btyp_bool:
00244           retval = do_minmax_red_op<boolNDArray> (arg, nargout, dim, ismin);
00245           break;
00246         default:
00247           gripe_wrong_type_arg (func, arg);
00248       }
00249     }
00250   else if (nargin == 2)
00251     {
00252       octave_value argx = args(0), argy = args(1);
00253       builtin_type_t xtyp = argx.builtin_type (), ytyp = argy.builtin_type ();
00254       builtin_type_t rtyp = btyp_mixed_numeric (xtyp, ytyp);
00255 
00256       switch (rtyp)
00257         {
00258         case btyp_double:
00259           {
00260             if ((argx.is_sparse_type ()
00261                  && (argy.is_sparse_type () || argy.is_scalar_type ()))
00262                 || (argy.is_sparse_type () && argx.is_scalar_type ()))
00263               retval = do_minmax_bin_op<SparseMatrix> (argx, argy, ismin);
00264             else
00265               retval = do_minmax_bin_op<NDArray> (argx, argy, ismin);
00266             break;
00267           }
00268         case btyp_complex:
00269           {
00270             if ((argx.is_sparse_type ()
00271                  && (argy.is_sparse_type () || argy.is_scalar_type ()))
00272                 || (argy.is_sparse_type () && argx.is_scalar_type ()))
00273               retval = do_minmax_bin_op<SparseComplexMatrix> (argx, argy, ismin);
00274             else
00275               retval = do_minmax_bin_op<ComplexNDArray> (argx, argy, ismin);
00276             break;
00277           }
00278         case btyp_float:
00279           retval = do_minmax_bin_op<FloatNDArray> (argx, argy, ismin);
00280           break;
00281         case btyp_float_complex:
00282           retval = do_minmax_bin_op<FloatComplexNDArray> (argx, argy, ismin);
00283           break;
00284 #define MAKE_INT_BRANCH(X) \
00285         case btyp_ ## X: \
00286           retval = do_minmax_bin_op<X ## NDArray> (argx, argy, ismin); \
00287           break;
00288         MAKE_INT_BRANCH (int8);
00289         MAKE_INT_BRANCH (int16);
00290         MAKE_INT_BRANCH (int32);
00291         MAKE_INT_BRANCH (int64);
00292         MAKE_INT_BRANCH (uint8);
00293         MAKE_INT_BRANCH (uint16);
00294         MAKE_INT_BRANCH (uint32);
00295         MAKE_INT_BRANCH (uint64);
00296 #undef MAKE_INT_BRANCH
00297         default:
00298           error ("%s: cannot compute %s (%s, %s)", func, func,
00299                  argx.type_name ().c_str (), argy.type_name ().c_str ());
00300         }
00301     }
00302   else
00303     print_usage ();
00304 
00305   return retval;
00306 }
00307 
00308 DEFUN_DLD (min, args, nargout,
00309   "-*- texinfo -*-\n\
00310 @deftypefn  {Loadable Function} {} min (@var{x})\n\
00311 @deftypefnx {Loadable Function} {} min (@var{x}, @var{y})\n\
00312 @deftypefnx {Loadable Function} {} min (@var{x}, [], @var{dim})\n\
00313 @deftypefnx {Loadable Function} {} min (@var{x}, @var{y}, @var{dim})\n\
00314 @deftypefnx {Loadable Function} {[@var{w}, @var{iw}] =} min (@var{x})\n\
00315 For a vector argument, return the minimum value.  For a matrix\n\
00316 argument, return the minimum value from each column, as a row\n\
00317 vector, or over the dimension @var{dim} if defined, in which case @var{y} \n\
00318 should be set to the empty matrix (it's ignored otherwise).  For two matrices\n\
00319 (or a matrix and scalar), return the pair-wise minimum.\n\
00320 Thus,\n\
00321 \n\
00322 @example\n\
00323 min (min (@var{x}))\n\
00324 @end example\n\
00325 \n\
00326 @noindent\n\
00327 returns the smallest element of @var{x}, and\n\
00328 \n\
00329 @example\n\
00330 @group\n\
00331 min (2:5, pi)\n\
00332     @result{}  2.0000  3.0000  3.1416  3.1416\n\
00333 @end group\n\
00334 @end example\n\
00335 \n\
00336 @noindent\n\
00337 compares each element of the range @code{2:5} with @code{pi}, and\n\
00338 returns a row vector of the minimum values.\n\
00339 \n\
00340 For complex arguments, the magnitude of the elements are used for\n\
00341 comparison.\n\
00342 \n\
00343 If called with one input and two output arguments,\n\
00344 @code{min} also returns the first index of the\n\
00345 minimum value(s).  Thus,\n\
00346 \n\
00347 @example\n\
00348 @group\n\
00349 [x, ix] = min ([1, 3, 0, 2, 0])\n\
00350     @result{}  x = 0\n\
00351         ix = 3\n\
00352 @end group\n\
00353 @end example\n\
00354 @seealso{max, cummin, cummax}\n\
00355 @end deftypefn")
00356 {
00357   return do_minmax_body (args, nargout, true);
00358 }
00359 
00360 /*
00361 
00362 %% test/octave.test/arith/min-1.m
00363 %!assert (min ([1, 4, 2, 3]) == 1);
00364 %!assert (min ([1; -10; 5; -2]) == -10);
00365 
00366 %% test/octave.test/arith/min-2.m
00367 %!assert(all (min ([4, i; -2, 2]) == [-2, i]));
00368 
00369 %% test/octave.test/arith/min-3.m
00370 %!error <Invalid call to min> min ();
00371 
00372 %% test/octave.test/arith/min-4.m
00373 %!error <Invalid call to min> min (1, 2, 3, 4);
00374 
00375 %!test
00376 %! x = reshape (1:8,[2,2,2]);
00377 %! assert (max (x,[],1), reshape ([2, 4, 6, 8], [1,2,2]));
00378 %! assert (max (x,[],2), reshape ([3, 4, 7, 8], [2,1,2]));
00379 %! [y, i ] = max (x, [], 3);
00380 %! assert (y, [5, 7; 6, 8]);
00381 %! assert (ndims(y), 2);
00382 %! assert (i, [2, 2; 2, 2]);
00383 %! assert (ndims(i), 2);
00384 
00385 */
00386 
00387 DEFUN_DLD (max, args, nargout,
00388   "-*- texinfo -*-\n\
00389 @deftypefn  {Loadable Function} {} max (@var{x})\n\
00390 @deftypefnx {Loadable Function} {} max (@var{x}, @var{y})\n\
00391 @deftypefnx {Loadable Function} {} max (@var{x}, [], @var{dim})\n\
00392 @deftypefnx {Loadable Function} {} max (@var{x}, @var{y}, @var{dim})\n\
00393 @deftypefnx {Loadable Function} {[@var{w}, @var{iw}] =} max (@var{x})\n\
00394 For a vector argument, return the maximum value.  For a matrix\n\
00395 argument, return the maximum value from each column, as a row\n\
00396 vector, or over the dimension @var{dim} if defined, in which case @var{y} \n\
00397 should be set to the empty matrix (it's ignored otherwise).  For two matrices\n\
00398 (or a matrix and scalar), return the pair-wise maximum.\n\
00399 Thus,\n\
00400 \n\
00401 @example\n\
00402 max (max (@var{x}))\n\
00403 @end example\n\
00404 \n\
00405 @noindent\n\
00406 returns the largest element of the matrix @var{x}, and\n\
00407 \n\
00408 @example\n\
00409 @group\n\
00410 max (2:5, pi)\n\
00411     @result{}  3.1416  3.1416  4.0000  5.0000\n\
00412 @end group\n\
00413 @end example\n\
00414 \n\
00415 @noindent\n\
00416 compares each element of the range @code{2:5} with @code{pi}, and\n\
00417 returns a row vector of the maximum values.\n\
00418 \n\
00419 For complex arguments, the magnitude of the elements are used for\n\
00420 comparison.\n\
00421 \n\
00422 If called with one input and two output arguments,\n\
00423 @code{max} also returns the first index of the\n\
00424 maximum value(s).  Thus,\n\
00425 \n\
00426 @example\n\
00427 @group\n\
00428 [x, ix] = max ([1, 3, 5, 2, 5])\n\
00429     @result{}  x = 5\n\
00430         ix = 3\n\
00431 @end group\n\
00432 @end example\n\
00433 @seealso{min, cummax, cummin}\n\
00434 @end deftypefn")
00435 {
00436   return do_minmax_body (args, nargout, false);
00437 }
00438 
00439 /*
00440 
00441 %% test/octave.test/arith/max-1.m
00442 %!assert (max ([1, 4, 2, 3]) == 4);
00443 %!assert (max ([1; -10; 5; -2]) == 5);
00444 
00445 %% test/octave.test/arith/max-2.m
00446 %!assert(all (max ([4, i 4.999; -2, 2, 3+4i]) == [4, 2, 3+4i]));
00447 
00448 %% test/octave.test/arith/max-3.m
00449 %!error <Invalid call to max> max ();
00450 
00451 %% test/octave.test/arith/max-4.m
00452 %!error <Invalid call to max> max (1, 2, 3, 4);
00453 
00454 %!test
00455 %! x = reshape (1:8,[2,2,2]);
00456 %! assert (min (x,[],1), reshape ([1, 3, 5, 7], [1,2,2]));
00457 %! assert (min (x,[],2), reshape ([1, 2, 5, 6], [2,1,2]));
00458 %! [y, i ] = min (x, [], 3);
00459 %! assert (y, [1, 3; 2, 4]);
00460 %! assert (ndims(y), 2);
00461 %! assert (i, [1, 1; 1, 1]);
00462 %! assert (ndims(i), 2);
00463 
00464 
00465 */
00466 
00467 template <class ArrayType>
00468 static octave_value_list
00469 do_cumminmax_red_op (const octave_value& arg,
00470                      int nargout, int dim, bool ismin)
00471 {
00472   octave_value_list retval;
00473   ArrayType array = octave_value_extract<ArrayType> (arg);
00474 
00475   if (error_state)
00476     return retval;
00477 
00478   if (nargout == 2)
00479     {
00480       retval.resize (2);
00481       Array<octave_idx_type> idx;
00482       if (ismin)
00483         retval(0) = array.cummin (idx, dim);
00484       else
00485         retval(0) = array.cummax (idx, dim);
00486 
00487       retval(1) = octave_value (idx, true, true);
00488     }
00489   else
00490     {
00491       if (ismin)
00492         retval(0) = array.cummin (dim);
00493       else
00494         retval(0) = array.cummax (dim);
00495     }
00496 
00497   return retval;
00498 }
00499 
00500 static octave_value_list
00501 do_cumminmax_body (const octave_value_list& args,
00502                    int nargout, bool ismin)
00503 {
00504   octave_value_list retval;
00505 
00506   const char *func = ismin ? "cummin" : "cummax";
00507 
00508   int nargin = args.length ();
00509 
00510   if (nargin == 1 || nargin == 2)
00511     {
00512       octave_value arg = args(0);
00513       int dim = -1;
00514       if (nargin == 2)
00515         {
00516           dim = args(1).int_value (true) - 1;
00517           if (error_state || dim < 0)
00518             {
00519               error ("%s: DIM must be a valid dimension", func);
00520               return retval;
00521             }
00522         }
00523 
00524       switch (arg.builtin_type ())
00525         {
00526         case btyp_double:
00527           retval = do_cumminmax_red_op<NDArray> (arg, nargout, dim, ismin);
00528           break;
00529         case btyp_complex:
00530           retval = do_cumminmax_red_op<ComplexNDArray> (arg, nargout, dim, ismin);
00531           break;
00532         case btyp_float:
00533           retval = do_cumminmax_red_op<FloatNDArray> (arg, nargout, dim, ismin);
00534           break;
00535         case btyp_float_complex:
00536           retval = do_cumminmax_red_op<FloatComplexNDArray> (arg, nargout, dim, ismin);
00537           break;
00538 #define MAKE_INT_BRANCH(X) \
00539         case btyp_ ## X: \
00540           retval = do_cumminmax_red_op<X ## NDArray> (arg, nargout, dim, ismin); \
00541           break;
00542         MAKE_INT_BRANCH (int8);
00543         MAKE_INT_BRANCH (int16);
00544         MAKE_INT_BRANCH (int32);
00545         MAKE_INT_BRANCH (int64);
00546         MAKE_INT_BRANCH (uint8);
00547         MAKE_INT_BRANCH (uint16);
00548         MAKE_INT_BRANCH (uint32);
00549         MAKE_INT_BRANCH (uint64);
00550 #undef MAKE_INT_BRANCH
00551         case btyp_bool:
00552           {
00553             retval = do_cumminmax_red_op<int8NDArray> (arg, nargout, dim, ismin);
00554             if (retval.length () > 0)
00555               retval(0) = retval(0).bool_array_value ();
00556             break;
00557           }
00558         default:
00559           gripe_wrong_type_arg (func, arg);
00560       }
00561     }
00562   else
00563     print_usage ();
00564 
00565   return retval;
00566 }
00567 
00568 DEFUN_DLD (cummin, args, nargout,
00569   "-*- texinfo -*-\n\
00570 @deftypefn  {Loadable Function} {} cummin (@var{x})\n\
00571 @deftypefnx {Loadable Function} {} cummin (@var{x}, @var{dim})\n\
00572 @deftypefnx {Loadable Function} {[@var{w}, @var{iw}] =} cummin (@var{x})\n\
00573 Return the cumulative minimum values along dimension @var{dim}.  If @var{dim}\n\
00574 is unspecified it defaults to column-wise operation.  For example:\n\
00575 \n\
00576 @example\n\
00577 @group\n\
00578 cummin ([5 4 6 2 3 1])\n\
00579     @result{}  5  4  4  2  2  1\n\
00580 @end group\n\
00581 @end example\n\
00582 \n\
00583 \n\
00584 The call\n\
00585 \n\
00586 @example\n\
00587   [w, iw] = cummin (x)\n\
00588 @end example\n\
00589 \n\
00590 @noindent\n\
00591 with @code{x} a vector, is equivalent to the following code:\n\
00592 \n\
00593 @example\n\
00594 @group\n\
00595 w = iw = zeros (size (x));\n\
00596 for i = 1:length (x)\n\
00597   [w(i), iw(i)] = max (x(1:i));\n\
00598 endfor\n\
00599 @end group\n\
00600 @end example\n\
00601 \n\
00602 @noindent\n\
00603 but computed in a much faster manner.\n\
00604 @seealso{cummax, min, max}\n\
00605 @end deftypefn")
00606 {
00607   return do_cumminmax_body (args, nargout, true);
00608 }
00609 
00610 DEFUN_DLD (cummax, args, nargout,
00611   "-*- texinfo -*-\n\
00612 @deftypefn  {Loadable Function} {} cummax (@var{x})\n\
00613 @deftypefnx {Loadable Function} {} cummax (@var{x}, @var{dim})\n\
00614 @deftypefnx {Loadable Function} {[@var{w}, @var{iw}] =} cummax (@var{x})\n\
00615 Return the cumulative maximum values along dimension @var{dim}.  If @var{dim}\n\
00616 is unspecified it defaults to column-wise operation.  For example:\n\
00617 \n\
00618 @example\n\
00619 @group\n\
00620 cummax ([1 3 2 6 4 5])\n\
00621     @result{}  1  3  3  6  6  6\n\
00622 @end group\n\
00623 @end example\n\
00624 \n\
00625 The call\n\
00626 \n\
00627 @example\n\
00628 [w, iw] = cummax (x, dim)\n\
00629 @end example\n\
00630 \n\
00631 @noindent\n\
00632 with @code{x} a vector, is equivalent to the following code:\n\
00633 \n\
00634 @example\n\
00635 @group\n\
00636 w = iw = zeros (size (x));\n\
00637 for i = 1:length (x)\n\
00638   [w(i), iw(i)] = max (x(1:i));\n\
00639 endfor\n\
00640 @end group\n\
00641 @end example\n\
00642 \n\
00643 @noindent\n\
00644 but computed in a much faster manner.\n\
00645 @seealso{cummin, max, min}\n\
00646 @end deftypefn")
00647 {
00648   return do_cumminmax_body (args, nargout, false);
00649 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines