sabato 2 novembre 2013

Odeset & odeget

Odeset & odeget

Odeset and odeget functions allow to build a valid ODE options structure. They are already available in Octave odepkg but they are not perfectly compatible with MATLAB odeset and odeget functions. Furthermore, for geometric integrators like Spectral Variational Integrators,
I will need new options into the ODE options structure, which now are not admitted in Octave odepkg.

So that I have written my own versions of odeget.m, odeset.m and the new function ode_struct_value_check.m in order to have full compatibility with MATLAB odeset and odeget (their same behaviour on the basis of their official documentation) and also the possibility to add new field names which i will need for future solvers of this project.

The new fields are the union of MATLAB ODE options and Octave ODE options, plus my new options (default values are in square brackets):

'             AbsTol:  scalar or vector, >0, [1.e-6]'
'                BDF:  binary, {on, [off]}'
'             Events:  '
'           Explicit:  binary, {yes, no, []}'
'      InexactSolver:  switch, {inexact_newton, []}'
'       InitialSlope:  vector, []'
'        InitialStep:  scalar, >0, []'
'           Jacobian:  matrix or function_handle, []'
'          JConstant:  binary, {on, [off]}'
'           JPattern:  sparse matrix, []'
'               Mass:  matrix or function_handle, []'
'       MassConstant:  binary, {on, [off]}'
'       MassSingular:  switch, {yes, [maybe], no}'
'MaxNewtonIterations:  scalar, integer, >0, [1.e3]'
'           MaxOrder:  switch, {1, 2, 3, 4, [5]}'
'            MaxStep:  scalar, >0, []'
'   MStateDependence:  switch, {none, [weak], strong}'
'          MvPattern:  sparse matrix, []'
'          NewtonTol:  scalar or vector, >0, []'
'        NonNegative:  vector of integers, []'
'        NormControl:  binary, {on, [off]}'
'          OutputFcn:  function_handle, []'
'         OutputSave:  scalar, integer, >0, []'
'          OutputSel:  scalar or vector, []'
'   PolynomialDegree:  scalar or vector, integer, >0, []'
'    QuadratureOrder:  scalar or vector, integer, >0, []'
'             Refine:  scalar, integer, >0, []'
'             RelTol:  scalar, >0, [1.e-3]'
'              Stats:  binary, {on, [off]}'
'     TimeStepNumber:  scalar, integer, >0, []'
'       TimeStepSize:  scalar, >0, []'
'         Vectorized:  binary, {on, [off]}'

The usage of odeset will be one of the following:

odeset
opt = odeset()
opt = odeset(old_ODE_options,new_ODE_options)
opt = odeset(old_ODE_options,'field1',value1,'field2',value2,...)
opt = odeset('field1',value1,'field2',value2,'field3',value3,...)

The usage of odeget will be one of the following:

option_value = odeget(ODE_structure,'field')
option_value = odeget(ODE_structure,'field',default_value)
option_value = odeget(any_struct,'field',default_value,'fast')
The last usage is needed for MATLAB compatibility and represents a fast access to the given structure with no error checking on options names.

Fuzzy string comparison

Users may do mistakes while typing ODE option names or they may want to write everything in low cases for a faster coding. So that my odeset and odeget functions behave in a user-friendly way, calling the fuzzy_compare function which determines the distance of each structure option name from the given word and returns the indices of those options whose distance is under a given tolerance.

The idea is that word cases are not relevant, if we want an exact matching then the tolerance will be 0, if no index is returned then it will definitely be a typing error, if one index is returned but words don't match exactly a warning will be displayed saying that the program is going on assuming that the user was intending the closest option name, otherwise all the fields whose distance is under the tolerance will be displayed and the user will be asked to insert the name again.

Signature of this function follows.

res = fuzzy_compare(string1,string_set,correctness)
  • string1 must be a string and is the option name we're looking for;
  • string_set must be a cell array of strings or a column vector of strings; it represents the set of option names;
  • correctness is the tolerance we want. It is an optional input argument;
We may set correctness equal to 'exact' or 0 and in this case fuzzy_compare will look only for exact matching; if we set correctness to any positive integer it will be the tolerance of the method (that is the maximum distance, from the given string, accepted). If we don't specify anything for correctness then the tolerance will be calculated as a function of the minimum distance and of the length of the given string: the less the distance, the less the tolerance; the greater the length, the greater the tolerance.
tolerance = minimus + floor(length(string1)/4)*floor(minimus/3)
There exist many definitions of distance between strings. I've chosen the Levenshtein distance.

Levenshtein distance

The Levenshtein distance is a string metric and is equal to the minimum number of single-characters edit (insertion, deletion and substitution) required to change one word into the other. This is the main algorithm of levenshtein function:

function [dist,d] = levenshtein(string1,string2)
  m = length(string1);
  n = length(string2);

  d = zeros(m+1,n+1);
  d(2:m+1,1) = [1:1:m];
  d(1,2:n+1) = [1:1:n];

  for j=2:1:n+1
    for k=2:1:m+1
      if(string1(k-1)==string2(j-1))
        d(k,j)=d(k-1,j-1);
      else
        d(k,j)=min(d(k-1,j)+1,min(d(k,j-1)+1,d(k-1,j-1)+1));
      end
    end
  end

  dist = d(m+1,n+1);
end

All the code is available under the terms of GNU General Public License at my_octave-odepkg.

Nessun commento:

Posta un commento