function [x, f, binf, bsup] = marginal_pdf(o, indx, npoints, truncprior)

% Evaluate the marginal prior PDF of a single parameter on a grid.
%
% INPUTS
% - o           [dprior]   Prior object.
% - indx        [integer]  Parameter index.
% - npoints     [integer]  Number of grid points (default: 200).
% - truncprior  [double]   Tail probability to exclude (default: 1e-3).
%
% OUTPUTS
% - x           [double]   1×npoints row vector, abscissa values.
% - f           [double]   1×npoints row vector, density values.
% - binf        [double]   Scalar, lower plot bound.
% - bsup        [double]   Scalar, upper plot bound.

% Copyright © 2026 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare.  If not, see <https://www.gnu.org/licenses/>.

if nargin < 4 || isempty(truncprior)
    truncprior = 1e-3;
end
if nargin < 3 || isempty(npoints)
    npoints = 200;
end

is_uniform = false;

if ismember(indx, o.idbeta)
    density = @(x) betapdf((x-o.p3(indx))/(o.p4(indx)-o.p3(indx)), o.p6(indx), o.p7(indx))/(o.p4(indx)-o.p3(indx));
    binf = betainv(truncprior, o.p6(indx), o.p7(indx))*(o.p4(indx)-o.p3(indx)) + o.p3(indx);
    bsup = betainv(1-truncprior, o.p6(indx), o.p7(indx))*(o.p4(indx)-o.p3(indx)) + o.p3(indx);
elseif ismember(indx, o.idgamma)
    density = @(x) gampdf(x-o.p3(indx), o.p6(indx), o.p7(indx));
    binf = gaminv(truncprior, o.p6(indx), o.p7(indx)) + o.p3(indx);
    bsup = gaminv(1-truncprior, o.p6(indx), o.p7(indx)) + o.p3(indx);
elseif ismember(indx, o.idgaussian)
    density = @(x) normpdf(x, o.p6(indx), o.p7(indx));
    binf = max(o.p3(indx), norminv(truncprior, o.p6(indx), o.p7(indx)));
    bsup = min(o.p4(indx), norminv(1-truncprior, o.p6(indx), o.p7(indx)));
elseif ismember(indx, o.idinvgamma1)
    density = @(x) exp(lpdfig1(x-o.p3(indx), o.p6(indx), o.p7(indx)));
    binf = 1/sqrt(gaminv(1-10*truncprior, o.p7(indx)/2, 2/o.p6(indx))) + o.p3(indx);
    bsup = 1/sqrt(gaminv(10*truncprior, o.p7(indx)/2, 2/o.p6(indx))) + o.p3(indx);
elseif ismember(indx, o.iduniform)
    is_uniform = true;
    binf = o.p6(indx);
    bsup = o.p7(indx);
elseif ismember(indx, o.idinvgamma2)
    density = @(x) exp(lpdfig2(x-o.p3(indx), o.p6(indx), o.p7(indx)));
    binf = 1/(gaminv(1-10*truncprior, o.p7(indx)/2, 2/o.p6(indx))) + o.p3(indx);
    bsup = 1/(gaminv(10*truncprior, o.p7(indx)/2, 2/o.p6(indx))) + o.p3(indx);
elseif ismember(indx, o.idweibull)
    density = @(x) exp(lpdfgweibull(x, o.p6(indx), o.p7(indx), o.p3(indx)));
    binf = o.p3(indx) + wblinv(truncprior, o.p7(indx), o.p6(indx));
    bsup = o.p3(indx) + wblinv(1-truncprior, o.p7(indx), o.p6(indx));
else
    error('dprior::marginal_pdf: parameter index %d does not belong to any known distribution.', indx)
end

x = linspace(binf, bsup, npoints);

if is_uniform
    f = ones(1, npoints) / (bsup - binf);
else
    f = density(x);
    [~, k1] = max(f);
    if k1 == 1 || k1 == npoints
        f(f > 10) = NaN;
    end
end

return % --*-- Unit tests --*--

%@test:1
% Test that marginal_pdf returns vectors of the right size and finite
% values on a 7-parameter prior built incrementally with add().
Prior = dprior();
Prior.add('p_beta',      'shape', 'beta',       'mean', 0.4, 'std', 0.2, 'prior_trunc', 1e-10);
Prior.add('p_gamma',     'shape', 'gamma',      'mean', 0.4, 'std', 0.2, 'prior_trunc', 1e-10);
Prior.add('p_normal',    'shape', 'normal',     'mean', 0.0, 'std', 1.0, 'prior_trunc', 1e-10);
Prior.add('p_invgamma1', 'shape', 'inv_gamma',  'mean', 0.4, 'std', 0.2, 'prior_trunc', 1e-10);
Prior.add('p_uniform',   'shape', 'uniform',    'lower_bound', 0, 'upper_bound', 1, 'prior_trunc', 1e-10);
Prior.add('p_invgamma2', 'shape', 'inv_gamma2', 'mean', 0.4, 'std', 0.2, 'prior_trunc', 1e-10);
Prior.add('p_weibull',   'shape', 'weibull',    'mean', 0.4, 'std', 0.2, 'prior_trunc', 1e-10);
t(1) = true;
try
    for j = 1:7
        [x, f, binf, bsup] = marginal_pdf(Prior, j);
        t(end+1) = length(x)==200;
        t(end+1) = length(f)==200;
        t(end+1) = binf < bsup;
        t(end+1) = all(isfinite(x));
    end
catch
    t(1) = false;
end
T = all(t);
%@eof:1
