function [B,p] = chol(A,uplo)
%MATLAB Code Generation Library Function

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

coder.columnMajor;
coder.inline('always');
eml_invariant(nargin >= 1, ...
    'MATLAB:minrhs');
eml_invariant(isa(A,'float'), ...
    'Coder:toolbox:unsupportedClass','chol',class(A));
if nargin == 2
    eml_invariant(eml_is_const(uplo) && ...
        coder.internal.isCharOrScalarString(uplo), ...
        'Coder:toolbox:chol_3', ...
        'IfNotConst','Fail');
    
    isupper = strcmpi(uplo,'upper');
    islower = strcmpi(uplo,'lower');

    eml_invariant(isupper || islower, ...
        'Coder:toolbox:chol_3', ...
        'IfNotConst','Fail');
    if isupper
        uplochar = 'U';
    else
        uplochar = 'L';
    end
else
    uplochar = 'U';
end
if nargout <= 1
    A = cholesky(A,uplochar);
    B = A; % This copy may be removed after inlining.
elseif ~(eml_is_const(size(A,1)) || eml_is_const(size(A,2)))
    % A is already variably-sized in both dimensions.
    [A,info] = cholesky(A,uplochar);
    B = A; % This copy may be removed after inlining.
    p = double(info);
else
    coder.varsize('B');
    B = A;
    [B,info] = cholesky(B,uplochar);
    p = double(info);
end

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

function [A,info] = cholesky(A,uplochar)
coder.internal.prefer_const(uplochar);
m = cast(size(A,1),coder.internal.indexIntClass);
n = cast(size(A,2),coder.internal.indexIntClass);
eml_invariant(ismatrix(A) && m == n, ...
    'Coder:MATLAB:square');
ZERO = zeros(coder.internal.indexIntClass);
ONE = ones(coder.internal.indexIntClass);
RZERO = zeros('like',real(A));
info = zeros('like',coder.internal.lapack.info_t);
if n == ZERO
    return
end
if nargout <= 1 && ~isreal(A)
    % Check for non-real diagonal entries.
    for j = 1:n
        if imag(A(j,j)) ~= RZERO
            info(1) = j;
            coder.internal.error('Coder:MATLAB:chol_matrixMustBePosDefWithRealDiag');
            return
        end
    end
end
% Perform the factorization.
[A,info] = coder.internal.lapack.xpotrf(uplochar,n,A,ONE,n);
if info == ZERO
    jmax = n;
else
    jmax = coder.internal.indexInt(info) - 1;
end
coder.internal.assert(nargout == 2 || info == ZERO,'Coder:MATLAB:posdef');

if uplochar == 'L'
    % Zero entries above the main diagonal.
    for j = 2:jmax
        for i = ONE:coder.internal.indexMinus(j,1)
            A(i,j) = RZERO;
        end
    end
else
    % Zero entries below the main diagonal.
    for j = 1:jmax
        for i = coder.internal.indexPlus(j,1):jmax
            A(i,j) = RZERO;
        end
    end
end
% Trim the output matrix.
if nargout == 2
    assert(jmax <= m && jmax <= n); %<HINT>
    A = A(1:jmax,1:jmax);
end

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