function [eff_solver,dosc,dotensor,maxiter,alpha0,beta0,...
    dofitalpha0,dofitalphas,usemex,batchsize,decay,freqval] = ...
    checkInputs(fun,X,Xval,K,solver,usemex,maxiter,maxpass,maxbatch,...
    alpha0,beta0,dofitalpha0,dofitalphas,batchsize,decay,freqval)
% Check validity of input parameters and return validated parameter values

% Inputs:
%   fun         - Name of the calling function or method, char vector
%   X           - Training data, W-by-N sparse double matrix for W words
%                 and N documents
%   Xval        - Validation data, W-by-Nval sparse double matrix for W
%                 words and Nval documents
%   K           - Number of topics, double scalar
%   solver      - Solver name, char vector. If [], 'cgs' is assumed.
%                 Allowed values: 'cgs', 'cvb0' and 'avb' for batch
%                 solvers; 'savb' for stochastic solver.
%   usemex      - Use mex, true or false. If [], true is assumed.
%   maxiter     - max number of iterations, double scalar. If [], default is assumed.
%   maxpass     - max number of passes through the data. If [], 1 is assumed.
%   maxbatch    - max number of mini-batches to process. If [],
%                   ceil(maxpass*N/batchsize) is assumed, that is, one pass
%                   through the data
%   alpha0      - Topic concentration, double scalar. If [], K/4 is assumed.
%   beta0       - Word concentration, double scalar. If [], 1 is assumed.
%   dofitalpha0 - Fit topic concentration, true or false. 
%                 If [], false is assumed for 'tensor' and true for all
%                 other solvers.
%   dofitalphas - Fit topic probabilities, true or false. If [], true is assumed.
%   batchsize   - Batch size. If [], 1000 is assumed. Only needed for
%                 stochastic solvers.
%   decay       - Exponent in (1+t)^(-decay) specifying how the learning
%                 rate depends on batch index t. If [], 0.5 is assumed.
%                 Relevant for stochastic solver only.
%   freqval     - Frequency of print-outs for validation data. If [], 1 is
%                 assumed for the batch solver and 10 for the stochastic
%                 solver. If Xval is not passed, this parameter has no
%                 effect.
%
% Outputs:
%   eff_solver  - Solver name, one of: cgs', 'cvb0', and 'avb'
%   dosc        - Use stochastic learning, true or false
%   dotensor    - Use tensor decomposition, true or false (Always false for
%                 now, inarsky, March 2017)
%   maxiter     - max number of iterations, double scalar.
%   alpha0      - Topic concentration, double scalar.
%   beta0       - Word concentration, double scalar.
%   dofitalpha0 - Fit topic concentration, true or false. 
%   dofitalphas - Fit topic probabilities, true or false.
%   usemex      - Use mex, true or false.
%   batchsize   - Batch size. Used only for stochastic solver.
%   decay       - Exponent in (1+t)^(-decay) specifying how the learning
%                 rate depends on batch index t. Used only for stochastic
%                 solver.
%   freqval     - Frequency of print-outs for validation data.

%   Copyright 2017-2022 The MathWorks, Inc.

if ~isscalar(K) || ~isreal(K) || round(K)~=K || K<=0
    error(message('stats:clustering:ldautils:checkInputs:BadNumberOfTopics'));
end
K = double(K);

[W,N] = size(X);

if K > N
    error(message('stats:clustering:ldautils:checkInputs:TooManyTopics'));
end

allowed_solvers = {'avb' 'cvb0' 'cgs' 'savb'};
solver = validatestring(solver,allowed_solvers,fun,'Solver');

dosc = ismember(solver,{'savb'});
if dosc
    eff_solver = solver(2:end);
else
    eff_solver = solver;
end

dotensor = strcmp(solver,'tensor');

if ~isempty(Xval) && size(Xval,1)~=W
    error(message('stats:clustering:ldautils:checkInputs:BadNumWordsValidationData',W));
end

if isempty(freqval)
    freqval = max(1,10*dosc);
else
    if ~isnumeric(freqval) || ~isscalar(freqval) || ~isreal(freqval) || freqval<1 ...
            || round(freqval)~=freqval
        error(message('stats:clustering:ldautils:checkInputs:BadValidationFrequency'));
    end
end

if isempty(usemex)
    usemex = ~dotensor;
end

if strcmp(solver,'cgs') && ~usemex
    warning(message('stats:clustering:ldautils:checkInputs:CppForCGS'));
end

if dosc && ~usemex
    warning(message('stats:clustering:ldautils:checkInputs:CppForStochastic'));
end

% Commented out since dotensor is always false and localization is not needed
% if dotensor && usemex
%     warning('MEX will not be used for tensor learning.');
% end

if isempty(maxiter)
    maxiter = 100; % overridden if dosc==true
else
    if dosc
        error(message('stats:clustering:ldautils:checkInputs:NoIterationLimitForStochastic'));
    end
    
    if ~isnumeric(maxiter) || ~isscalar(maxiter) || ~isreal(maxiter) || maxiter<1 ...
            || round(maxiter)~=maxiter
        error(message('stats:clustering:ldautils:checkInputs:BadIterationLimit'));
    end
end
maxiter = double(maxiter);

if dosc
    if isempty(batchsize)
        batchsize = min(1000,N);
    else
        if ~isnumeric(batchsize) || ~isscalar(batchsize) || ~isreal(batchsize) || batchsize<1 ...
                || round(batchsize)~=batchsize
            error(message('stats:clustering:ldautils:checkInputs:BadBatchSize'));
        end
        batchsize = min(double(batchsize),N);
    end
    
    user_set_maxpass = false;
    if isempty(maxpass)
        maxpass = 1;
    else
        if ~isnumeric(maxpass) || ~isscalar(maxpass) || ~isreal(maxpass) || maxpass<1 ...
                || round(maxpass)~=maxpass
            error(message('stats:clustering:ldautils:checkInputs:BadPassLimit'));
        end
        maxpass = double(maxpass);
        user_set_maxpass = true;
    end
    
    user_set_maxbatch = false;
    if isempty(maxbatch)
        maxbatch = ceil(maxpass*N/batchsize);
    else
        if ~isnumeric(maxbatch) || ~isscalar(maxbatch) || ~isreal(maxbatch) || maxbatch<1 ...
                || round(maxbatch)~=maxbatch
            error(message('stats:clustering:ldautils:checkInputs:BadBatchLimit'));
        end
        maxbatch = double(maxbatch);
        user_set_maxbatch = true;
    end    

    % From now on, use maxiter for all solvers
    if user_set_maxpass && user_set_maxbatch
        maxiter = min(maxbatch,ceil(maxpass*N/batchsize));
    else
        maxiter = maxbatch;
    end
    
    if isempty(decay)
        decay = 0.5;
    else
        if ~isnumeric(decay) || ~isscalar(decay) || ~isreal(decay) || decay<=0 || decay>1
            error(message('stats:clustering:ldautils:checkInputs:BadDecay'));
        end
        decay = double(decay);
    end
    
else
    if ~isempty(maxpass)
        error(message('stats:clustering:ldautils:checkInputs:NoPassLimitForNonStochastic'));
    end
    
    if ~isempty(maxbatch)
        error(message('stats:clustering:ldautils:checkInputs:NoBatchLimitForNonStochastic'));
    end
    
    if ~isempty(batchsize)
        error(message('stats:clustering:ldautils:checkInputs:NoBatchSizeForNonStochastic'));
    end
    
    if ~isempty(decay)
        error(message('stats:clustering:ldautils:checkInputs:NoDecayForNonStochastic'));
    end
end

if ~isempty(alpha0) && (~isscalar(alpha0) || ~isreal(alpha0) ...
        || ~isfloat(alpha0) || alpha0<=0)
    error(message('stats:clustering:ldautils:checkInputs:BadTopicConcentration'));
end
alpha0 = double(alpha0);

if ~isempty(beta0) && (~isscalar(beta0) || ~isreal(beta0) ...
        || ~isfloat(beta0) || beta0<=0)
    error(message('stats:clustering:ldautils:checkInputs:BadWordConcentration'));
end
beta0 = double(beta0);

if ~isempty(dofitalpha0) && ( ~isscalar(dofitalpha0) ...
        || ~(islogical(dofitalpha0) || dofitalpha0==0 || dofitalpha0==1) )
    error(message('stats:clustering:ldautils:checkInputs:BadFitTopicConcentration'));
end

if ~isempty(dofitalphas) && ( ~isscalar(dofitalphas) ...
        || ~(islogical(dofitalphas) || dofitalphas==0 || dofitalphas==1) )
    error(message('stats:clustering:ldautils:checkInputs:BadFitTopicProbabilities'));
end

if     dotensor
% Commenting out since tensor decomposition is not supported for now.    
%     if ~isempty(dofitalpha0) && dofitalpha0
%         error('Topic concentration cannot be fit by tensor.');
%     end
%     dofitalpha0 = false;
%     
%     if ~isempty(dofitalphas) && ~dofitalphas
%         error('Topic probabilities are always fit by tensor.');
%     end
%     dofitalphas = true;
elseif dosc
    if isempty(dofitalpha0)
        dofitalpha0 = false;
    end
else
    if isempty(dofitalpha0)
        dofitalpha0 = true;
    end
end

if isempty(dofitalphas)
    dofitalphas = true;
end

if dofitalpha0 && ~dofitalphas
    error(message('stats:clustering:ldautils:checkInputs:UnableToFitAlpha0WithoutFittingAlphas'));
end

if isempty(alpha0)
    alpha0 = K/4;
end

if isempty(beta0)
    beta0 = 1;
end

% Commented out since dotensor is always false and localization is not needed.
% if dotensor
%     if any(sum(X,1) < 3)
%         error('Each document must have at least 3 terms for tensor decomposition.');
%     end
% end

end

% LocalWords:  Xval Nval savb maxpass maxbatch dofitalpha dofitalphas freqval dosc dotensor
