changeset 26180:55564fdb3e4d

optimset.m: preserve empty options if given as arguments (bug #54952). * optimset.m: Don't recursively call optimset with structure arguments, but use a subfunction. Let the subfunction drop empty new fields only if new options were given as a structure argument to optimset.
author Olaf Till <i7tiol@t-online.de>
date Sat, 08 Dec 2018 12:49:39 +0100
parents a0b63c183d4b
children d77938ba31c4
files scripts/optimization/optimset.m
diffstat 1 files changed, 42 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/optimization/optimset.m	Sat Dec 08 01:38:45 2018 +0100
+++ b/scripts/optimization/optimset.m	Sat Dec 08 12:49:39 2018 +0100
@@ -118,6 +118,8 @@
   nargs = nargin;
 
   opts = __all_opts__ ();
+  ## Skip validation if we're in the internal query.
+  validation = ! isempty (opts);
 
   if (nargs == 0)
     if (nargout == 0)
@@ -142,45 +144,54 @@
     ## Should we be checking to ensure that the field names are expected?
     old = varargin{1};
     new = varargin{2};
-    fnames = fieldnames (old);
-    ## skip validation if we're in the internal query
-    validation = ! isempty (opts);
-    for [val, key] = new
-      if (validation)
-        ## Case insensitive lookup in all options.
-        i = strncmpi (opts, key, length (key));
-        nmatch = sum (i);
-        ## Validate option.
-        if (nmatch == 1)
-          key = opts{find (i)};
-        elseif (nmatch == 0)
-          warning ("optimset: unrecognized option: %s", key);
-        else
-          fmt = sprintf ("optimset: ambiguous option: %%s (%s%%s)",
-                         repmat ("%s, ", 1, nmatch-1));
-          warning (fmt, key, opts{i});
-        endif
-      endif
-      if (! isempty (val))
-        old.(key) = val;
-      endif
-    endfor
-    retval = old;
+    useempty = false; # Matlab drops empty new fields, too.
+    retval = setoptionfields (opts, old, new, validation, useempty);
   elseif (rem (nargs, 2) && isstruct (varargin{1}))
     ## Set values in old from name/value pairs.
+    old = varargin{1};
     pairs = reshape (varargin(2:end), 2, []);
-    retval = optimset (varargin{1}, cell2struct (pairs(2, :), pairs(1, :), 2));
+    new = cell2struct (pairs(2, :), pairs(1, :), 2);
+    useempty = true; # Matlab preserves empty arguments, too.
+    retval = setoptionfields (opts, old, new, validation, useempty);
   elseif (rem (nargs, 2) == 0)
     ## Create struct.
     ## Default values are replaced by those specified by name/value pairs.
+    old = struct ();
     pairs = reshape (varargin, 2, []);
-    retval = optimset (struct (), cell2struct (pairs(2, :), pairs(1, :), 2));
+    new = cell2struct (pairs(2, :), pairs(1, :), 2);
+    useempty = true; # Matlab preserves empty arguments, too.
+    retval = setoptionfields (opts, old, new, validation, useempty);
   else
     print_usage ();
   endif
 
 endfunction
 
+function retval = setoptionfields (opts, old, new, validation, useempty)
+
+  for [val, key] = new
+    if (validation)
+      ## Case insensitive lookup in all options.
+      i = strncmpi (opts, key, length (key));
+      nmatch = sum (i);
+      ## Validate option.
+      if (nmatch == 1)
+        key = opts{find (i)};
+      elseif (nmatch == 0)
+        warning ("optimset: unrecognized option: %s", key);
+      else
+        fmt = sprintf ("optimset: ambiguous option: %%s (%s%%s)",
+                       repmat ("%s, ", 1, nmatch-1));
+        warning (fmt, key, opts{i});
+      endif
+    endif
+    if (useempty || ! isempty (val))
+      old.(key) = val;
+    endif
+  endfor
+  retval = old;
+
+endfunction
 
 %!assert (isfield (optimset (), "TolFun"))
 %!assert (isfield (optimset ("tolFun", 1e-3), "TolFun"))
@@ -194,6 +205,11 @@
 %! assert (joint.TolX, 1e-2);
 %! assert (joint.TolFun, 1e-3);
 
+## Test preserving empty values given as arguments
+%!test
+%! opts = optimset ("TypicalX", []);
+%! assert (isempty (opts.TypicalX));
+
 ## Test input validation
 %!error optimset ("1_Parameter")
 %!error <no defaults for function> optimset ("%NOT_A_REAL_FUNCTION_NAME%")