2023-01-02 16:57:08 +01:00
function [s,nu] = inverse_gamma_specification ( mu, sigma2, lb, type, use_fzero_flag, name)
2015-12-08 17:51:54 +01:00
2021-10-27 10:13:04 +02:00
% Computes the inverse Gamma hyperparameters from the prior mean and variance.
2015-12-08 17:51:54 +01:00
%
2017-05-16 15:10:20 +02:00
% INPUTS
2015-12-08 17:51:54 +01:00
% - mu [double] scalar, prior mean.
% - sigma2 [double] positive scalar, prior variance.
% - type [integer] scalar equal to 1 or 2, type of the inverse gamma distribution
% - use_fzero_flag [logical] scalar, Use (matlab/octave's implementation of) fzero to solve for nu if true, use
% dynare's implementation of the secant method otherwise.
% - name [string] name of the parameter or random variable.
%
2017-05-16 15:10:20 +02:00
% OUTPUS
2015-12-08 17:51:54 +01:00
% - s [double] scalar, first hyperparameter.
% - nu [double] scalar, second hyperparameter.
%
2017-09-18 17:27:15 +02:00
% REMARKS
% 1. In the Inverse Gamma parameterization with alpha and beta, we have alpha=nu/2 and beta=2/s, where
% if X is IG(alpha,beta) then 1/X is Gamma(alpha,1/beta)
% 2. The call to the matlab's implementation of the secant method is here for testing purpose and should not be used. This routine fails
2015-12-08 17:51:54 +01:00
% more often in finding an interval for nu containing a signe change because it expands the interval on both sides and eventually
% violates the condition nu>2.
2008-09-10 10:41:53 +02:00
2023-01-02 16:57:08 +01:00
% Copyright © 2003-2023 Dynare Team
2008-09-10 10:41:53 +02:00
%
% 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
2021-06-09 17:33:48 +02:00
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
2008-09-10 10:41:53 +02:00
2015-12-10 11:43:17 +01:00
if nargin < 4
error ( ' At least four input arguments are required!' )
2015-12-08 17:51:54 +01:00
end
if ~ isnumeric ( mu ) || ~ isscalar ( mu ) || ~ isreal ( mu )
2015-12-10 11:43:17 +01:00
error ( ' First input argument must be a real scalar!' )
2015-12-08 17:51:54 +01:00
end
2011-11-14 12:04:23 +01:00
2015-12-08 17:51:54 +01:00
if ~ isnumeric ( sigma2 ) || ~ isscalar ( sigma2 ) || ~ isreal ( sigma2 ) || sigma2 < = 0
error ( ' Second input argument must be a real positive scalar!' )
2011-11-14 12:04:23 +01:00
end
2015-12-10 11:43:17 +01:00
if ~ isnumeric ( lb ) || ~ isscalar ( lb ) || ~ isreal ( lb )
error ( ' Third input argument must be a real scalar!' )
2015-12-08 17:51:54 +01:00
end
2015-12-10 11:43:17 +01:00
if ~ isnumeric ( type ) || ~ isscalar ( type ) || ~ ismember ( type , [ 1 , 2 ] )
error ( ' Fourth input argument must be equal to 1 or 2!' )
end
if nargin == 4 || isempty ( use_fzero_flag )
2015-12-08 17:51:54 +01:00
use_fzero_flag = false ;
else
2015-12-10 11:43:17 +01:00
if ~ isscalar ( use_fzero_flag ) || ~ islogical ( use_fzero_flag )
2017-09-18 17:27:15 +02:00
error ( ' Fifth input argument must be a scalar logical!' )
2015-12-08 17:51:54 +01:00
end
end
2015-12-10 11:43:17 +01:00
if nargin > 5 && ( ~ ischar ( name ) || size ( name , 1 ) > 1 )
error ( ' Sixth input argument must be a string!' )
2015-12-08 17:51:54 +01:00
else
name = ' ' ;
end
if ~ isempty ( name )
2015-12-10 11:43:17 +01:00
name = sprintf ( ' for %s' , name ) ;
2015-12-08 17:51:54 +01:00
end
2015-12-10 11:43:17 +01:00
if mu < = lb
error ( ' The prior mean%s (%f) must be above the lower bound (%f)of the Inverse Gamma (type %d) prior distribution!' , mu , lb , name , type ) ;
2015-12-08 17:51:54 +01:00
end
check_solution_flag = true ;
s = [ ] ;
nu = [ ] ;
sigma = sqrt ( sigma2 ) ;
mu2 = mu * mu ;
2008-09-10 10:41:53 +02:00
2017-05-16 12:42:01 +02:00
if type == 2 % Inverse Gamma 2
2009-12-16 18:17:34 +01:00
nu = 2 * ( 2 + mu2 / sigma2 ) ;
s = 2 * mu * ( 1 + mu2 / sigma2 ) ;
2017-05-16 12:42:01 +02:00
elseif type == 1 % Inverse Gamma 1
2011-11-14 12:04:23 +01:00
if sigma2 < Inf
2009-12-16 18:17:34 +01:00
nu = sqrt ( 2 * ( 2 + mu2 / sigma2 ) ) ;
2011-11-14 12:04:23 +01:00
if use_fzero_flag
nu = fzero ( @ ( nu ) ig1fun ( nu , mu2 , sigma2 ) , nu ) ;
else
nu2 = 2 * nu ;
nu1 = 2 ;
err = ig1fun ( nu , mu2 , sigma2 ) ;
err2 = ig1fun ( nu2 , mu2 , sigma2 ) ;
2011-12-03 15:55:06 +01:00
if err2 > 0 % Too short interval.
while nu2 < 1e12 % Shift the interval containing the root.
2011-11-14 12:04:23 +01:00
nu1 = nu2 ;
2011-12-03 15:55:06 +01:00
nu2 = nu2 * 2 ;
2011-11-14 12:04:23 +01:00
err2 = ig1fun ( nu2 , mu2 , sigma2 ) ;
if err2 < 0
break
end
end
2011-12-02 12:12:46 +01:00
if err2 > 0
error ( ' inverse_gamma_specification:: Failed in finding an interval containing a sign change! You should check that the prior variance is not too small compared to the prior mean...' ) ;
end
2011-11-14 12:04:23 +01:00
end
2011-12-03 15:55:06 +01:00
% Solve for nu using the secant method.
2012-01-01 20:12:51 +01:00
while abs ( nu2 / nu1 - 1 ) > 1e-14
2011-11-14 12:04:23 +01:00
if err > 0
nu1 = nu ;
if nu < nu2
nu = nu2 ;
else
nu = 2 * nu ;
nu2 = nu ;
end
2009-12-16 18:17:34 +01:00
else
nu2 = nu ;
end
2011-11-14 12:04:23 +01:00
nu = ( nu1 + nu2 ) / 2 ;
err = ig1fun ( nu , mu2 , sigma2 ) ;
2009-12-16 18:17:34 +01:00
end
end
s = ( sigma2 + mu2 ) * ( nu - 2 ) ;
2011-11-14 12:04:23 +01:00
if check_solution_flag
2012-01-01 20:12:51 +01:00
if abs ( log ( mu ) - log ( sqrt ( s / 2 ) ) - gammaln ( ( nu - 1 ) / 2 ) + gammaln ( nu / 2 ) ) > 1e-7
2011-11-14 12:04:23 +01:00
error ( ' inverse_gamma_specification:: Failed in solving for the hyperparameters!' ) ;
end
2015-12-08 17:51:54 +01:00
if abs ( sigma - sqrt ( s / ( nu - 2 ) - mu * mu ) ) > 1e-7
2011-11-14 12:04:23 +01:00
error ( ' inverse_gamma_specification:: Failed in solving for the hyperparameters!' ) ;
end
end
else
2008-09-10 10:41:53 +02:00
nu = 2 ;
s = 2 * mu2 / pi ;
2011-11-14 12:04:23 +01:00
end
else
2011-12-03 15:55:06 +01:00
error ( ' inverse_gamma_specification: unkown type' )
2011-11-14 12:04:23 +01:00
end
2008-09-10 10:41:53 +02:00
2023-01-02 16:57:08 +01:00
return % --*-- Unit tests --*--
2011-11-14 12:04:23 +01:00
%@test:1
2023-01-02 16:57:08 +01:00
try
[ s , nu ] = inverse_gamma_specification ( . 5 , . 05 , 0 , 1 ) ;
t ( 1 ) = true ;
catch
t ( 1 ) = false ;
end
if t ( 1 )
t ( 2 ) = abs ( 0.5 - sqrt ( . 5 * s ) * gamma ( . 5 * ( nu - 1 ) ) / gamma ( . 5 * nu ) ) < 1e-12 ;
t ( 3 ) = abs ( 0.05 - s / ( nu - 2 ) + . 5 ^2 ) < 1e-12 ;
end
T = all ( t ) ;
2015-12-08 17:51:54 +01:00
%@eof:1
%@test:2
2023-01-02 16:57:08 +01:00
try
[ s , nu ] = inverse_gamma_specification ( . 5 , . 05 , 0 , 2 ) ;
t ( 1 ) = true ;
catch
t ( 1 ) = false ;
end
if t ( 1 )
t ( 2 ) = abs ( 0.5 - s / ( nu - 2 ) ) < 1e-12 ;
t ( 3 ) = abs ( 0.05 - 2 * . 5 ^2 / ( nu - 4 ) ) < 1e-12 ;
end
T = all ( t ) ;
2015-12-08 17:51:54 +01:00
%@eof:2
%@test:3
2023-01-02 16:57:08 +01:00
try
[ s , nu ] = inverse_gamma_specification ( . 5 , Inf , 0 , 1 ) ;
t ( 1 ) = true ;
catch
t ( 1 ) = false ;
end
if t ( 1 )
t ( 2 ) = abs ( 0.5 - sqrt ( . 5 * s ) * gamma ( . 5 * ( nu - 1 ) ) / gamma ( . 5 * nu ) ) < 1e-12 ;
t ( 3 ) = isequal ( nu , 2 ) ; %abs(0.05-2*.5^2/(nu-4))<1e-12;
end
T = all ( t ) ;
2015-12-08 17:51:54 +01:00
%@eof:3
%@test:4
2023-01-02 16:57:08 +01:00
try
[ s , nu ] = inverse_gamma_specification ( . 5 , Inf , 0 , 2 ) ;
t ( 1 ) = true ;
catch
t ( 1 ) = false ;
end
if t ( 1 )
t ( 2 ) = abs ( 0.5 - s / ( nu - 2 ) ) < 1e-12 ;
t ( 3 ) = isequal ( nu , 4 ) ;
end
T = all ( t ) ;
2015-12-08 17:51:54 +01:00
%@eof:4