function [fval,info,exit_flag,DLIK,Hess,model_solution,smoother_results,regime_history] = IVF_posterior(xparam1,...
    dataset_,dataset_info,options_,M_,estim_params_,Prior,BoundsInfo,dr, endo_steady_state, exo_steady_state, exo_det_steady_state, ~, ~)
% Computes Likelihood with inversion filter
%
% INPUTS
% - xparam1             [double]        current values for the estimated parameters.
% - dataset_            [structure]     dataset after transformations
% - dataset_info        [structure]     storing information about the
%                                       sample; not used but required for interface
% - options_            [structure]     MATLAB's structure describing the current options
% - M_                  [structure]     MATLAB's structure describing the model
% - estim_params_       [structure]     characterizing parameters to be estimated
% - Prior               [@dprior]       prior information object
% - BoundsInfo          [structure]     containing prior bounds
% - dr                  [structure]     Reduced form model.
% - endo_steady_state   [vector]        steady state value for endogenous variables
% - exo_steady_state    [vector]        steady state value for exogenous variables
% - exo_det_steady_state [vector]       steady state value for exogenous deterministic variables
%
% OUTPUTS
% - fval                    [double]        scalar, value of the likelihood or posterior kernel.
% - info                    [integer]       4×1 vector, information resolution of the model and evaluation of the likelihood.
% - exit_flag               [integer]       scalar, equal to 1 (no issues when evaluating the likelihood) or 0 (not able to evaluate the likelihood).
% - DLIK                    [double]        Empty array.
% - Hess                    [double]        Empty array.
% - model_solution          [struct]        Structure containing the model solution at the current parameter
%                                           values with fields: dr, ys, trend_coeff, and the M_ fields
%                                           set by set_all_parameters (params, Sigma_e, Correlation_matrix,
%                                           H, Correlation_matrix_ME, Skew_e, endo_initial_state_values, csn).
% - smoother_results        [struct]        Struct with same layout as DsgeSmoother output.
% - regime_history          [struct]        Regime history from IVF.

% Copyright © 2021-2025 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/>.


DLIK=[];
Hess=[];
trend_coeff = [];
obs = dataset_.data;
obs_list = options_.varobs(:);
exit_flag   = 1;
% initialize output arguments in case of early return
model_solution = [];
smoother_results = [];
regime_history = [];


if size(xparam1,1)<size(xparam1,2)
    xparam1=xparam1';
end


%------------------------------------------------------------------------------
% 1. Get the structural parameters & define penalties
%------------------------------------------------------------------------------

if ~isempty(xparam1)
    M_ = set_all_parameters(xparam1,estim_params_,M_);
    [fval,info,exit_flag]=check_bounds_and_definiteness_estimation(xparam1, M_, estim_params_, BoundsInfo);
    if info(1)
        return
    end
end

err_index=options_.occbin.likelihood.IVF_shock_observable_mapping; % err_index= find(diag(M_.Sigma_e)~=0);
COVMAT1 = M_.Sigma_e(err_index,err_index);

% Linearize the model around the deterministic steady state and extract the matrices of the state equation (T and R).
[~,~,SteadyState,info,dr, M_.params] = dynare_resolve(M_,options_,dr, endo_steady_state, exo_steady_state, exo_det_steady_state,'restrict');

% Return, with endogenous penalty when possible, if dynare_resolve issues an error code (defined in resol).
if info(1)
    if info(1) == 3 || info(1) == 4 || info(1) == 5 || info(1)==6 ||info(1) == 19 ||...
                info(1) == 20 || info(1) == 21 || info(1) == 23 || info(1) == 26 || ...
                info(1) == 81 || info(1) == 84 ||  info(1) == 85 ||  info(1) == 86
        %meaningful second entry of output that can be used
        fval = Inf;
        if ~isfinite(info(2))
            info(4) = 0.1;
        else
            info(4) = info(2);
        end
        exit_flag = 0;
        return
    else
        fval = Inf;
        info(4) = 0.1;
        exit_flag = 0;
        return
    end
end

%---------------------------------------------
% Calculate likelihood
%---------------------------------------------
sample_length = size(obs,1);
filtered_errs_init = zeros(sample_length,sum(err_index));

[filtered_errs, resids, Emat, stateval, info, regime_history] = occbin.IVF_core(M_,dr,endo_steady_state,exo_steady_state,exo_det_steady_state,options_,err_index,filtered_errs_init,obs_list,obs);
n_obs = length(options_.varobs_id);
if info(1)
    fval = Inf;
    exit_flag = 0;
    smoother_results = build_smoother_results_struct( ...
        NaN(size(stateval(:,dr.order_var)')),...  % atT
        NaN(M_.exo_nbr,sample_length),...  % innov
        [],...  % measurement_error
        NaN(size(stateval(:,dr.order_var)')),...  % updated_variables
        SteadyState,...
        zeros(n_obs,1),...  % trend_coeff
        [], [], [], [],...  % aK, P, PK, decomp
        zeros(n_obs,sample_length));  % Trend
    return
else
    atT = stateval(:,dr.order_var)';
    innov = zeros(M_.exo_nbr,sample_length);
    innov(diag(M_.Sigma_e)~=0,:)=filtered_errs';
    smoother_results = build_smoother_results_struct( ...
        atT,...  % alphahat
        innov,...  % etahat
        [],...  % epsilonhat (no measurement error in IVF)
        atT*nan,...  % updated_variables
        SteadyState,...
        zeros(n_obs,1),...  % trend_coeff
        [], [], [], [],...  % aK, P, PK, decomp
        zeros(n_obs,sample_length));  % Trend
end
nobs=size(filtered_errs,1);


%-------------------------------------
% Calculate the selection matrix
%-------------------------------------

iobs=options_.varobs_id';

likei=NaN(nobs,1);
if ~any(any(isnan(obs)))
    log_det_COV=log(det(COVMAT1));
    for t = 1:nobs
        Gmat1  = Emat(iobs,:,t);
        log_det_jacobian = log_det_COV + 2*log(abs(det(Gmat1)));
        trace_term = filtered_errs(t,:)/(COVMAT1)*filtered_errs(t,:)';

        likei(t,1) = log_det_jacobian + trace_term;
    end
    likei=likei+length(iobs)*log(2*pi);
else
    for t = 1:nobs
        inan=~isnan(obs(t,:));
        Gmat1  = Emat(iobs(inan),inan,t);
        log_det_jacobian = log(det(COVMAT1(inan,inan))) + 2*log(abs(det(Gmat1)));
        trace_term = filtered_errs(t,inan)/(COVMAT1(inan,inan))*filtered_errs(t,inan)';

        likei(t,1) = log_det_jacobian + trace_term + length(iobs(inan))*log(2*pi);
    end
end

like = 0.5*sum(likei(options_.presample+1:end));

if isinf(like)
    fval = Inf; info(1) = 301; info(4) = 1000; exit_flag = 0;
    return
elseif isnan(like)
    fval = Inf; info(1) = 302; info(4) = 1000; exit_flag = 0;
    return
elseif imag(like)~=0
    fval = Inf; info(1) = 300; info(4) = 1000; exit_flag = 0;
    return
end

maxresid = max(abs(resids(:)));
if maxresid>1e-3
    disp_verbose('Penalize failure of residuals to be zero',options_.verbosity)
    fval = Inf; info(1) = 303; info(4) = sum(resids(:).^2); exit_flag = 0;
    return
end

if ~isempty(xparam1)
    prior = -Prior.density(xparam1);
else
    prior = 0;
end
if isinf(prior)
    % If parameters outside prior bound, minus prior density is very large
    fval = Inf; info(1) = 40; info(4) = 1000; exit_flag = 0;
    return
end
if isnan(prior)
    fval = Inf; info(1) = 47; info(4) = 1000; exit_flag = 0;
    return
end
if imag(prior)~=0
    fval = Inf; info(1) = 48; info(4) = 1000; exit_flag = 0;
    return
end

%---------------------------------------------
% Calculate posterior
%---------------------------------------------

% remember that the likelihood has already been multiplied by -1
% hence, posterior is -1 times the log of the prior
fval = like+prior;

if nargout >= 6
    model_solution.dr = dr;
    model_solution.ys = SteadyState;
    model_solution.trend_coeff = trend_coeff;
    model_solution.params = M_.params;
    model_solution.Sigma_e = M_.Sigma_e;
    model_solution.Correlation_matrix = M_.Correlation_matrix;
    model_solution.H = M_.H;
    model_solution.Correlation_matrix_ME = M_.Correlation_matrix_ME;
    model_solution.Skew_e = M_.Skew_e;
    if isfield(M_,'endo_initial_state')
        model_solution.endo_initial_state_values = M_.endo_initial_state.values;
    end
    if isfield(M_,'csn')
        model_solution.csn = M_.csn;
    end
end


function smoother_results = build_smoother_results_struct(atT, innov, measurement_error, ...
    updated_variables, ys, trend_coeff, aK, P, PK, decomp, Trend, ...
    state_uncertainty, a0T, state_uncertainty0, Ptt, V_eta)
% BUILD_SMOOTHER_RESULTS_STRUCT  Build the smoother_results struct expected by
%   store_smoother_results from legacy positional arguments.
%
%   smoother_results = build_smoother_results_struct(atT, innov, measurement_error,
%       updated_variables, ys, trend_coeff)
%   smoother_results = build_smoother_results_struct(atT, innov, measurement_error,
%       updated_variables, ys, trend_coeff, aK, P, PK, decomp, Trend,
%       state_uncertainty, a0T, state_uncertainty0, Ptt, V_eta)

% Copyright © 2025-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 < 7,  aK = []; end
if nargin < 8,  P = []; end
if nargin < 9,  PK = []; end
if nargin < 10, decomp = []; end
if nargin < 11, Trend = []; end
if nargin < 12, state_uncertainty = []; end
if nargin < 13, a0T = []; end
if nargin < 14, state_uncertainty0 = []; end
if nargin < 15, Ptt = []; end
if nargin < 16, V_eta = []; end

smoother_results.smoothed.alphahat    = atT;
smoother_results.smoothed.etahat      = innov;
smoother_results.smoothed.epsilonhat  = measurement_error;
smoother_results.smoothed.alphahat0   = a0T;
smoother_results.smoothed.V_tgT       = state_uncertainty;
smoother_results.smoothed.V_0gT       = state_uncertainty0;
smoother_results.smoothed.V_eta       = V_eta;
smoother_results.filtered.ahat        = updated_variables;
smoother_results.filtered.P           = P;
smoother_results.filtered.Ptt         = Ptt;
smoother_results.filtered.aK          = aK;
smoother_results.filtered.PK          = PK;
smoother_results.filtered.decomp      = decomp;
smoother_results.model.SteadyState    = ys;
smoother_results.model.trend_coeff    = trend_coeff;
smoother_results.model.trend_addition = Trend;