classdef (InferiorClasses = {?matlab.graphics.axis.Axes, ?matlab.ui.control.UIAxes}) LoguniformDistribution < prob.ParametricDistribution & ...
                                  prob.TruncatableDistribution
%LoguniformDistribution Loguniform probability distribution
%    An object of the LoguniformDistribution class represents a loguniform
%    probability distribution with lower limit "Lower" and upper limit 
%    "Upper". This distribution object can be created using the MAKEDIST 
%    function.
%
%    LoguniformDistribution methods:
%       cdf                   - Cumulative distribution function
%       icdf                  - Inverse cumulative distribution function
%       iqr                   - Interquartile range
%       mean                  - Mean
%       median                - Median
%       pdf                   - Probability density function
%       random                - Random number generation
%       std                   - Standard deviation
%       truncate              - Truncation distribution to an interval
%       var                   - Variance
%
%    LoguniformDistribution properties:    
%       Lower                 - Value of the Lower parameter (lower limit)
%       Upper                 - Value of the Upper parameter (upper limit)
%       DistributionName      - Name of the distribution
%       NumParameters         - Number of parameters
%       ParameterNames        - Names of parameters
%       ParameterDescription  - Descriptions of parameters
%       ParameterValues       - Vector of values of parameters
%       Truncation            - Two-element vector indicating truncation limits
%       IsTruncated           - Boolean flag indicating if distribution is truncated
%
%    See also makedist.

%   Copyright 2021-2022 The MathWorks, Inc.

    properties(Dependent)
%A Lower limit of log uniform distribution.
%    The Lower property represents the parameter of the distribution that is
%    the lower bound of the support. 
%
%    See also Upper.
        Lower

%B Location of peak of triangular distribution.
%    The Upper property represents the parameter of the distribution that is
%    the upper bound of the support. 
%
%    See also Lower.
        Upper
        
    end
    properties(GetAccess='public',Constant=true)
%DistributionName Distribution name.
%    The DistributionName property indicates the name of the probability
%    distribution.
%
%    See also ParameterNames, ParameterValues.
        DistributionName = getString(message('stats:probdists:DistributionLoguniform'));

%NumParameter Number of parameters.
%    NumParameters is the number of parameters in the distribution.
%
%    See also ParameterValues. 
        NumParameters = 2;

%ParameterNames Parameter names.
%    ParameterNames is a cell array of strings containing the names of the
%    parameters of the probability distribution.
%
%    See also ParameterValues, ParameterDescription.
        ParameterNames = {'Lower' 'Upper'};

%ParameterDescription Parameter description.
%    ParameterNames is a cell array of strings containing short
%    descriptions of the parameters of the probability distribution.
%
%    See also ParameterNames, ParameterValues.
        ParameterDescription = {getString(message('stats:probdists:ParameterDescriptionLower')) ...
                                getString(message('stats:probdists:ParameterDescriptionUpper'))};
    end
    properties(GetAccess='public',SetAccess='protected')
        ParameterValues = [1 4];       % need to store these as a group to do error checking
    end
    
    methods(Hidden)
        function pd = LoguniformDistribution(Lower,Upper)
 %LOGUNIFORMDISTRIBUTION Create a LOGUNIFORMDISTRIBUTION object.
 %   PD = LOGUNIFORMDISTRIBUTION(Lower,Upper) creates a LOGUNIFORMDISTRIBUTION 
 %   object with support on [Lower,Upper], where 0<Lower<Upper.

            if nargin==0
                Lower = 1;
                Upper = 4;
            end
            checkParams(Lower,Upper);
            pd.ParameterValues = [Lower Upper];
        end
    end
    methods
        function m = mean(this)
            requireScalar(this)
            if this.IsTruncated
                m = truncatedMoment(this,1);
                return
            end
            Lower = this.Lower;
            Upper = this.Upper;
            
            n = Upper-Lower;
            d = log(Upper/Lower);
            m = n/d;
        end
        function v = var(this)
            requireScalar(this)
            if this.IsTruncated
                v = truncatedMoment(this,2);
                return
            end
            Lower = this.Lower;
            Upper = this.Upper;
           
            q = log(Upper) - log(Lower);
            v = (Upper-Lower)*(Upper*(q-2) + Lower*(q+2)) / (2*(q^2));
        end
        function this = set.Lower(this,Lower)
            checkParams(Lower,this.Upper);
            this.ParameterValues(1) = Lower;
        end
        function this = set.Upper(this,Upper)            
            checkParams(this.Lower,Upper);
            this.ParameterValues(2) = Upper;
        end
   
        function Lower = get.Lower(this)
            Lower = this.ParameterValues(1);
        end
        function Upper = get.Upper(this)
            Upper = this.ParameterValues(2);
        end
    end
    methods(Access=protected)
        function y = pdffun(this,x)
            requireScalar(this);
            Lower = this.Lower;
            Upper = this.Upper;
            
            y = 1./(x.*log(Upper/Lower));
            y(x<Lower | x>Upper) = 0;
        end
        function y = cdffun(this,x)
            requireScalar(this);            
            Lower = this.Lower;
            Upper = this.Upper;

            n = log(x) - log(Lower);
            d = log(Upper) - log(Lower);            
            y = n/d;
            y(x<Lower) = 0;
            y(x>Upper) = 1;
        end
        function y = icdffun(this,p)
            requireScalar(this);
            Lower = this.Lower;
            Upper = this.Upper;
            
            y = p;
            y(p<0 | p>1 | isnan(p)) = NaN;
            t = (p>=0 & p<=1);
            y(t) = (Upper.^p(t)) ./ (Lower.^(p(t)-1));
        end
        
        function y = randomfun(this,varargin)
            requireScalar(this);
            y = icdf(this,rand(varargin{:}));
        end
    end
    methods(Access=protected)
        function displayCallback(this)
            fprintf('  %s\n',getString(message('stats:probdists:DisplayDistribution',this.DistributionName)));
            if ~isempty(this)
                nms = this.ParameterNames;
                n = length(nms);
                nameWidth = max(cellfun('length',nms));

                vals = cell(n,1);
                isFitted = isa(this,'prob.FittableDistribution') && ~all(this.ParameterIsFixed);
                if isFitted
                    try
                        ci = paramci(this);
                    catch me
                        ci = [];
                    end
                end
                for j=1:n
                    vals{j} = sprintf('%g',this.ParameterValues(j));
                end
                valWidth = max(cellfun('length',vals));
                
                for j=1:n
                    if ~isFitted || this.ParameterIsFixed(j) || isempty(ci) || any(isnan(ci(:,j)))
                        fprintf('    %*s = %*s\n',nameWidth,nms{j},valWidth,vals{j});
                    else
                        conf = sprintf('[%g, %g]',ci(:,j));
                        fprintf('    %*s = %*s   %s\n',nameWidth,nms{j},valWidth,vals{j},conf);
                    end
                end
            end
        end
    end

end % classdef

function checkParams(Lower,Upper)
if ~(isscalar(Lower) && isnumeric(Lower) && isreal(Lower) && isfinite(Lower))
    error(message('stats:probdists:ScalarParameter','Lower'))
end
if ~(isscalar(Upper) && isnumeric(Upper) && isreal(Upper) && isfinite(Upper))
    error(message('stats:probdists:ScalarParameter','Upper'))
end
if ~(Lower>0 && Lower<Upper)
    error(message('stats:probdists:LowerltUpper'));
end
end


