function optout=imfil_optset(varargin) % IMFIL_OPTSET % % Set the options in imfil. % C. T. Kelley, Nov 11, 2007 % % OPTIONS = IMFIL_OPTSET('name1',val1,'name2',val2, ... ); % creates the options structure with the options named % in the list set to something other than the defaults. % % OPTOUT = IMFIL_OPTSET('name1',val1,'name2',val2, ... , OPTIN); % modifies the structure OPTIN and creates a new structure % OPTOUT. % % And now for the lists. The details of the options, the motiviation % for the defaults, and suggestions for their use live in the manual. % % Scalar Options: % % armijo_reduction: Reduction factor for the linesearch. The default is .5. % % complete_history: 1 or 'on' to store complete history of all calls to f. % 0 or 'off' otherwise. The default is 'on'. % % fscale: A ``typical value of f'', used to improve the quality of % the difference gradient. The default is % 1.2*| f(x_0) |. % % function_error: Set this to an estimate for the absolute error in f % if you have one. Ignore this option if you do have no idea % how accurate your function evaluation is. The optimization % loop will terminate when the maximum absolute difference % of function values on the stencil is < function_error. % The default is -1, which means that function_error has no % effect. % % least_squares: imfil does the smart thing if you're solving a nonlinear % overdetermined (m >=n) least squares problem. Set % least_squares = 1 and let your function return the vector residual % in R^m. imfil will compute f'*f/2 as part of the optimization. % % limit_quasi_newton: 'yes' or 1 means that the quasi-Newton direction will be % truncated to a length of at most 10*h, where h is the current % scale. This is a good idea if the function is very noisy, as % it can keep the line search from thrashing about. The code % is different from the old FORTRAN version, and now I am not % sure. 'yes' is currently the default. % % maxit: The quasi-Newton inner iteration is limited to maxit*n iterations % for each scale. The default is 50. % % maxitarm: The line search will reduce the step by at most maxitarm times % before declaring failure. The default is 3. The line search is % on a short leash for good reason. If you don't find something % useful after three reductions, you're not likely to do better % with more effort. % % noise_aware: Set this to one if your function can return as estimate % of the norm of the noise. The call is % [fout,ifail,icount,noise_val]=f(x). % In this case imfil will declare stencil failure if % the difference between the max and min values on the % stencil is < noise_val. % The default is 0 (not noise_aware). % You can set stencil_aware=1 and noise_aware=1 at the same time. % % noise_val is not the same as function_error. You set noise_val % via the call to f as f's best estimate of the error. noise_val % is used as a test to reject the stencil and reduce the scale. % function_error is used to terminate the optimization. % % parallel: Set this to one if f can accept multiple input vectors and % exploit parallelism. The output should be vectors of % [fout,ifail,icount], with a length equal to the number of % input variables. When imfil computes the stencil gradient % f will get all the directions at once. It is then your job % to manage the parallel coputation for optimal load balancing. % % You may also want to parallelize the line search and enable % additional exploration of the stencil directions. To do this % set parallel to the number of processors you want to committ % to this part of the optimization. Read the manual to see how % this rapidly changing part of the code works. % % quasi: Your choices for quasi-Newton acceleration are none (0), % BFGS ('bfgs'), or SR-1 ('sr1'). The default as of today is BFGS, but % I may change that as I have done in the past. % % random_stencil: Set this to k > 0 and k random unit vectors will be % added to the stencil before each call to the simplex gradient. % The default is 0. % % scalestart and scaledepth: The range of scales is 2^-scalestart % to 2^-scaledepth. The defaults are scalestart=1, scaledepth=7. % % scale_aware: Setting this to 1 tells imfil that f can do something % smart if it knows the scale. The call then becomes % [fout,ifail,icount]=f(x,h) % The scale is the second input argument. % The default is 0 (not scale-aware) % You can set stencil_aware=1 and noise_aware=1 at the same time. % % stencil: imfil has three built-in stencils, with room for you to % create you own in the matrix options. Setting stencil % lets you chose the centered difference stencil (0), the % forward difference stencil (1), and the positive basis % stencil (2). The default is the centered difference stencil % (stencil = 0). Choosing the forward difference stencil will % cause a warning, and that option will go away in a future % version. % % stencil_wins: Setting this to 'yes' or 1 will make the new point % the better of the best point in the stencil and % the point returned by the line search. The default 'no' % is a bias in favor of the quasi-Newton point, and % sets the point to the quasi-Newton point if the line % search succeeds, and to the best point in the stencil % only if the line search fails. % % target: You may have either a good lower estimate of the optimal % value of f, or an idea about when the optimization has done % enough. If you do, set target to that value and the optimization % will stop when f < target. % % % Matrix options % % custom_scales: You may set you own scales with an array % H=[h(1), ... h(smax)] % where 1 > h(1) > .. > h(smax) > 0 % % The syntax is % optout=imfil_optset('custom_scales',H,optin) % % vstencil: You may replace the built-in stencils with your own custom % design. If VS is your N x M list of M directions, then % % optout=imfil_optset('vstencil',VS,optin) % % will get it done. % % Advanced Options: WARNING!!! You have to be aware of imfil_core's % internal scaling to use this stuff. RTFM. % % add_new_directions: % This function, which you must provied, will % examine the current stencil, scale, and history of the iteration % and add directions to the stencil. You may want to do this, for % example, to add tangent directions for nearly active linear % constraints. % % You enable this with % options=imfil_optset('add_new_directions','mystencil',options); % where the calling sequence of your function must be % % Vadd=mystencil(x,h,V); % % where x = current iterate; % h = current scale; % V = stencil for this iteration (which may include any % random directions you asked for with the % random_stencil option) % % Please look at the example for this in the software collection and in % the users' guide. % nv=length(varargin); % % Even number of arguments means you're setting options from scratch. % if 2*floor(.5*nv) == nv optin = set_defaults; mv=nv/2; else % % Odd number of arguments means you're changing options. % mv=(nv-1)/2; optin=varargin{nv}; end optout=optin; for i=1:mv optout=imfil_optset_base(varargin{2*i-1},varargin{2*i},optout); end function optout=imfil_optset_base(str,val,optin) % IMFIL_OPTSET_BASE % % This is the internal function to manage the options structure. % % Is this an advanced option? switch str case 'add_new_directions' adv_flag=1; otherwise adv_flag=0; end % optout=set_defaults; if nargin == 3 optout=optin; end if nargin > 0 str=lower(str); parms=fieldnames(optout); n=length(parms); okflag=0; % % Test for verbal shortcuts and do the right thing. % The advanced options are set to names of functions and % do not use verbal shortcuts. % if ischar(val) & adv_flag==0 [okflag,optout]=verbal_shortcut(str,val,optin); if okflag == 0 disp('error in imfil_optset'); disp([val,' is not a legal verbal short cut for parameter ', str]); end else % % Update options. % for p=1:n if strcmp(str,parms(p)) optout=setfield(optout,str,val); okflag=1; end end if okflag == 0 disp('error in imfil_optset'); disp([str,' is not a known parameter name']); end end end function imfil_defaults = set_defaults % % Default values % add_new_directions = []; % function to add new directions. % armijo_reduction = .5; % Step size reduction factor for Armijo rule. % complete_history = 1; % Store complete history. % custom_scales = []; % vector of custom scales % fscale = -1.2; % Scale function by 1.2 times abs(f(x_0)). % function_error = -1; % Do not terminate on small variation of f. % least_squares = 0; % Is this a nonlinear least squares problem? % limit_quasi_newton = 1; % Don't let the quasi-Newton direction get too long. % maxit = 50; % At most maxit*n quasi-Newton iterations/scale. % maxitarm = 3; % Limit on number of step length reductions. % noise_aware = 0; % Can your function estimate the noise? Default = no. % parallel = 0; % Serial is the default. % quasi=1; % BFGS % random_stencil = 0; % Leave the stencil alone. % scale_aware = 0; % Can your function use the scale? % scalestart = 1; % Scales begin at h=(1/2)^scalestart; % scaledepth = 7; % Scales end at h=(1/2)^(scalestart+scaledepth) % stencil = 0; % Central difference stencil. % stencil_wins=0; % Who's the new point? % target = -1.d8; % Target for optimal value = -1.d8. % You should try to do better. % verbose = 0; % Shut up. % vstencil = []; % No fancy stencil. % % Fill the structure % imfil_defaults=struct(... 'add_new_directions',add_new_directions,... 'armijo_reduction',armijo_reduction,... 'complete_history',complete_history,... 'custom_scales',custom_scales,... 'fscale', fscale,... 'function_error',function_error,... 'least_squares',least_squares,... 'limit_quasi_newton',limit_quasi_newton,... 'maxit',maxit,... 'maxitarm', maxitarm,... 'noise_aware', noise_aware,... 'parallel',parallel,... 'quasi',quasi,... 'random_stencil',random_stencil,... 'scale_aware',scale_aware,... 'scalestart',scalestart,... 'scaledepth',scaledepth,... 'stencil',stencil,... 'stencil_wins', stencil_wins,... 'target',target,... 'verbose',verbose,... 'vstencil',vstencil); function [okflag,optout]=verbal_shortcut(str,val,optin) % VSHORT % Plugs into imfil_optset and lets you use verbal shortcuts % to control options with yes/no, on/off, or short lists of % options. % okflag=0; optout=optin; val=lower(val); switch str case 'add_new_directions' okflag=2; case 'complete_history' [valout,okflag]=yes_no(val); strout='complete_history'; okflag=1; case 'limit_quasi_newton' strout='limit_quasi_newton'; [valout,okflag]=yes_no(val); case 'quasi' okflag=1; strout='quasi'; switch val case 'bfgs' valout=1; case 'sr1' valout=2; case 'none' valout=0; otherwise okflag=0; end case 'scale_aware' strout='scale_aware'; [valout,okflag]=yes_no(val); case 'stencil_wins' strout='stencil_wins'; [valout,okflag]=yes_no(val); case 'verbose' strout='verbose' [valout,okflag]=yes_no(val); end if okflag==1 optout=imfil_optset(strout,valout,optin); end if okflag==2 okflag=1; end function [valout,okflag]=yes_no(val) valout=-1; okflag=1; switch val case 'yes' valout=1; case 'on' valout=1; case 'off' valout=0; case 'no' valout=0; otherwise okflag=0; end