changeset 18636:8d4d78285c8e

Overhaul optimset/optimget functions for Matlab compatibility (bug #41915). * optimget.m: Rewrite docstring. Use function name in all emitted warnings. Return the input DEFAULT when the options structure is empty rather than returning an empty matrix (Matlab compatibility). Add more tests for function and input validation. * optimset.m: Rewrite docstring. Use function name in all emitted warnings. Add more tests for function and input validation.
author Rik <rik@octave.org>
date Sat, 29 Mar 2014 11:24:59 -0700
parents 077575fe9a7e
children c29b00276818
files scripts/optimization/optimget.m scripts/optimization/optimset.m
diffstat 2 files changed, 57 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/optimization/optimget.m	Fri Mar 28 15:59:54 2014 -0700
+++ b/scripts/optimization/optimget.m	Sat Mar 29 11:24:59 2014 -0700
@@ -20,10 +20,12 @@
 ## -*- texinfo -*-
 ## @deftypefn  {Function File} {} optimget (@var{options}, @var{parname})
 ## @deftypefnx {Function File} {} optimget (@var{options}, @var{parname}, @var{default})
-## Return a specific option from a structure created by
-## @code{optimset}.  If @var{parname} is not a field of the @var{options}
-## structure, return @var{default} if supplied, otherwise return an
-## empty matrix.
+## Return the specific option @var{parname} from the optimization options
+## structure @var{options} created by @code{optimset}.
+##
+## If @var{parname} is not defined then return @var{default} if supplied,
+## otherwise return an empty matrix.
+## @seealso{optimset}
 ## @end deftypefn
 
 function retval = optimget (options, parname, default)
@@ -32,21 +34,22 @@
     print_usage ();
   endif
 
+  ## Expand partial-length names into full names
   opts = __all_opts__ ();
   idx = strncmpi (opts, parname, length (parname));
-
   nmatch = sum (idx);
 
   if (nmatch == 1)
     parname = opts{idx};
   elseif (nmatch == 0)
-    warning ("unrecognized option: %s", parname);
+    warning ("optimget: unrecognized option: %s", parname);
   else
-    fmt = sprintf ("ambiguous option: %%s (%s%%s)",
+    fmt = sprintf ("optimget: ambiguous option: %%s (%s%%s)",
                    repmat ("%s, ", 1, nmatch-1));
     warning (fmt, parname, opts{idx});
   endif
-  if (isfield (options, parname))
+
+  if (isfield (options, parname) && ! isempty (options.(parname)))
     retval = options.(parname);
   elseif (nargin > 2)
     retval = default;
@@ -57,13 +60,20 @@
 endfunction
 
 
-%!error optimget ()
-
 %!shared opts
 %! opts = optimset ("tolx", 0.1, "maxit", 100);
-%!assert (optimget (opts, "TolX"), 0.1);
-%!assert (optimget (opts, "maxit"), 100);
-%!assert (optimget (opts, "MaxITer"), 100);
-%!warning (optimget (opts, "Max"));
-%!warning (optimget (opts, "foobar"));
+%!assert (optimget (opts, "TolX"), 0.1)
+%!assert (optimget (opts, "maxit"), 100)
+%!assert (optimget (opts, "MaxITer"), 100)
+%!assert (optimget (opts, "TolFun"), [])
+%!assert (optimget (opts, "TolFun", 1e-3), 1e-3)
 
+%% Test input validation
+%!error optimget ()
+%!error optimget (1)
+%!error optimget (1,2,3,4,5)
+%!error optimget (1, "name")
+%!error optimget (struct (), 2)
+%!warning <unrecognized option: foobar> (optimget (opts, "foobar"));
+%!warning <ambiguous option: Max> (optimget (opts, "Max"));
+
--- a/scripts/optimization/optimset.m	Fri Mar 28 15:59:54 2014 -0700
+++ b/scripts/optimization/optimset.m	Sat Mar 29 11:24:59 2014 -0700
@@ -19,10 +19,24 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {Function File} {} optimset ()
-## @deftypefnx {Function File} {} optimset (@var{par}, @var{val}, @dots{})
-## @deftypefnx {Function File} {} optimset (@var{old}, @var{par}, @var{val}, @dots{})
-## @deftypefnx {Function File} {} optimset (@var{old}, @var{new})
-## Create options struct for optimization functions.
+## @deftypefnx {Function File} {@var{options} =} optimset ()
+## @deftypefnx {Function File} {@var{options} =} optimset (@var{par}, @var{val}, @dots{})
+## @deftypefnx {Function File} {@var{options} =} optimset (@var{old}, @var{par}, @var{val}, @dots{})
+## @deftypefnx {Function File} {@var{options} =} optimset (@var{old}, @var{new})
+## Create options structure for optimization functions.
+##
+## When called without any input or output arguments, @code{optimset} prints
+## a list of all valid optimization parameters.
+##
+## When called with one output and no inputs, return an options structure with
+## all valid option parameters initialized to @code{[]}.
+##
+## When called with a list of parameter/value pairs, return an options
+## structure with only the named parameters initialized.
+##
+## When the first input is an existing options structure @var{old}, the values
+## are updated from either the @var{par}/@var{val} list or from the options
+## structure @var{new}.
 ##
 ## Valid parameters are:
 ##
@@ -96,13 +110,13 @@
 ##
 ## @item Updating
 ## @end table
+## @seealso{optimget}
 ## @end deftypefn
 
 function retval = optimset (varargin)
 
   nargs = nargin ();
 
-  ## Add more as needed.
   opts = __all_opts__ ();
 
   if (nargs == 0)
@@ -124,8 +138,8 @@
       error ("optimset: no defaults for function '%s'", fcn);
     end_try_catch
   elseif (nargs == 2 && isstruct (varargin{1}) && isstruct (varargin{2}))
-    ## Set slots in old from nonempties in new.  Should we be checking
-    ## to ensure that the field names are expected?
+    ## Set slots in old from non-empties in new.
+    ## Should we be checking to ensure that the field names are expected?
     old = varargin{1};
     new = varargin{2};
     fnames = fieldnames (old);
@@ -140,9 +154,9 @@
         if (nmatch == 1)
           key = opts{find (i)};
         elseif (nmatch == 0)
-          warning ("unrecognized option: %s", key);
+          warning ("optimset: unrecognized option: %s", key);
         else
-          fmt = sprintf ("ambiguous option: %%s (%s%%s)",
+          fmt = sprintf ("optimset: ambiguous option: %%s (%s%%s)",
                          repmat ("%s, ", 1, nmatch-1));
           warning (fmt, key, opts{i});
         endif
@@ -155,8 +169,8 @@
     pairs = reshape (varargin(2:end), 2, []);
     retval = optimset (varargin{1}, cell2struct (pairs(2, :), pairs(1, :), 2));
   elseif (rem (nargs, 2) == 0)
-    ## Create struct.  Default values are replaced by those specified by
-    ## name/value pairs.
+    ## Create struct.
+    ## Default values are replaced by those specified by name/value pairs.
     pairs = reshape (varargin, 2, []);
     retval = optimset (struct (), cell2struct (pairs(2, :), pairs(1, :), 2));
   else
@@ -166,10 +180,13 @@
 endfunction
 
 
-%!assert (optimget (optimset ("tolx", 1e-2), "tOLx"), 1e-2)
+%!assert (isfield (optimset (), "TolFun"))
 %!assert (isfield (optimset ("tolFun", 1e-3), "TolFun"))
-%!warning (optimset ("Max", 10));
-%!warning (optimset ("foobar", 13));
+%!assert (optimget (optimset ("tolx", 1e-2), "tOLx"), 1e-2)
 
-%!error (optimset ("%NOT_A_REAL_FUNCTION_NAME%"))
+%% Test input validation
+%!error optimset ("1_Parameter")
+%!error <no defaults for function> optimset ("%NOT_A_REAL_FUNCTION_NAME%")
+%!warning <unrecognized option: foobar> optimset ("foobar", 13);
+%!warning <ambiguous option: Max> optimset ("Max", 10);