changeset 20620:e5f36a7854a5

Remove fuzzy matching from odeset/odeget. * levenshtein.cc: Deleted file. * libinterp/corefcn/module.mk: Remove levenshtein.cc from build system. * fuzzy_compare.m: Deleted file. * scripts/ode/module.mk: Remove fuzzy_compare.m from build system * odeget.m: Reword docstring. Use a persistent cellstr variable to keep track of all options. Replace fuzzy_compare() calls with combination of strcmpi and strncmpi. Report errors relative to function odeget rather than OdePkg. Rewrite and extend BIST tests. Add input validation BIST tests. * odeset.m: Reword docstring. Use a persistent cellstr variable to keep track of all options. Replace fuzzy_compare() calls with combination of strcmpi and strncmpi. Report errors relative to function odeset rather than OdePkg. Use more meaningful variables names and create intermediate variables with logical names to help make code readable. Remove interactive input when multiple property names match and just issue an error. Rewrite BIST tests. * ode_struct_value_check.m: Remove input checking for private function which must always be invoked correctly by caller. Use intermediate variables opt and val to make the code more understandable. Consolidate checks on values into single if statements. Use 'val == fix (val)' to check for integer. * __unimplemented__.m: Removed odeset, odeget, ode45 from list.
author Rik <rik@octave.org>
date Fri, 09 Oct 2015 12:03:23 -0700
parents eef93a493ce3
children 22618d5fb6ad
files libinterp/corefcn/levenshtein.cc libinterp/corefcn/module.mk scripts/help/__unimplemented__.m scripts/ode/module.mk scripts/ode/odeget.m scripts/ode/odeset.m scripts/ode/private/fuzzy_compare.m scripts/ode/private/ode_struct_value_check.m
diffstat 8 files changed, 370 insertions(+), 801 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/levenshtein.cc	Fri Oct 09 14:43:36 2015 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
-
-Copyright (C) 2014 Jacopo Corno
-Copyright (C) 2014 Carlo de Falco
-Copyright (C) 2013 Roberto Porcu
-Copyright (C) 2013 Mattia Penati
-
-This file is part of Octave.
-
-Octave is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or (at
-your option) any later version.
-
-Octave is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Octave; see the file COPYING.  If not, see
-<http://www.gnu.org/licenses/>.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "defun.h"
-
-#define MIN2(A,B) ((A)<(B)?(A):(B))
-#define MIN3(A,B,C) (MIN2(MIN2((A),(B)),(C)))
-
-DEFUN (levenshtein, args, nargout,
-          "-*- texinfo -*-\n\
-@deftypefn  {Loadable Function} {@var{d} =} levenshtein (@var{str1}, @var{str2}, [@var{u_bound}])\n \
-@deftypefnx {Loadable Function} {[@var{d}, @var{mat}] =} levenshtein (@var{str1}, @var{str2}, [@var{u_bound}])\n \
-This function file computes the Levenshtein distance between two strings. More details at @url{http://en.wikipedia.org/wiki/Levenshtein_distance}.\n \
-This function can be called with one or two output arguments: @var{d} is the distance between the two strings and @var{mat} is the matrix computed by Levenshtein algorithm.\n \
-The first and the second input arguments, @var{str1} and @var{str2}, are the two strings to be compared. This comparison is case-sensitive.\n \
-The third argument @var{u_bound} is optional and fixes an upper bound for the distance. If the distance is greater than this limit then the function ends and returns a value equal to Inf.\n \
-@seealso{odeset}\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-  int nargin = args.length ();
-  octave_idx_type ub;
-
-  if (nargin < 2
-      || nargin > 3
-      || nargout > 2)
-    {
-      print_usage ();
-      return retval;
-    }
-
-  if (nargin == 3)
-    ub = args(2).idx_type_value ();
-  else
-    ub = std::numeric_limits<int32_t>::max ();
-
-  Array<char> s1 (args(0).char_array_value ());
-  char *s1_p = s1.fortran_vec ();
-
-  Array<char> s2 (args(1).char_array_value ());
-  char *s2_p = s2.fortran_vec ();
-
-  octave_idx_type
-    s1len = s1.numel (),
-    s2len = s2.numel (),
-    ii, jj;
-
-  Array<octave_idx_type>
-    dist (dim_vector (s1len + 1, s2len + 1), 0);
-
-  for (ii = 1; ii <= s1len; ii++)
-    dist.xelem (ii, 0) = ii;
-
-  for (jj = 1; jj <= s2len; jj++)
-    dist.xelem (0, jj) = jj;
-
-  for (jj = 1; jj <= s2len; jj++)
-    {
-      for (ii = 1; ii <= s1len; ii++)
-        if (s1_p[ii-1] == s2_p[jj-1])
-          dist.xelem (ii, jj) = dist.xelem (ii-1, jj-1);
-        else
-          dist.xelem (ii, jj) =
-            MIN3(dist.xelem (ii-1, jj) + 1,
-                 dist.xelem (ii, jj-1) + 1,
-                 dist.xelem (ii-1, jj-1) + 1);
-
-      if (dist(MIN2(jj, s1len), jj) > ub)
-        {
-          retval(0) = std::numeric_limits<int32_t>::max ();
-          if (nargout == 2)
-            retval(1) = Matrix ();
-          return retval;
-        }
-    }
-
-  retval(0) = dist.xelem (s1len, s2len);
-
-  if (nargout == 2)
-    retval(1) = dist;
-
-  return retval;
-}
--- a/libinterp/corefcn/module.mk	Fri Oct 09 14:43:36 2015 -0400
+++ b/libinterp/corefcn/module.mk	Fri Oct 09 12:03:23 2015 -0700
@@ -174,7 +174,6 @@
   libinterp/corefcn/input.cc \
   libinterp/corefcn/inv.cc \
   libinterp/corefcn/kron.cc \
-	libinterp/corefcn/levenshtein.cc \
   libinterp/corefcn/load-path.cc \
   libinterp/corefcn/load-save.cc \
   libinterp/corefcn/lookup.cc \
--- a/scripts/help/__unimplemented__.m	Fri Oct 09 14:43:36 2015 -0400
+++ b/scripts/help/__unimplemented__.m	Fri Oct 09 12:03:23 2015 -0700
@@ -749,9 +749,6 @@
   "ode23s",
   "ode23t",
   "ode23tb",
-  "ode45",
-  "odeget",
-  "odeset",
   "odextend",
   "openfig",
   "opengl",
--- a/scripts/ode/module.mk	Fri Oct 09 14:43:36 2015 -0400
+++ b/scripts/ode/module.mk	Fri Oct 09 12:03:23 2015 -0700
@@ -4,7 +4,6 @@
 
 scripts_ode_PRIVATE_FCN_FILES = \
   scripts/ode/private/AbsRel_Norm.m \
-  scripts/ode/private/fuzzy_compare.m \
   scripts/ode/private/integrate_adaptive.m \
   scripts/ode/private/integrate_const.m \
   scripts/ode/private/integrate_n_steps.m \
--- a/scripts/ode/odeget.m	Fri Oct 09 14:43:36 2015 -0400
+++ b/scripts/ode/odeget.m	Fri Oct 09 12:03:23 2015 -0700
@@ -25,26 +25,21 @@
 ## @var{ode_opt}.
 ##
 ## If called with two input arguments and the first input argument @var{ode_opt}
-## is a structure and the second input argument @var{field} is a string then
-## return the option value @var{val} that is specified by the option name
-## @var{field} in the ODE option structure @var{ode_opt}.
+## is an ODE option structure and the second input argument @var{field} is a
+## string specifying an option name then return the option value @var{val}
+## corresponding to to @var{field} from @var{ode_opt}.
 ##
-## If called called with an optional third input argument then return the
-## default value @var{default} if @var{field} is not set in the structure
-## @var{ode_opt}.
+## If called called with an optional third input argument, and @var{field} is
+## not set in the structure @var{ode_opt}, then return the default value
+## @var{default} instead. 
 ## @seealso{odeset}
 ## @end deftypefn
 
-## FIXME: 4th input argument 'opt' is undocumented.
-
-## Note: 2006-10-22, Thomas Treichl
-##   We cannot create a function of the form odeget (@var{odestruct},
-##   @var{name1}, @var{name2}) because we would get a mismatch with
-##   the function form 1 like described above.
+## FIXME: 4th input argument "opt" is undocumented.
 
 function val = odeget (ode_opt, field, default = [], opt)
 
-  if (nargin == 1 || nargin > 4)
+  if (nargin < 1 || nargin > 4)
     print_usage ();
   endif
 
@@ -85,64 +80,56 @@
     return;
   endif
 
-  ## check if the given struct is a valid OdePkg struct
+  ## Check if the given struct is a valid OdePkg struct
   ode_struct_value_check (ode_opt);
 
-  ## define all the possible OdePkg fields
-  options = ["AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events";
-             "Explicit"; "InexactSolver"; "InitialSlope"; "InitialStep";
-             "Jacobian";"JConstant";"JPattern";"Mass"; "MassConstant";
-             "MassSingular"; "MaxNewtonIterations"; "MaxOrder"; "MaxStep";
-             "MStateDependence"; "MvPattern"; "NewtonTol"; "NonNegative";
-             "NormControl"; "OutputFcn"; "OutputSave"; "OutputSel";
-             "PolynomialDegree"; "QuadratureOrder"; "Refine"; "RelTol";
-             "Restart"; "Stats"; "TimeStepNumber"; "TimeStepSize";
-             "UseJacobian"; "Vectorized"];
-
-  while (1)
-    pos = fuzzy_compare (field, options);
-
-    if (isempty (pos))  # no match for the given option
-      if (nargin == 2)
-        error ("odeget: invalid property. No property found with name '%s'",
-               field);
-      endif
-      warning ("odeget:NoExactMatching",
-               "no property found with name '%s'. ",
-               "Assuming default value.", field);
-      val = default;
-      return;
-    endif
+  ## Define all the possible OdePkg fields
+  persistent options = {"AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events";
+                        "Explicit"; "InexactSolver"; "InitialSlope";
+                        "InitialStep"; "Jacobian"; "JConstant"; "JPattern";
+                        "Mass"; "MassConstant"; "MassSingular";
+                        "MaxNewtonIterations"; "MaxOrder"; "MaxStep";
+                        "MStateDependence"; "MvPattern"; "NewtonTol";
+                        "NonNegative"; "NormControl"; "OutputFcn"; "OutputSave";
+                        "OutputSel"; "PolynomialDegree"; "QuadratureOrder";
+                        "Refine"; "RelTol"; "Restart"; "Stats";
+                        "TimeStepNumber"; "TimeStepSize"; "UseJacobian";
+                        "Vectorized"};
+  
+  exactmatch = true;
+  match = find (strcmpi (field, options));
+  if (isempty (match))
+    match = find (strncmpi (field, options, length (field)));
+    exactmatch = false;
+  endif
 
-    if (rows (pos) == 1)  # one matching
-      if (! strcmp (lower (deblank (field)),
-                    lower (deblank (options(pos,:)))) )
-        warning ("odeget:InvalidArgument",
-                 "no exact matching for '%s'. ",
-                 "Assuming you were intending '%s'.",
-                 field, deblank (options(pos,:)));
-      endif
-      val = ode_opt.(deblank (options(pos,:)));
-      if (isempty (val))
-        val = default;
-      endif
-      return;
+  if (isempty (match))
+    if (nargin == 2)
+      error ("odeget: invalid property '%s'", field);
+    else
+      ## FIXME: Should we warn, but complete the action, or just error out?
+      warning ("odeget:InvalidArgument",
+               "odeget: invalid property '%s'.  Using supplied default value.",
+               field);
+      val = default;
     endif
-
-    ## FIXME: Do we really need interactive selection?
-    ##        Matlab doesn't appear to offer this.
-    ## if there are more matching, ask the user to be more precise
-    warning ("OdePkg:InvalidArgument",
-             "no exact matching for '%s'. %d possible fields were found.",
-             field, rows (pos));
-    for j = 1:(rows (pos))
-      printf ("%s\n", deblank (options(pos(j),:)));
-    endfor
-    do
-      printf ("Please insert field name again.\n");
-      field = input ("New field name: ");
-    until (ischar (field))
-  endwhile
+  elseif (numel (match) == 1)
+    if (! exactmatch)
+      warning ("odeget:NoExactMatching",
+               "odeget: no exact match for '%s'.  Assuming '%s'.\n",
+               field, options{match});
+    endif
+    val = [];
+    try
+      val = ode_opt.(options{match});
+    end_try_catch
+    if (isempty (val))
+      val = default;
+    endif
+  else
+    error ("odeget: no exact match for '%s'.  Possible fields found: %s.",
+           field, strjoin (options(match), ", "));
+  endif
 
 endfunction
 
@@ -155,17 +142,23 @@
 %! A = odeset ("RelTol", 1e-1, "AbsTol", 1e-2);
 %! odeget (A, "RelTol", [])
 
-%!test
-%! wstate = warning ("off", "OdePkg:InvalidArgument");
-%! unwind_protect
-%!   assert (odeget (odeset (), "RelTol"), []);
-%!   assert (odeget (odeset (), "RelTol", 10), 10);
-%!   assert (odeget (odeset (), "Stats"), []);
-%!   assert (odeget (odeset (), "Stats", "on"), "on");
-%!   assert (odeget (odeset (), "AbsTol", 1e-6, "fast"), []);
-%!   assert (odeget (odeset (), "AbsTol", 1e-6, "fast_not_empty"), 1e-6);
-%!   assert (odeget (odeset (), "AbsTol", 1e-9), 1e-9);
-%! unwind_protect_cleanup
-%!   warning (wstate);
-%! end_unwind_protect
+%!assert (odeget (odeset (), "RelTol"), [])
+%!assert (odeget (odeset ("RelTol", 10), "RelTol"), 10)
+%!assert (odeget (odeset (), "RelTol", 10), 10)
+%!assert (odeget (odeset (), "Stats"), [])
+%!assert (odeget (odeset (), "Stats", "on"), "on")
+%!assert (odeget (odeset (), "Mass"), [])
+%!assert (odeget (odeset (), "AbsTol", 1e-6, "fast"), [])
+%!assert (odeget (odeset (), "AbsTol", 1e-6, "fast_not_empty"), 1e-6)
+%!assert (odeget (odeset (), "AbsTol", 1e-9), 1e-9)
 
+%!error odeget ()
+%!error odeget (1)
+%!error odeget (1,2,3,4,5)
+%!error <ODE_OPT must be a valid ODE_STRUCT> odeget (1, "opt1")
+%!error <FIELD must be a string> odeget (struct ("opt1", 1), 1)
+%!error <invalid property 'foo'> odeget (struct ("opt1", 1), "foo")
+%!warning <Using supplied default value> odeget (struct ("opt1", 1), "foo", 3);
+%!warning <no exact match for 'Rel'.  Assuming 'RelTol'> odeget (struct ("RelTol", 1), "Rel");
+%!error <Possible fields found: InitialSlope, InitialStep> odeget (odeset (), "Initial")
+
--- a/scripts/ode/odeset.m	Fri Oct 09 14:43:36 2015 -0400
+++ b/scripts/ode/odeset.m	Fri Oct 09 12:03:23 2015 -0700
@@ -25,27 +25,23 @@
 ##
 ## Create or modify an ODE options structure.
 ##
-## If this function is called without an input argument then return a new ODE
-## options structure array that contains all the necessary fields and sets
-## the values of all fields to default values.
+## When called without an input argument, return a new ODE options structure
+## that contains all possible fields initialized to their default values.
 ##
-## If this function is called with string input arguments @var{"field1"},
-## @var{"field2"}, @dots{} identifying valid ODE options then return a new
-## ODE options structure with all necessary fields and set the values of the
-## fields @var{"field1"}, @var{"field2"}, @dots{} to the values @var{value1},
-## @var{value2}, @dots{}
+## If called with string input arguments @var{"field1"}, @var{"field2"},
+## @dots{} identifying valid ODE options then return a new ODE options
+## structure with all possible fields initialized @strong{and} set the values
+## of the fields @var{"field1"}, @var{"field2"}, @dots{} to the values
+## @var{value1}, @var{value2}, @dots{}
 ##
-## If this function is called with a first input argument @var{oldstruct} of
-## type structure array then overwrite all values of the options
-## @var{"field1"}, @var{"field2"}, @dots{} of the structure @var{oldstruct}
-## with new values @var{value1}, @var{value2}, @dots{} and return the
-## modified structure array.
+## If called with an input structure @var{oldstruct} then overwrite the values
+## of the options @var{"field1"}, @var{"field2"}, @dots{} with new values
+## @var{value1}, @var{value2}, @dots{} and return the modified structure.
 ##
-## If this function is called with two input arguments @var{oldstruct} and
-## @var{newstruct} of type structure array then overwrite all values in the
-## fields from the structure @var{oldstruct} with new values of the fields
-## from the structure @var{newstruct}.  Empty values of @var{newstruct} will
-## not overwrite values in @var{oldstruct}.
+## When called with two input ODE options structures @var{oldstruct} and
+## @var{newstruct} overwrite all values from the structure @var{oldstruct} with
+## new values from the structure @var{newstruct}.  Empty values in
+## @var{newstruct} will not overwrite values in @var{oldstruct}.
 ## @seealso{odeget}
 ## @end deftypefn
 
@@ -57,231 +53,179 @@
     return;
   endif
 
-  ## Column vector of all possible OdePkg fields
-  fields = ["AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events";
-            "Explicit"; "InexactSolver"; "InitialSlope"; "InitialStep";
-            "Jacobian";"JConstant";"JPattern";"Mass"; "MassConstant";
-            "MassSingular"; "MaxNewtonIterations"; "MaxOrder"; "MaxStep";
-            "MStateDependence"; "MvPattern"; "NewtonTol"; "NonNegative";
-            "NormControl"; "OutputFcn"; "OutputSave"; "OutputSel";
-            "PolynomialDegree"; "QuadratureOrder"; "Refine"; "RelTol";
-            "Restart"; "Stats"; "TimeStepNumber"; "TimeStepSize";
-            "UseJacobian"; "Vectorized"];
-
-  fields_nb = rows (fields);
+  ## Column vector of all possible OdePkg options
+  persistent options = {"AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events";
+                        "Explicit"; "InexactSolver"; "InitialSlope";
+                        "InitialStep"; "Jacobian"; "JConstant"; "JPattern";
+                        "Mass"; "MassConstant"; "MassSingular";
+                        "MaxNewtonIterations"; "MaxOrder"; "MaxStep";
+                        "MStateDependence"; "MvPattern"; "NewtonTol";
+                        "NonNegative"; "NormControl"; "OutputFcn"; "OutputSave";
+                        "OutputSel"; "PolynomialDegree"; "QuadratureOrder";
+                        "Refine"; "RelTol"; "Restart"; "Stats";
+                        "TimeStepNumber"; "TimeStepSize"; "UseJacobian";
+                        "Vectorized"};
 
   ## initialize output
-  odestruct = cell2struct (cell (rows (fields), 1), cellstr (fields));
+  odestruct = cell2struct (cell (numel (options), 1), options);
 
-  odestruct.Refine = 0;
-  odestruct.OutputSave = 1;
-
-  if (nargin == 0 && nargout == 1)
+  if (nargin == 0)
     return;
   endif
 
-  ode_fields = fieldnames (odestruct);
-  
   if (isstruct (varargin{1}))
     oldstruct = varargin{1};
     ode_struct_value_check (oldstruct);
 
-    optA_fields = fieldnames (oldstruct);
-    optA_f_nb = length (optA_fields);
+    oldstruct_fldnames = (fieldnames (oldstruct)).';
 
-    ## loop on first struct options for updating
-    for i = 1:optA_f_nb
-      name = lower (deblank (optA_fields{i}));
+    ## Copy oldstruct values into output odestruct
+    for fldname = oldstruct_fldnames
+      name = lower (fldname{1});
 
-      while (1)
-        pos = fuzzy_compare (name, fields);
-        if (isempty (pos))
-          warning ("OdePkg:InvalidArgument",
-                   "no property found with name '%s'", name);
-        endif
+      exactmatch = true;
+      match = find (strcmpi (name, options));
+      if (isempty (match))
+        match = find (strncmpi (name, options, length (name)));
+        exactmatch = false;
+      endif
 
-        if (rows (pos) == 1)
-          if (! strcmp (lower (deblank (name)),
-                        lower (deblank (fields(pos,:)))))
-            warning ("OdePkg:InvalidArgument", "no exact matching for ",
-                     "'%s'. Assuming you were intending '%s'",
-                     name, deblank (fields(pos,:)));
-          endif
-
-          odestruct.(deblank (fields(pos,:))) = oldstruct.(optA_fields{i});
-          break;
+      if (isempty (match))
+        error ("odeset: invalid property '%s'", fldname{1});
+      elseif (numel (match) == 1)
+        if (! exactmatch)
+          warning ("odeset:NoExactMatching",
+                   "no exact match for '%s'.  Assuming '%s'.",
+                   name, options{match});
         endif
+        odestruct.(options{match}) = oldstruct.(fldname{1});
+      else
+        error ("odeset: no exact match for '%s'.  Possible fields found: %s.",
+               name, strjoin (options(match), ", "));
+      endif
+    endfor
 
-        ## FIXME: Do we really need interactive selection?
-        ## if there are more matching, ask the user to be more precise
-        warning ("OdePkg:InvalidArgument",
-                 "no exact matching for '%s'. %d possible fields were found",
-                 name, size(pos, 1));
-        for j = 1:(rows (pos))
-          printf ("%s\n", deblank (fields(pos(j),:)));
-        endfor
-        do
-          disp ("Please insert field name again");
-          name = input ("New field name: ");
-        until (ischar (name))
-      endwhile
-    endfor
+    ## At this point, odestruct has been initialized with default values,
+    ## and if oldstruct was present it has overwritten fields in odestruct.
 
     if (nargin == 2 && isstruct (varargin{2}))
       newstruct = varargin{2};
       ode_struct_value_check (newstruct);
 
-      optB_fields = fieldnames (newstruct);
-      optB_f_nb = length (optB_fields);
+      newstruct_fldnames = (fieldnames (newstruct)).';
+
+      ## Update the first struct with the values from the second one
+      for fldname = newstruct_fldnames
+        name = lower (fldname{1});
 
-      ## update the first struct with the values in the second one
-      for i = 1:optB_f_nb
-        name = lower (deblank (optB_fields{i}));
-        while (1)
-          pos = fuzzy_compare (name, fields);
-
-          if (isempty (pos))
-            warning ("OdePkg:InvalidArgument",
-                     "no property found with name '%s'", name);
-          endif
+        exactmatch = true;
+        match = find (strcmpi (name, options));
+        if (isempty (match))
+          match = find (strncmpi (name, options, length (name)));
+          exactmatch = false;
+        endif
 
-          if (rows (pos) == 1)
-            if (! strcmp (lower (deblank (name)),
-                          lower (deblank (fields(pos,:)))))
-              warning ("OdePkg:InvalidArgument", "no exact matching for ",
-                       "'%s'. Assuming you were intending '%s'",
-                        name, deblank (fields(pos,:)));
-            endif
-            odestruct.(deblank (fields(pos,:))) = newstruct.(optB_fields{i});
-            break;
+        if (isempty (match))
+          error ("odeset: invalid property '%s'", fldname{1});
+        elseif (numel (match) == 1)
+          if (! exactmatch)
+            warning ("odeset:NoExactMatching",
+                     "no exact match for '%s'.  Assuming '%s'.",
+                     name, options{match});
           endif
+          odestruct.(options{match}) = newstruct.(fldname{1});
+        else
+          error ("odeset: no exact match for '%s'.  Possible fields found: %s.",
+                 name, strjoin (options(match), ", "));
+        endif
+      endfor
 
-          ## FIXME: Do we really need interactive selection?
-          ## if there are more matching, ask the user to be more precise
-          warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
-                   "%d possible fields were found",
-                   name, rows (pos));
-          for j = 1:(rows (pos))
-            printf ("%s\n", deblank (fields(pos(j),:)));
-          endfor
-          do
-            disp ("Please insert field name again");
-            name = input ("New field name: ");
-          until (ischar (name))
-        endwhile
-      endfor
+      ## Done copying newstruct to oldstruct
       return;
     endif
 
-    ## if the second argument is not a struct,
-    ## pass new values of the OdePkg options to the first struct
+    ## Second argument is not a struct
     if (mod (nargin, 2) != 1)
       error ("odeset: FIELD/VALUE arguments must occur in pairs");
     endif
-
     if (! all (cellfun ("isclass", varargin(2:2:end), "char")))
       error ("odeset: All FIELD names must be strings");
     endif
 
-    ## loop on the input arguments
-    for i = 2:2:(nargin - 1)
-      name = varargin{i};
+    ## Write new field/value pairs into odestruct
+    for i = 2:2:nargin
+      name = lower (varargin{i});
 
-      while (1)
-        pos = fuzzy_compare (name, fields);
-
-        if (isempty (pos))
-          error ("OdePkg:InvalidArgument",
-                 "no property found with name '%s'", name);
-        endif
+      exactmatch = true;
+      match = find (strcmpi (name, options));
+      if (isempty (match))
+        match = find (strncmpi (name, options, length (name)));
+        exactmatch = false;
+      endif
 
-        if (rows (pos) == 1)
-          if (! strcmp (lower (deblank (name)),
-                        lower (deblank (fields(pos,:)))))
-            warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
-                     "%d possible fields were found",
-                     name, rows (pos));
-          endif
-          odestruct.(deblank (fields(pos,:))) = varargin{i+1};
-          break;
+      if (isempty (match))
+        error ("odeset: invalid property '%s'", varargin{i});
+      elseif (numel (match) == 1)
+        if (! exactmatch)
+          warning ("odeset:NoExactMatching",
+                   "no exact match for '%s'.  Assuming '%s'.",
+                   name, options{match});
         endif
-
-        ## FIXME: Do we really need interactive selection?
-        ## if there are more matching, ask the user to be more precise
-        warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
-                 "%d possible fields were found",
-                 name, rows (pos));
-        for j = 1:(rows (pos))
-          printf ("%s\n", deblank (fields(pos(j),:)));
-        endfor
-        do
-          disp ("Please insert field name again");
-          name = input ("New field name: ");
-        until (ischar (name))
-      endwhile
+        odestruct.(options{match}) = varargin{i+1};
+      else
+        error ("odeset: no exact match for '%s'.  Possible fields found: %s.",
+               name, strjoin (options(match), ", "));
+      endif
     endfor
 
-    ## check if all has been done gives a valid OdePkg struct
+    ## Check if all changes have resulted in a valid OdePkg struct
     ode_struct_value_check (odestruct);
-    return;
-  endif
-
-  ## first input argument was not a struct
-  if (mod (nargin, 2) != 0)
-    error ("odeset: FIELD/VALUE arguments must occur in pairs");
-  endif
 
-  if (! all (cellfun ("isclass", varargin(1:2:end), "char")))
-    error ("odeset: All FIELD names must be strings");
-  endif
-
-  for i = 1:2:(nargin-1)
-    name = varargin{i};
+  else
+    ## First input argument was not a struct, must be field/value pairs
+    if (mod (nargin, 2) != 0)
+      error ("odeset: FIELD/VALUE arguments must occur in pairs");
+    elseif (! all (cellfun ("isclass", varargin(1:2:end), "char")))
+      error ("odeset: All FIELD names must be strings");
+    endif
 
-    while (1)
-      pos = fuzzy_compare (name, fields);
+    for i = 1:2:nargin
+      name = lower (varargin{i});
 
-      if (isempty (pos))
-        error ("OdePkg:InvalidArgument",
-               "invalid property. No property found with name '%s'", name);
+      exactmatch = true;
+      match = find (strcmpi (name, options));
+      if (isempty (match))
+        match = find (strncmpi (name, options, length (name)));
+        exactmatch = false;
       endif
 
-      if (rows (pos) == 1)
-        if (! strcmp (lower (deblank (name)),
-                      lower (deblank (fields(pos,:)))))
-          warning ("OdePkg:InvalidArgument", "no exact matching for ",
-                   "'%s'. Assuming you were intending '%s'",
-                   name, deblank (fields(pos,:)));
+      if (isempty (match))
+        error ("odeset: invalid property '%s'", varargin{i});
+      elseif (numel (match) == 1)
+        if (! exactmatch)
+          warning ("odeset:NoExactMatching",
+                   "no exact match for '%s'.  Assuming '%s'.",
+                   name, options{match});
         endif
-        odestruct.(deblank (fields(pos,:))) = varargin{i+1};
-        break;
+        odestruct.(options{match}) = varargin{i+1};
+      else
+        error ("odeset: no exact match for '%s'.  Possible fields found: %s.",
+               name, strjoin (options(match), ", "));
       endif
+    endfor
 
-      ## FIXME: Do we really need interactive selection?
-      ## if there are more matching, ask the user to be more precise
-      warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
-               "%d possible fields were found",
-               name, rows (pos));
-      for j = 1:rows (pos)
-        printf ("%s\n", deblank (fields(pos(j),:)));
-      endfor
-      do
-        disp ("Please insert field name again");
-        name = input ("New field name: ");
-      until (ischar (name))
-    endwhile
-  endfor
+    ## Check if all changes have resulted in a valid OdePkg struct
+    ode_struct_value_check (odestruct);
 
-  ## check if all has been done gives a valid OdePkg struct
-  ode_struct_value_check (odestruct);
+  endif
 
 endfunction
 
 ## function useful to print all the possible options
 function print_options ()
   
-  disp ("These following are all possible options.");
-  disp ("Default values are put in square brackets.");
+  disp ("List of all possible ODE solver options.");
+  disp ("Default values are in square brackets.");
   disp ("");
   disp ("             AbsTol:  scalar or vector, >0, [1e-6]");
   disp ("          Algorithm:  string, {['gmres'], 'pcg', 'bicgstab'}");
@@ -338,25 +282,31 @@
 %!demo
 %! # A new OdePkg options structure is created from odeoptB with
 %! # a modified value for option "NormControl".
-
+%!
 %! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
 %! odeoptC = odeset (odeoptB, "NormControl", "on");
 
 ## All tests that are needed to check if a correct resp. valid option
 ## has been set are implemented in ode_struct_value_check.m.
 %!test
-%! wstate = warning ("off", "OdePkg:InvalidArgument");
-%! unwind_protect
-%!   odeoptA = odeset ();
-%!   ## FIXME: no assert check on odeoptA
-%!   odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
-%!   assert (odeoptB.AbsTol, 1e-2);
-%!   assert (odeoptB.RelTol, 1e-1);
-%!   odeoptC = odeset (odeoptB, "NormControl", "on");
-%!   ## FIXME: no assert check on odeoptC
-%!   odeoptD = odeset (odeoptC, odeoptB);
-%!   ## FIXME: no assert check on odeoptD
-%! unwind_protect_cleanup
-%!   warning (wstate);
-%! end_unwind_protect
+%! odeoptA = odeset ();
+%! assert (isstruct (odeoptA));
+%! fields = fieldnames (odeoptA); 
+%! assert (numel (fields), 37); 
+%! assert (all (structfun ("isempty", odeoptA)));
 
+%!shared odeoptB, odeoptC
+%!test
+%! odeoptB = odeset ("ABSTOL", 1e-2, "reltol", 1e-1);
+%! assert (odeoptB.AbsTol, 1e-2);  # Check canonicalization of name
+%! assert (odeoptB.RelTol, 1e-1);
+
+%!test
+%! odeoptC = odeset (odeoptB, "NormControl", "on");
+%! assert (odeoptC.AbsTol, 1e-2);       # check values from first struct copied
+%! assert (odeoptC.NormControl, "on");  # check new values override old ones
+
+%!test
+%! odeoptD = odeset (odeoptB, odeoptC);
+%! assert (odeoptD, odeoptC); 
+
--- a/scripts/ode/private/fuzzy_compare.m	Fri Oct 09 14:43:36 2015 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-## Copyright (C) 2013, Roberto Porcu' <roberto.porcu@polimi.it>
-##
-## This file is part of Octave.
-##
-## Octave is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn  {Function File} {@var{res} =} fuzzy_compare (@var{"string1"}, @var{string_set})
-## @deftypefnx {Function File} {@var{res} =} fuzzy_compare (@var{"string1"}, @var{string_set}, @var{correctness})
-##
-## Compare a string with a set of strings and returns the positions in the
-## set of strings at which there are the fields that best fit the one we are
-## comparing.
-##
-## The distance used to compare the words is the Levenshtein distance.
-## For more details see
-## @url{http://en.wikipedia.org/wiki/Levenshtein_distance}.
-##
-## This function must be called with one output argument @var{res} which
-## contains the positions of the elements in @var{string_set} which best fit
-## the given word.  The tolerance that is used to determine if a field of the
-## list fits or not the given word is a function of the length of the word
-## and of the minimum distance of the word from all the elements of the list.
-##  The more the length, the more the tolerance.  The less the minimum, the
-## less the tolerance but if the minimum is close to the length of the word,
-## the tolerance must be small because it means that no field in the list is
-## really fitting the given word.  So that the function is:
-##
-## @ifhtml
-## @example
-## @math{tolerance = 2 * (length-minimum) * minimum / length}
-## @end example
-## @end ifhtml
-## @ifnothtml
-## @math{tolerance = 2 * (length-minimum) * minimum / length}.
-## @end ifnothtml
-##
-## The first input argument must be a string containing the word to compare.
-##
-## The second input argument must be a vector of strings or a cell_array of
-## strings and should contain the fields to use for the comparison.
-##
-## The third input argument is optional and represents a fixed tolerance that
-## will replace the implemented one.
-## @end deftypefn
-##
-## @seealso{odeset, odeget, levenshtein}
-
-function res = fuzzy_compare (string1, string_set, correctness)
-
-  ## check on output arguments
-  if (nargout > 1)
-    error ("OdePkg:InvalidArgument", "too many output arguments");
-  endif
-
-  ## check on input arguments
-  if (nargin < 2 || nargin > 3)
-    error ("OdePkg:InvalidArgument", "wrong input arguments number");
-  endif
-
-  if (! ischar (string1)
-      || (! iscellstr (string_set)
-          && ! ischar (string_set)))
-    error ("OdePkg:InvalidArgument",
-           "first argument must be a string, second argument ",
-           "must be an array of strings or a cell array of strings");
-  endif
-
-  if (nargin == 3)
-    if ((! isnumeric (correctness) || ! isscalar (correctness))
-        && (! ischar (correctness)))
-      error ("OdePkg:InvalidArgument",
-             "third input argument must be a positive ",
-             "integer or a string");
-    endif
-
-    if (isnumeric (correctness)
-        && ( correctness < 0 || mod (correctness, 1) != 0))
-      error ("OdePkg:InvalidArgument",
-             "third input argument must be a positive integer");
-    endif
-  endif
-
-  res = [];
-
-  m = length (string1);
-  fields_nb = rows (string_set);
-
-  values = Inf (fields_nb, 1);
-
-  string1 = deblank (string1);
-  string2 = [];
-
-  minimus = inf;
-  ## loop on every field of the list
-  for i = 1:fields_nb
-    if (iscellstr (string_set))
-      string2 = deblank (string_set{i});
-    else
-      string2 = deblank (string_set(i,:));
-    endif
-    ## compute Levenshtein distance (not case sensitive)
-    values(i) = levenshtein (lower (string1),
-                             lower (string2),
-                             minimus);
-    ## update the upper_bound to speedup the computation
-    minimus = min (minimus, values(i));
-  endfor
-
-  positions = find (values == minimus);
-
-  if (minimus == 0)  # exact match
-    if (rows (positions) != 1)
-      error ("OdePkg:InvalidArgument",
-             "there are %d strings perfectly matching '%s'",
-             rows (positions), string1);
-    endif
-    res = positions;
-    return;
-  endif
-
-  ## determine the tolerance with the formula described in the
-  ## textinfo section it is a downwards parable with zeros in 0 and m
-  ## and with a maximum in m/2 of value m/2
-  tolerance = m * (-(minimus - m) * minimus * (2 / (m*m)));
-
-  ## if the degree of correctness is fixed by the user, it will
-  ## replace the tolerance
-  if (nargin == 3)
-    if ((isnumeric (correctness)
-         && isscalar (correctness)
-         && correctness == 0)
-        || (ischar (correctness)
-            && strcmp (lower (deblank (correctness)), "exact")))
-      error ("OdePkg:InvalidArgument",
-             "no exact matching for string '%s'", string1);
-    endif
-    if (isnumeric (correctness) && isscalar (correctness))
-      tolerance = correctness;
-    endif
-  endif
-
-  ## returning the positions of the fields whose distance is lower
-  ## than the tolerance
-  for i = 1:fields_nb
-    if (values(i) <= tolerance)
-      res = [res; i];
-    endif
-  endfor
-
-endfunction
-
--- a/scripts/ode/private/ode_struct_value_check.m	Fri Oct 09 14:43:36 2015 -0400
+++ b/scripts/ode/private/ode_struct_value_check.m	Fri Oct 09 12:03:23 2015 -0700
@@ -29,442 +29,345 @@
 ## does not modify any of the field names or field values but terminates with
 ## an error if an invalid option or value is found.
 ##
-## This function is an OdePkg internal helper function therefore it should
-## never be necessary that this function is called directly by a user.
+## This function is an OdePkg internal helper function; Therefore, it should
+## never be necessary for a user to call this function directly.
 ## @end deftypefn
 ##
 ## @seealso{odeset, odeget}
 
-function ode_struct_value_check (arg, solver)
-
-  ## Check the number of input arguments
-  if (nargin == 0 || nargin > 2)
-    error ("OdePkg:InvalidArgument",
-           "wrong input arguments number");
-  endif
+function ode_struct_value_check (arg, solver = [])
 
-  if (! isstruct (arg))
-    error ("OdePkg:InvalidArgument",
-           "first input argument is not a struct");
-  endif
-
-  if (nargin == 1)
-    solver = [];
-  elseif (! ischar (solver) )
-    error ("OdePkg:InvalidArgument",
-           "second input argument is not a string");
-  endif
-
-  fields = fieldnames (arg);
+  fields = (fieldnames (arg)).';
   fields_nb = length (fields);
 
-  for i = 1:fields_nb  # Run through the number of given structure field names
-    switch (fields{i})
+  for fldname = fields  # Cycle over all fields
+    opt = fldname{1};
+    val = arg.(opt);
+
+    switch (opt)
 
       case "AbsTol"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              || any (arg.(fields{i}) <= 0)
-              || ! isreal (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isreal (val)
+              || ! isvector (val) || any (val <= 0))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (! isvector (arg.(fields{i})))
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif ( any (arg.(fields{i}) <= 0))
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Algorithm"
-        if (! isempty (arg.(fields{i})))
-          if (! ischar (arg.(fields{i})))
+        if (! isempty (val))
+          if (! ischar (val))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "BDF"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "on")
-              && ! strcmp (arg.(fields{i}), "off"))
+        if (! isempty (val))
+          if (! strcmp (val, "on") && ! strcmp (val, "off"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Choice"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (arg.(fields{i}) != 1 && arg.(fields{i}) != 2)
+                   "invalid value assigned to field %s", opt);
+          elseif (val != 1 && val != 2)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Eta"
-        if ( ! isempty (arg.(fields{i})) )
-          if ( ! isreal (arg.(fields{i})) )
+        if (! isempty (val))
+          if (! isreal (val) || val < 0 || val >= 1)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif ( arg.(fields{i})<0 || arg.(fields{i})>=1 )
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Events"
-        if (! isempty (arg.(fields{i})))
-          if (! isa (arg.(fields{i}), "function_handle"))
+        if (! isempty (val))
+          if (! isa (val, "function_handle"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Explicit"
-        if (! isempty (arg.(fields{i})))
-          if (! ischar (arg.(fields{i}))
-              || (! strcmp (arg.(fields{i}), "yes")
-                  && ! strcmp (arg.(fields{i}), "no")))
+        if (! isempty (val))
+          if (! strcmp (val, "yes") && ! strcmp (val, "no"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "InexactSolver"
-        if (! isempty (arg.(fields{i})))
-          if (! ischar (arg.(fields{i})))
+        if (! isempty (val))
+          if (! ischar (val))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "InitialSlope"
-        if (! isempty (arg.(fields{i})))
-          if (! ischar (arg.(fields{i}))
-              && (! isnumeric (arg.(fields{i}))
-                  || (! isvector (arg.(fields{i}))
-                      && ! isreal (arg.(fields{i})))))
+        if (! isempty (val))
+          if (! ischar (val)
+              && (! isnumeric (val) || (! isvector (val) && ! isreal (val))))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "InitialStep"
-        if (! isempty (arg.(fields{i})) )
-          if (! isnumeric (arg.(fields{i}))
-              || ! isscalar (arg.(fields{i}))
-              || ! isreal (arg.(fields{i}))
-              || arg.(fields{i}) <=0)
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isreal (val) || ! isscalar (val)
+              || val <= 0)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Jacobian"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i})))
-            if (! isa (arg.(fields{i}), "function_handle")
-                && ! iscell (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val))
+            if (! isa (val, "function_handle") && ! iscell (val))
               error ("OdePkg:InvalidArgument",
-                     "value assigned to field %s is not a valid one",
-                     fields{i});
+                     "invalid value assigned to field %s", opt);
             endif
           endif
         endif
 
       case "JConstant"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "on")
-              && ! strcmp (arg.(fields{i}), "off"))
+        if (! isempty (val))
+          if (! strcmp (val, "on") && ! strcmp (val, "off"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "JPattern"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              && ! isscalar (arg.(fields{i}))
-              && ! isvector (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) && ! isvector (val))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Mass"
-        if (! isempty (arg.(fields{i})))
-          if ((! isnumeric (arg.(fields{i}))
-               || ! ismatrix (arg.(fields{i})))
-              && ! isa (arg.(fields{i}), "function_handle"))
+        if (! isempty (val))
+          if ((! isnumeric (val) || ! ismatrix (val))
+              && ! isa (val, "function_handle"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MassConstant"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "on")
-              && ! strcmp (arg.(fields{i}), "off"))
+        if (! isempty (val))
+          if (! strcmp (val, "on") && ! strcmp (val, "off"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MassSingular"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "yes")
-              && ! strcmp (arg.(fields{i}), "no")
-              && ! strcmp (arg.(fields{i}), "maybe"))
+        if (! isempty (val))
+          if (! any (strcmp (val, {"yes", "no", "maybe"})))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MaxNewtonIterations"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val)
+              || val != fix (val) || val <= 0)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (mod (arg.(fields{i}), 1) != 0
-                  || arg.(fields{i}) <= 0)
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MaxOrder"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val)
+              || val != fix (val) || val <= 0 || val >= 8)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (mod (arg.(fields{i}), 1) != 0
-                  || arg.(fields{i}) <= 0
-                  || arg.(fields{i}) >= 8 )
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MaxStep"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              || ! isscalar (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isscalar (val) || val <= 0)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (arg.(fields{i}) <= 0)
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MStateDependence"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "none")
-              && ! strcmp (arg.(fields{i}), "weak")
-              && ! strcmp (arg.(fields{i}), "strong"))
+        if (! isempty (val))
+          if (! any (strcmp (val, {"none", "weak", "strong"})))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "MvPattern"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              && ! isvector (arg.(fields{i})) )
+        if (! isempty (val))
+          if (! isnumeric (val) && ! isvector (val))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "NewtonTol"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              || ! isreal (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isreal (val) || any (val <= 0))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (any (arg.(fields{i}) <= 0))
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "NonNegative"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              || ! isvector (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isvector (val)
+              || any (val <= 0) || any (val != fix (val)))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (any (arg.(fields{i}) <= 0)
-                  || any (mod (arg.(fields{i}), 1) != 0))
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "NormControl"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "on")
-              && ! strcmp (arg.(fields{i}), "off"))
+        if (! isempty (val))
+          if (! strcmp (val, "on") && ! strcmp (val, "off"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "OutputFcn"
-        if (! isempty (arg.(fields{i})))
-          if (! isa (arg.(fields{i}), "function_handle"))
+        if (! isempty (val))
+          if (! isa (val, "function_handle"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "OutputSave"
-        if (! isempty (arg.(fields{i})))
-          if (! isscalar (arg.(fields{i}))
-              && arg.(fields{i}) != Inf)
+        if (! isempty (val))
+          if (! isscalar (val) && val != Inf)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif ((mod (arg.(fields{i}), 1) != 0 || arg.(fields{i}) <= 0)
-                  && arg.(fields{i}) != Inf)
+                   "invalid value assigned to field %s", opt);
+          elseif ((val != fix (val) || val <= 0) && val != Inf)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "OutputSel"
-        if (! isempty (arg.(fields{i})))
-          if (! isscalar (arg.(fields{i})) )
-            if (! isnumeric (arg.(fields{i}))
-                || ! isvector (arg.(fields{i})))
-              error ("OdePkg:InvalidArgument",
-                     "value assigned to field %s is not a valid one",
-                     fields{i});
-            endif
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isvector (val))
+            error ("OdePkg:InvalidArgument",
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "PolynomialDegree"
-        if (! isempty (arg.(fields{i})) )
-          if (! isnumeric (arg.(fields{i}))
-              || ! isvector (arg.(fields{i})) )
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isvector (val) || any (val <= 0))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (any (arg.(fields{i}) <= 0))
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "QuadratureOrder"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              || ! isvector (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isvector (val) || any (val <= 0))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (any(arg.(fields{i}) <= 0))
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Refine"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i}))
-              || ! isscalar (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isscalar (val)
+              || val != fix (val)  || val < 0 || val > 5)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (mod (arg.(fields{i}), 1) != 0
-                  || arg.(fields{i}) < 0
-                  || arg.(fields{i}) > 5 )
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "RelTol"
-        if (! isempty (arg.(fields{i})) )
-          if (! isnumeric (arg.(fields{i})) )
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (! isreal (arg.(fields{i}))
-                  || any (arg.(fields{i}) <= 0))
+        if (! isempty (val))
+          if (! isnumeric (val) || ! isreal (val) || any (val <= 0))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
-        endif
-        if (any (strcmp (solver, {"ode23", "ode23d", "ode45", "ode45d",
-                                  "ode54", "ode54d", "ode78", "ode78d"})))
-          if (! isempty (arg.(fields{i})) && ! isscalar (arg.(fields{i})))
-            error ("OdePkg:InvalidArgument",
-                   "for this type of solver, value assigned to field %s ",
-                   "is not a valid one", fields{i});
+          if (any (strcmp (solver, {"ode23", "ode23d", "ode45", "ode45d",
+                                    "ode54", "ode54d", "ode78", "ode78d"})))
+            if (! isscalar (val))
+              error ("OdePkg:InvalidArgument",
+                     "invalid value assigned to field %s", opt);
+            endif
           endif
         endif
 
       case "Restart"
-        if (! isempty (arg.(fields{i})))
-          if (! isnumeric (arg.(fields{i})))
+        if (! isempty (val))
+          if (! isnumeric (val) || val != fix (val) || val <= 0)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
-          elseif (mod (arg.(fields{i}), 1) != 0
-                  || arg.(fields{i}) <=0 )
-            error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Stats"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "on")
-              && ! strcmp (arg.(fields{i}), "off"))
+        if (! isempty (val))
+          if (! strcmp (val, "on") && ! strcmp (val, "off"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "TimeStepNumber"
-        if (! isempty (arg.(fields{i})))
-          if (mod (arg.(fields{i}), 1) != 0
-              || arg.(fields{i}) <= 0)
+        if (! isempty (val))
+          if (val != fix (val) || val <= 0)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "TimeStepSize"
-        if (! isempty (arg.(fields{i})))
-          if (! isreal (arg.(fields{i}))
-              || (arg.(fields{i}) == 0))
+        if (! isempty (val))
+          if (! isreal (val) || val == 0)
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "UseJacobian"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "yes")
-              && ! strcmp (arg.(fields{i}), "no"))
+        if (! isempty (val))
+          if (! strcmp (val, "yes") && ! strcmp (val, "no"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       case "Vectorized"
-        if (! isempty (arg.(fields{i})))
-          if (! strcmp (arg.(fields{i}), "on")
-              && ! strcmp (arg.(fields{i}), "off"))
+        if (! isempty (val))
+          if (! strcmp (val, "on") && ! strcmp (val, "off"))
             error ("OdePkg:InvalidArgument",
-                   "value assigned to field %s is not a valid one", fields{i});
+                   "invalid value assigned to field %s", opt);
           endif
         endif
 
       otherwise
         warning ("OdePkg:InvalidArgument",
-                 "no fields with name %s in ODE options.", fields{i});
+                 "invalid field '%s' in ODE options", opt);
     endswitch
   endfor
 
@@ -480,8 +383,9 @@
 %!demo
 %! # Create the OdePkg options structure A with odeset and check it 
 %! # with odepkg_structure_check.  This actually is unnecessary
-%! # because odeset automtically calls odepkg_structure_check before
+%! # because odeset automatically calls odepkg_structure_check before
 %! # returning.
 %!
-%! A = odeset (); ode_struct_value_check (A);
+%! A = odeset ();
+%! ode_struct_value_check (A);