function options = sdpsettings(varargin)
%sdpsettings       Create/alter solver options structure.
%
%   OPTIONS = SDPSETTINGS with no input arguments returns 
%   setting structure with default values
%
%   OPTIONS = SDPSETTINGS('NAME1',VALUE1,'NAME2',VALUE2,...) creates an
%   solution options structure OPTIONS in which the named properties have
%   the specified values.  Any unspecified properties have default values.
%   It is sufficient to type only the leading characters that uniquely
%   identify the property.  Case is ignored for property names.
%   
%SDPSETTINGS PROPERTIES
%   
% Solver             - Forces use of specific solver [ char ''|SP|SDPT3|SEDUMI|SDPA|CSDP|DSDP|MAXDET|SOCP ('')]
% Silent             - Supress output from solvers [ integer 0|1 (0)] 
% Savesolveroutput   - Keep all data returned from solver [ integer 0|1 (0)] 
% sp._               - See SP manual
% maxdet._           - See MAXDET manual
% socp._             - See SOCP manual
% sdpt3._            - See SDPT3 manual
% sedumi._           - See SeDuMi manual
% csdp._             - See CSDP manual
% sdpa._             - See SDPA manual
% dsdp._             - See DSDP manual
%
%   
% See also SOLVESDP, LMI, ADDLMI

% Author Johan Löfberg (ripped from odeset)
% $Id: sdpsettings.m,v 1.24 2001/12/12 09:22:46 johanl Exp $

% Print out possible values of properties.
if (nargin == 0) & (nargout == 0)
   help sdpsettings
   return;
end

Names = {'Solver'
     'Silent'
    'SaveSolverOutput'
     'sp.AbsTol'
     'sp.RelTol'
     'sp.nu'
     'sp.tv'
     'sp.Mfactor'
     'sp.NTiters'
     'maxdet.AbsTol'
     'maxdet.RelTol'
     'maxdet.gam'
     'socp.AbsTol'
     'socp.RelTol'
     'socp.target'
     'socp.max_iter'
     'socp.nu'
     'socp.outmode'
     'sdpt3.vers'
     'sdpt3.gam'
     'sdpt3.predcorr'
     'sdpt3.expon'
     'sdpt3.gaptol'
     'sdpt3.inftol'
     'sdpt3.steptol'
     'sdpt3.maxit'
     'sdpt3.sw2PC_tol'
     'sdpt3.use_corrprim'
     'sdpt3.printyes'
     'sdpt3.scale_data'
     'sdpt3.schurfun'
     'sdpt3.schurfun_parms'
     'sdpt3.randnstate'
     'sdpt3.spdensity'
     'sdpt3.rmdepconstr'
     'sdpt3.CACHE_SIZE'
     'sdpt3.LOOP_LEVEL'
     'sdpa.maxIteration'
     'sdpa.epsilonStar'
     'sdpa.lambdaStar'
     'sdpa.megaStar'
     'sdpa.lowerBound'
     'sdpa.upperBound'
     'sdpa.betaStar'
     'sdpa.betaBar'
     'sdpa.gammaStar'
     'sdpa.epsilonDash'
     'sedumi.alg'
     'sedumi.theta'
     'sedumi.beta'
     'sedumi.eps'
     'sedumi.numtol'
     'sedumi.denq'
     'sedumi.denf'
     'sedumi.vplot'
     'sedumi.eps'
     'sedumi.bigeps'
     'sedumi.numtol'
     'sedumi.maxiter'
     'sedumi.stopat'
     'sedumi.chol.numlvl'
     'sedumi.chol.deptol'
     'sedumi.chol.ph1tol'
     'sedumi.chol.maxu'
     'sedumi.chol.maxuden'
     'sedumi.chol.canceltol'
     'sedumi.chol.abstol'
     'sedumi.stepdif'
     'sedumi.w'
     'sedumi.cg.maxiter'
     'sedumi.cg.restol'
     'sedumi.cg.refine'
     'sedumi.cg.stagtol' 
     'sedumi.cg.qprec'
     'dsdp.gaptol'
     'dsdp.inftol'
     'dsdp.steptol'  
     'dsdp.maxit'
     'dsdp.scale_data'
     'dsdp.r0'};

ObsoleteNames ={
   'AbsTol'
   'RelTol'
   'Accelerator'
   'maxiters'
   'AbsTol_init'
   'RelTol_init'
   'Accelerator_init'
   'maxiters_init'
   'tv'
   'Mfactor'
   'sedumi.UseLPSolver'};

[m,n] = size(Names);
names = lower(Names);
obsoletenames = lower(ObsoleteNames);

% General options
options.Solver = '';
options.Silent = 0;
options.SaveSolverOutput = 0;

% Options for SP solver (sp, bigM and phase1)
options.sp.AbsTol  = 1e-6;
options.sp.RelTol  = 1e-6;
options.sp.nu      = 50;
options.sp.tv      = -inf; 
options.sp.Mfactor = [50e3 1.1];
options.sp.NTiters = 50;

% Options for MAXDET solver
options.maxdet.AbsTol = 1e-6;
options.maxdet.RelTol = 1e-6;
options.maxdet.gam    = 25;
options.maxdet.NTiters= 50;
options.socp.AbsTol   = 1e-5;
options.socp.RelTol   = 1e-5;
options.socp.target   = -inf;
options.socp.max_iter = 50;
options.socp.nu       = 50;
options.socp.outmode  = 0;

% Options for SDPT3
options.sdpt3.vers     = 2; 
options.sdpt3.gam      = 0;  
options.sdpt3.predcorr = 1;
options.sdpt3.expon    = [3 1 1 1]; 
options.sdpt3.gaptol   = 1e-8;
options.sdpt3.inftol   = 1e-8; 
options.sdpt3.steptol  = 1e-6; 
options.sdpt3.maxit    = 50;
options.sdpt3.sw2PC_tol  = inf;
options.sdpt3.use_corrprim  = 0;
options.sdpt3.printyes   = 1; 
options.sdpt3.scale_data = 0; 
options.sdpt3.schurfun   = [];
options.sdpt3.schurfun_parms = []; 
options.sdpt3.randnstate = 0; 
options.sdpt3.spdensity   = 0.5; 
options.sdpt3.rmdepconstr = 0; 
options.sdpt3.CACHE_SIZE = 256;
options.sdpt3.LOOP_LEVEL = 8; 

% Options for SDPA
options.sdpa.maxIteration = 40;
options.sdpa.epsilonStar = 1e-7;
options.sdpa.lambdaStar = 1e2;
options.sdpa.megaStar = 2;
options.sdpa.lowerBound = -1e5;
options.sdpa.upperBound = 1e5;
options.sdpa.betaStar = 0.1;
options.sdpa.betaBar = 0.2;
options.sdpa.gammaStar = 0.9;
options.sdpa.epsilonDash = 1e-7;

% Options for SeDuMi 
options.sedumi.alg    = 1;
options.sedumi.theta  = 0.25;
options.sedumi.beta   = 0.5;
options.sedumi.eps    = 1e-9;
options.sedumi.bigeps = 1e-3;
options.sedumi.numtol = 1e-8;
options.sedumi.denq   = 0.75;
options.sedumi.denf   = 10;
options.sedumi.vplot  = 0;
options.sedumi.numtol = 1e-5;
options.sedumi.maxiter= 100;
options.sedumi.stepdif= 1;
options.sedumi.w      = [1 1];
options.sedumi.stopat     = 101;
options.sedumi.cg.maxiter = 25;
options.sedumi.cg.restol  = 5e-3;
options.sedumi.cg.refine  = 1;
options.sedumi.cg.stagtol = 5e-14;
options.sedumi.cg.qprec   = 0;
options.sedumi.chol.canceltol = 1e-12;
options.sedumi.chol.maxu   = 5e5;
options.sedumi.chol.abstol = 1e-20;
options.sedumi.chol.maxuden= 5e2;

% Options for DSDP
options.dsdp.gaptol = 1e-3;
options.dsdp.inftol = 1e-8;
options.dsdp.steptol=1e-2;   
options.dsdp.maxit  = 100;
options.dsdp.scale_data = 1;
options.dsdp.r0 = -1;

i = 1;
% 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 ~isstr(arg)
         error(sprintf('Expected argument %d to be a string property name.', i));
      end
      
      lowArg = lower(arg);

      j_old = strmatch(lowArg,obsoletenames);
      if ~isempty(j_old)
         error(sprintf('The property name ''%s'' is obsolete. Sorry...', arg));
      end
      
      j = strmatch(lowArg,names);
      if isempty(j)                       % if no matches
         error(sprintf('Unrecognized property 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 property 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 property ''%s''.', arg));
end