function options = AnnealSet(varargin)
%ANNEALSET Create/alter ANNEAL OPTIONS structure.
%   OPTIONS = ANNEALSET('PARAM1',VALUE1,'PARAM2',VALUE2,...) creates an 
%   simulated annealing options structure OPTIONS in which the named parameters
%   have the specified values.  Any unspecified parameters are set to [] 
%   (parameters with value [] indicate to use the default value for that 
%   parameter when OPTIONS is passed to the simulated annealing function). It 
%   is sufficient to type only the leading characters that uniquely identify 
%   the parameter.  Case is ignored for parameter names.  
%   NOTE: For values that are strings, correct case and the complete string 
%   are required; if an invalid string is provided, the default is used.
%   
%   OPTIONS = ANNEALSET(OLDOPTS,'PARAM1',VALUE1,...) creates a copy of OLDOPTS 
%   with the named parameters altered with the specified values.
%   
%   OPTIONS = ANNEALSET(OLDOPTS,NEWOPTS) combines an existing options structure
%   OLDOPTS with a new options structure NEWOPTS.  Any parameters in NEWOPTS
%   with non-empty values overwrite the corresponding old parameters in 
%   OLDOPTS. 
%   
%   ANNEALSET with no input arguments and no output arguments displays all 
%   parameter names and their possible values.
%
%   OPTIONS = ANNEALSET (with no input arguments) creates an options structure
%   OPTIONS where all the fields are set to [].
%
%   OPTIONS = ANNEALSET(OPTIMFUNCTION) creates an options structure with all
%   the parameter names and default values relevant to the optimization
%   function named in OPTIMFUNCTION. For example,
%           AnnealSet('fminbnd') 
%   returns an options structure containing all the parameter names and default 
%   values relevant to the function 'fminbnd'.
%   
%ANNEALSET PARAMETERS
% Display - Level of display [ off | iter | {final} | simplex | best]  
% MaxFunEvals - Maximum number of function evaluations allowed 
%                   [ positive integer ]
% MaxIter - Maximum number of iterations allowed [ positive integer ]
% TolFun - Termination tolerance on the function value [ positive scalar ]
% TolX - Termination tolerance on X [ positive scalar ]
% BestSave - Save filename or 'off' for no save
% TInitial - Initial temperature [ positive scalar ]
% TFactor - Factor to decrease temperature each step [ positive scalar ]
% NumSteps - Number of Steps [ positive integer ]
% QFactor - Factor to increase MaxIter and MaxFunEvals for last (quench) step
% Restart - Step interval to perform restart [ positive integer ]
% Schedule - [ {regular} | vector of postive scalars not of size (1 by 3) |
%             matrix of size (n by 3) with n a positive integer]
%     If Schedule is a string ANNEAL uses TInitial, TFactor, NumSteps,
%        MaxFunEvals, MaxIter, and QFactor to determine cooling schedule
%     If Schedule is a vector (not 1 by 3) it is interpreted as temperatures
%        MaxFunEvals, MaxIter, and QFactor (if Schedule(end) = 0) are used. 
%     If Schedule is an (n by 3) matrix each row is interpreted as 
%        [Temperature, MaxFunEvals, MaxIter]
%
%   See also ANNEALGET, ANNEAL.
%
%   Adapted from OPTIMSET  
%   Copyright (c) 1984-98 by The MathWorks, Inc.

%  THREE THINGS TO CHANGE WHEN ADDING OPTIONS:
%     (1) Comment at top
%     (2) Print out of possible properties
%     (3) List of names

% Print out possible values of properties.
if (nargin == 0) & (nargout == 0)
   fprintf('           Display: [ off | iter | {final} | simplex ]\n');
   fprintf('          Schedule: [ {regular} | n-vector | n by 3 matrix ]\n');
   fprintf('          TInitial: [ positive scalar ]\n');
   fprintf('           Tfactor: [ positive scalar ]\n');
   fprintf('          NumSteps: [ positive integer ]\n');
   fprintf('           Qfactor: [ positive scalar ]\n');
   fprintf('           Restart: [ positive integer ]\n');
   fprintf('       MaxFunEvals: [ positive scalar ]\n');
   fprintf('           MaxIter: [ positive scalar ]\n');
   fprintf('            TolFun: [ positive scalar ]\n');
   fprintf('              TolX: [ positive scalar ]\n')
   fprintf('          BestSave: [ {off} | filename ]\n');
   fprintf('\n');
   return;
end


% If we pass in a function name then pass return the defaults.
if (nargin==1) & ischar(varargin{1})
   funcname = lower(varargin{1});  
   if ~exist(funcname)
      msg = sprintf(...
         'No default options available: the function ''%s'' does not exist on the path.',funcname);
      error(msg)
   end
   try 
      options = feval(funcname,'defaults');
   catch
      msg = sprintf(...
         'No default options available for the function ''%s''.',funcname);
      error(msg)
   end
   return
end


Names = [
   'Display           '
   'Schedule          '
   'TInitial          '
   'TFactor           '
   'NumSteps          '
   'Qfactor           '
   'Restart           '
   'MaxFunEvals       '
   'MaxIter           '
   'TolFun            '
   'TolX              '
   'BestSave          '
    ];
[m,n] = size(Names);
names = lower(Names);

% Combine all leading options structures o1, o2, ... in AnnealSet(o1,o2,...).
options = [];
for j = 1:m
   eval(['options.' Names(j,:) '= [];']);
end
i = 1;
while i <= nargin
   arg = varargin{i};
   if ischar(arg)                         % arg is an option name
      break;
   end
   if ~isempty(arg)                      % [] is a valid options argument
     if ~isa(arg,'struct')
       error(sprintf(['Expected argument %d to be a string parameter name ' ...
               'or an options structure\ncreated with ANNEALSET.'], i));
     end
     for j = 1:m
        if any(strcmp(fieldnames(arg),deblank(Names(j,:))))
           eval(['val = arg.' Names(j,:) ';']);
        else
           val = [];
        end
        if ~isempty(val)
           eval(['options.' Names(j,:) '= val;']);
        end
     end
   end
   i = i + 1;
end

% A finite state machine to parse name-value pairs.
if rem(nargin-i+1,2) ~= 0
   error('Arguments must occur in name-value pairs.');
end
expectval = 0;                          % start expecting a name, not a value
while i <= nargin
   arg = varargin{i};
   
   if ~expectval
     if ~ischar(arg)
      error(sprintf('Expected argument %d to be a string parameter name.', i));
     end
      
     lowArg = lower(arg);
     j = strmatch(lowArg,names);
     if isempty(j)                       % if no matches
        error(sprintf('Unrecognized parameter name ''%s''.', arg));
     elseif length(j) > 1                % if more than one match
        % Check for any exact matches (in case any names are subsets of others)
        k = strmatch(lowArg,names,'exact');
        if length(k) == 1
           j = k;
        else
           msg = sprintf('Ambiguous parameter name ''%s'' ', arg);
           msg = [msg '(' deblank(Names(j(1),:))];
           for k = j(2:length(j))'
              msg = [msg ', ' deblank(Names(k,:))];
           end
           msg = sprintf('%s).', msg);
           error(msg);
        end
     end
     expectval = 1;                      % we expect a value next
     
   else
     eval(['options.' Names(j,:) '= arg;']);
     expectval = 0;

   end
   i = i + 1;
end

if expectval
   error(sprintf('Expected value for parameter ''%s''.', arg));
end

