function [xf,fval,exitflag,output] = fminbnd(funfcnInput,ax,bx,options,varargin)
%MATLAB Code Generation Library Function

% Limitations:
%   1. A problem struct input is not supported for code generation.
%   2. The Display option in the options struct is not honored.  No status
%      information is printed during execution.  This includes when
%      terminating early. Check the third output argument instead.
%   3. The message and algorithm fields of the output struct are not
%      supported.
%   4. The OutputFcn and PlotFcns options are ignored for code generation.

%   Copyright 2013-2017 The MathWorks, Inc.
%#codegen

% Disallow problem struct input
eml_invariant(~isstruct(funfcnInput), ...
    'Coder:toolbox:OptimNoProblemStruct',upper(mfilename), ...
    'IfNotConst','Fail')
coder.internal.prefer_const(funfcnInput);

% Set default options
defaultopt = struct( ...
    'Display','notify', ...
    'FunValCheck','off', ...
    'MaxFunEvals',500, ...
    'MaxIter',500, ...
    'OutputFcn',[], ...
    'PlotFcns',[], ...
    'TolX',1e-4);

% If just 'defaults' passed in, return the default options in X
if nargin == 1 && nargout <= 1 && coder.internal.isCharOrScalarString(funfcnInput) && ...
        strcmp(funfcnInput,'defaults')
    xf = defaultopt;
    return
end
coder.internal.assert(nargin >= 3,'MATLAB:optimfun:fminbnd:NotEnoughInputs');

% initialization
if nargin < 4
    options = [];
else
    coder.internal.prefer_const(options);
end
% Check for non-double inputs
coder.internal.assert(isa(ax,'double') && isa(bx,'double'), ...
    'MATLAB:optimfun:fminbnd:NonDoubleInput');
tol = optimget(options,'TolX',defaultopt,'fast');
funValCheck = strcmp(optimget(options,'FunValCheck',defaultopt,'fast'),'on');
maxfun = optimget(options,'MaxFunEvals',defaultopt,'fast');
maxiter = optimget(options,'MaxIter',defaultopt,'fast');
% Check that MaxFunEvals and MaxIter are scalar double values;
% Their default values for some solvers are strings
coder.internal.assert(isnumeric(maxfun),'MATLAB:optimfun:fminbnd:CharMaxFunEvals');
coder.internal.assert(isnumeric(maxiter),'MATLAB:optimfun:fminbnd:CharMaxIter');
funccount = coder.internal.indexInt(0);
iter = coder.internal.indexInt(0);

% Assume we'll converge
exitflag = 1;

% Convert to function handle as needed.
if coder.internal.isCharOrScalarString(funfcnInput)
    funfcn = str2func(funfcnInput);
    funstr = funfcnInput;
else
    funfcn = funfcnInput;
    % We can't use func2str, but we need to fill the hole with something if
    % FunValCheck is on and funfcn returns a NaN.
    funstr = ' ';
end

% checkbounds
if ax > bx
    exitflag = -2;
    % Matlab returns xf = [] and fval = [].
    xf=coder.internal.nan; fval = coder.internal.nan('like',funfcn(xf));
    output.iterations = 0;
    output.funcCount = 0;
    return
end

% Compute the start point
seps = sqrt(eps);
c = 0.5*(3.0 - sqrt(5.0));
a = ax; b = bx;
v = a + c*(b-a);
w = v; xf = v;
d = 0.0; e = 0.0;
x = xf; fx = funfcn(x,varargin{:});
% For code generation, we always need to check that fx is real because
% otherwise the error will be "Cannot assign a complex value to a
% non-complex location." However, we only need to do it once.
coder.internal.assert(isreal(fx), ...
    'MATLAB:optimfun:fminbnd:checkfun:ComplexFval',funstr, ...
    coder.internal.flt2str(x));
checkfun(funValCheck,x,fx,funstr);
funccount = funccount + 1;

% Check that the objective value is a scalar
coder.internal.assert(isscalar(fx),'MATLAB:optimfun:fminbnd:NonScalarObj');

fv = fx; fw = fx;
xm = 0.5*(a+b);
tol1 = seps*abs(xf) + tol/3.0;
tol2 = 2.0*tol1;

% Main loop
while ( abs(xf-xm) > (tol2 - 0.5*(b-a)) )
    gs = 1;
    % Is a parabolic fit possible
    if abs(e) > tol1
        % Yes, so fit parabola
        gs = 0;
        r = (xf-w)*(fx-fv);
        q = (xf-v)*(fx-fw);
        p = (xf-v)*q-(xf-w)*r;
        q = 2.0*(q-r);
        if q > 0.0, p = -p; end
        q = abs(q);
        r = e; e = d;
        
        % Is the parabola acceptable
        if ( (abs(p)<abs(0.5*q*r)) && (p>q*(a-xf)) && (p<q*(b-xf)) )
            
            % Yes, parabolic interpolation step
            d = p/q;
            x = xf+d;
            
            % f must not be evaluated too close to ax or bx
            if ((x-a) < tol2) || ((b-x) < tol2)
                si = sign(xm-xf) + ((xm-xf) == 0);
                d = tol1*si;
            end
        else
            % Not acceptable, must do a golden section step
            gs=1;
        end
    end
    if gs
        % A golden-section step is required
        if xf >= xm
            e = a-xf; 
        else
            e = b-xf; 
        end
        d = c*e;
    end
    
    % The function must not be evaluated too close to xf
    si = sign(d) + (d == 0);
    x = xf + si * eml_max( abs(d), tol1 );
    fu = funfcn(x,varargin{:});
    checkfun(funValCheck,x,fx,funstr);
    funccount = funccount + 1;
    
    iter = iter + 1;
    
    % Update a, b, v, w, x, xm, tol1, tol2
    if fu <= fx
        if x >= xf
            a = xf; 
        else
            b = xf; 
        end
        v = w; fv = fw;
        w = xf; fw = fx;
        xf = x; fx = fu;
    else % fu > fx
        if x < xf
            a = x; 
        else
            b = x; 
        end
        if ( (fu <= fw) || (w == xf) )
            v = w; fv = fw;
            w = x; fw = fu;
        elseif ( (fu <= fv) || (v == xf) || (v == w) )
            v = x; fv = fu;
        end
    end
    xm = 0.5*(a+b);
    tol1 = seps*abs(xf) + tol/3.0; tol2 = 2.0*tol1;
    
    if funccount >= maxfun || iter >= maxiter
        exitflag = 0;
        break
    end
end % while

fval = fx;
output.iterations = double(iter);
output.funcCount = double(funccount);

%--------------------------------------------------------------------------

function checkfun(docheck,x,fx,funstr)
% CHECKFUN checks for complex or NaN results from userfcn.
% Note: we do not check for Inf as FMINBND handles it naturally.
coder.inline('always');
coder.internal.prefer_const(docheck,funstr);
if docheck
    coder.internal.assert(~isnan(fx), ...
        'MATLAB:optimfun:fminbnd:checkfun:NaNFval',funstr, ...
        coder.internal.flt2str(x));
end

%--------------------------------------------------------------------------


