function [x fval exitflag output jacobian] = nonSmoothSolve(arg1, x0, options, varargin)
% usage:
% [x fval exitflag output jacobian] = nonSmoothSolve(fun, x0, options)
% or better OpenOpt-style:
% prob = ooAssign(...);
% r = nonSmoothSolve(prob);
% x = r.xf;
% fval = r.ff;
% see nonSmoothSolveEx.m in OpenOpt/Examples
% see also r.isFeasible and other output structure fields
% WARNING! curent version of MATLAB fsolve uses very strange stop
% criterium TolFun, something like:
% Optimization terminated: norm of relative change in X is less
% than max(options.TolX^2,eps) and sum-of-squares of function
% values is less than sqrt(options.TolFun)
%
% OpenOpt nonSmoothSolve uses norm(F, inf)<=TolFun (norm(F, inf)=max(abs(F)))
% so you should handle TolFun carefully (now default is 1e-6 for both nonSmoothSolve & fsolve)
% if nonSmoothSolve search failed, try increasing TolFun, diffInt(up to 1e-4...1e-2), MaxIter, MaxFunEvals
if ~isstruct(arg1); matlabLikeCall = 1; else matlabLikeCall = 0; end
if matlabLikeCall
objFun = arg1;
prob = ooAssign(@(x) 0, x0);
prob.df = @(x) zeros(size(x));
prob.h = objFun;
prob.primal.h = prob.primal.f;
prob.primal.dh = prob.primal.df;
prob.TolFun = 1e-6;
prob.TolCon = 1e-6;
prob.diffInt = 1e-4;
prob.ralg.alp = 2.0;% todo: checkme!
if nargin<3 && exist('optimset', 'file')
try
options = optimset(@fsolve);
catch
options = [];
end
end
prob = parseMATLABOptimToolboxOptions(options, prob);
if isempty(prob.MaxTime); prob.MaxTime=inf; end
else
prob = arg1;
prob.assert(nargin==1, 'incorrect input');
prob.h = @oo_h;
% prob.TolFun = max(prob.TolFun, 1e-3);
%todo: handle it in other way (in nonSmoothAssign)!!!!
if iscell(prob.h)
if length(prob.h)>1
prob.warn('cell func in nonSmoothSolve: can''t handle this case properly yet')
else
prob.h = prob.h{1};
end
end
prob.f = @(varargin) 0;
prob.dh = prob.primal.df;
prob.df = @(x, varargin) zeros(size(x));
prob.hPattern = prob.fPattern;
prob.fPattern = [];
prob.primal.h = prob.primal.f;
prob.primal.dh = prob.primal.df;
end
if iscell(prob.primal.h)
if length(prob.primal.h)>1
prob.warn('cell func in nonSmoothSolve: can''t handle this case properly yet')
else
prob.primal.h = prob.primal.h{1};
end
end
solver = @ralg;
ExtractRoutineParamsFromProb;
prob.parallel.h = prob.parallel.f;
prob.parallel.f = 0;
prob.primal.f = @(x) 0;
prob.primal.df = @(x) zeros(size(x));
prob.f0 = 0;
if matlabLikeCall
h0 = prob.h(prob.x0);
else
h0 = prob.h(prob.x0, prob);
end
prob.nh = length(h0);
% prob.h0 = h0;
if ~isvector(h0)
ooPwarn('it is highly recomended using vector-output function, not matrix');
end
prob.osolve.iterfcn = prob.iterfcn;
prob.iterfcn = @ooSolveIterFcn;
% prob.MaxIter = 1500;
% prob.TolFun = length(h0) * prob.TolCon;
prob.TolFunSolve = prob.TolFun;
prob.TolFun = 1e-15;
prob.TolCon = 1e-15;
prob.TolX = 1e-15;
%todo: what if other than h() constraints are present in nonsmoothsolve
prob.advanced.dispBestVal = 0;
if matlabLikeCall
r = ooRun(prob, solver);
else
if prob.diffInt==1e-7
prob.info('default val prob.diffInt is changed from 1e-7 to 1e-4');
prob.diffInt = 1e-4;
prob.MaxIter = 1e4;
end
r = solver(prob);
end
x = r.xf;
if matlabLikeCall
fval = prob.h(r.xf, varargin{:});
else
fval = prob.h(r.xf, prob);
end
r.ff = fval;
globstat.ff = r.ff;
% exitflag can be OTHER (than MATLAB fminsearch)!
% So using ominsearch is not recomended, use it only for comparing
exitflag = stopcase(r);
if exitflag < 1
prob.info('nonSmoothSolve search failed, try increasing TolFun, diffInt, MaxIter, MaxFunEvals')
end
output.algorithm = r.alg;
% global globstat
if matlabLikeCall
output.funcCount = r.nFunEvals;
output.iterations = r.nIter;
output.message = r.msg;
output.randInfo = r.randInfo;
else
x = r;
% output.funcCount = globstat.nFunEvals;
% output.iterations = globstat.nIter;
% output.message = msgstop(r);
% output.randInfo = ooRandInfo(prob);
end
%todo: fixme
%jacobian = 'currently unavailable';
jacobian = r.df;