dynare/mex/sources/ms-sbvar/mex_ms_sbvar.cc

632 lines
19 KiB
C++

/*
* Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
*/
#if defined(MATLAB_MEX_FILE) || defined(OCTAVE_MEX_FILE)
#include "dynmex.h"
#include "mex_ms_sbvar.h"
#include <iostream>
#include <fstream>
extern "C" {
#include "modify_for_mex.h"
#include "switch.h"
#include "switchio.h"
#include "VARio.h"
#include "dw_rand.h"
}
using namespace std;
int
file_exist(char *filename)
{
int ret = 0;
char ch;
ifstream fin;
fin.open(filename, ios_base::in);
if (fin.is_open() && fin.get(ch))
ret = 1;
fin.close();
return ret;
}
char *
CreateFilenameFromTag(const char *fmt, const char *tag, const char *dir)
{
char *filename;
if (!tag)
tag = "";
if (!dir)
dir = "";
sprintf(filename = (char *) mxMalloc(strlen(dir) + strlen(fmt) + strlen(tag) - 3), fmt, dir, tag);
return filename;
}
/*
* initialize_ms_model
* - initiliazes a TstateModel given the filename or tagname of initialization file
*/
TStateModel *
initialize_ms_model(char *name)
{
TStateModel *model = (TStateModel *) NULL;
char *filename = (char *) NULL, *est_filename = (char *) NULL, *init_filename = (char *) NULL;
est_filename = CreateFilenameFromTag("%sest_final_%s.out", name, "");
init_filename = CreateFilenameFromTag("%sinit_%s.dat", name, "");
if (file_exist(name))
filename = name;
else if (file_exist(est_filename))
filename = est_filename;
else if (file_exist(init_filename))
filename = init_filename;
else
{
printf("Can not open initialization or estimation file!\n");
return (TStateModel *) NULL;
}
try
{
if (!(model = Read_VAR_Specification((FILE *) NULL, filename)))
{
mxFree(filename);
printf("Can not initialize model with given name!\n");
return (TStateModel *) NULL;
}
if (est_filename != NULL)
{
if (!strstr(est_filename, filename))
{
printf("Initializing with empty parameters %s\n", filename);
// If no estimation file is around then just initialize the sizes
double *theta = (double *) mxMalloc(sizeof(double)*NumberFreeParametersTheta(model));
double *q = (double *) mxMalloc(sizeof(double)*NumberFreeParametersQ(model));
ConvertFreeParametersToQ(model, q);
ConvertFreeParametersToTheta(model, theta);
}
}
}
catch (const char *s)
{
printf("Error Initializing TStateModel: %s\n", s);
model = (TStateModel *) NULL;
}
mxFree(filename);
return model;
}
int
get_var_dimensions(TStateModel *model, int *nstates, int *nvars, int *npre, int *nfree)
{
if (model)
{
try
{
*nfree = NumberFreeParametersTheta(model)+NumberFreeParametersQ(model);
T_VAR_Parameters *p = (T_VAR_Parameters *) (model->theta);
*nstates = model->sv->nstates;
*nvars = p->nvars;
*npre = p->npre;
return 0;
}
catch (const char *s)
{
printf("Error Getting VAR Dimensions");
return 1;
}
}
else
{
printf("The model passed was null!\n");
return 1;
}
}
int
set_parameters_in_VAR(TStateModel *model, double *free_parameters)
{
int nfree;
try
{
nfree = NumberFreeParametersTheta(model)+NumberFreeParametersQ(model);
ConvertFreeParametersToQ(model, free_parameters+NumberFreeParametersTheta(model));
ConvertFreeParametersToTheta(model, free_parameters);
ComputeTransitionMatrix(0, model);
}
catch (const char *s)
{
return 1;
}
return 0;
}
int
convert_free_parameters_to_VAR(TStateModel *model, double *free_parameters, double *A0, double *Aplus, double *Zeta, double *Q)
{
int nstates = 0, nvars = 0, npre = 0;
int i = 0, j = 0, s = 0;
if (model == NULL)
{
printf("The model passed was null in Convert Free Parameters!\n");
return 1;
}
if (set_parameters_in_VAR(model, free_parameters) > 0)
{
printf("Could not set Parameters in model when converting parameters to var\n");
return 2;
}
try
{
T_VAR_Parameters *p = (T_VAR_Parameters *) (model->theta);
nstates = model->sv->nstates;
nvars = p->nvars;
npre = p->npre;
TMatrix a = NULL, aplus = NULL;
a = CreateMatrix(p->nvars, p->nvars);
aplus = CreateMatrix(p->npre, p->nvars);
// Is this is a good idea in matlab?
if (A0 == NULL)
A0 = new double [nstates*nvars*nvars];
//A0 = malloc(sizeof(double)*(nstates*nvars*nvars));
if (Aplus == NULL)
Aplus = new double [nstates*npre*nvars];
//Aplus = malloc(sizeof(double)*(nstates*npre*nvars));
if (Zeta == NULL)
Zeta = new double [nstates*nvars*nvars];
//Zeta = malloc(sizeof(double)*(nstates*nvars*nvars));
if (Q == NULL)
Q = new double [nstates*nstates];
//Q = malloc(sizeof(double)*(nstates*nstates));
for (s = 0; s < nstates; s++)
{
MakeA0(a, s, p);
for (i = 0; i < nvars; i++)
{
for (j = 0; j < nvars; j++)
A0[(s)+((i+j*nvars)*nstates)] = ElementM(a, i, j);
}
MakeAplus(aplus, s, p);
for (i = 0; i < npre; i++)
{
for (j = 0; j < nvars; j++)
Aplus[(s)+((i+j*npre)*nstates)] = ElementM(aplus, i, j);
}
MakeZeta(a, s, p);
for (i = 0; i < nvars; i++)
{
for (j = 0; j < nvars; j++)
Zeta[(s)+((i+j*nvars)*nstates)] = ElementM(a, i, j);
}
}
// Grand Transition Matrix
for (i = 0; i < nstates; i++)
for (j = 0; j < nstates; j++)
Q[i + j*nstates] = ElementM(model->sv->Q, i, j);
FreeMatrix(a);
FreeMatrix(aplus);
}
catch (const char *s)
{
printf("Exception: convert_free_parameters\n");
return 3;
}
return 0;
}
/*
Additional command line parameters
'horizon', <integer>
If this argument exists, then the forecast horizon is given by the passed
integer. The default value is 12.
'filtered'
Uses filtered probabilities at the end of the sample as initial conditions
for regime probabilities. The default behavior is to us the erogdic
distribution for the initial conditions. This flag only applies if neither
-regimes nor -regime is specified.
'error_bands'
Output error bands. (default = off - only median is computed)
'percentiles' n p_1 p_2 ... p_n
Percentiles to compute. The first parameter after percentiles must be the
number of percentiles and the following values are the actual percentiles.
default = 3 0.16 0.50 0.84 if error_bands flag is set
= 1 0.50 otherwise
'parameter_uncertainty'
Apply parameter uncertainty when computing error bands or median. When set,
will default shocks = 1
'shocks_per_parameter', <integer>
Number of regime paths to draw for each parameter draw. The default value
is 1 if parameter_uncertainty is set and 10,000 otherwise.
'thin'
Thinning factor. Only 1/thin of the draws in posterior draws file are
used. The default value is 1.
'regimes'
Produces forecasts as if each regime were permanent. (default = off)
'regime' <integer>
Produces forecasts as if regime were permanent. Regime numbers are zero
based. (default = off)
'simulation_file', <string>
name of the file containing the model's simulated free values
'number_observations', <integer>
If this argument exists, then the number of data points included in the
output is given by the passed integer int the forecast output. The default value is 0.
'free_parameters' <vector>:
Vector of free paramters to initialize the model with.
'median':
Shortcut for setting 'percentiles',[0.5]
'mean':
Compute the mean, instead of percentiles
'seed':
Set the Seed for random number generation, default=0 (random)
*/
SbvarOption *
initialize_sbvar_options(char *file_tag)
{
SbvarOption *options = new SbvarOption;
options->shocks = 10000;
options->thin = 1;
options->horizon = 20;
options->number_observations = 0;
options->regime = -1;
options->regimes = false;
options->parameter_uncertainty = false;
options->num_percentiles = 3;
options->percentiles = new double[3];
options->percentiles[0] = 0.16;
options->percentiles[1] = 0.5;
options->percentiles[2] = 0.84;
options->filtered_probabilities = false;
options->num_parameters = -1;
options->free_parameters = (double *) NULL;
options->mean = false;
options->seed = 0;
if (file_tag != NULL)
{
options->simulation_filename = (char *) CreateFilenameFromTag("%ssimulation_%s.out", file_tag, "");
if (file_exist(options->simulation_filename))
options->simulation_file = fopen(options->simulation_filename, "r");
}
else
{
options->simulation_filename = (char *) NULL;
options->simulation_file = (FILE *) NULL;
}
return options;
}
int
set_options(SbvarOption *options, const mxArray *prhs[])
{
if (options == NULL)
options = initialize_sbvar_options((char *) NULL);
double *temp_buf;
bool shocks_passed = false;
int num_options = mxGetN(prhs[0]);
for (int i = 1; i < num_options; i++)
{
mxArray *this_option = mxGetCell(prhs[0],i);
char *option_name_c = mxArrayToString(mxGetCell(this_option,0));
string option_name (option_name_c);
mxArray *this_option_value = NULL;
if (mxGetN(this_option) > 1)
this_option_value = mxGetCell(this_option,1);
if (option_name == "horizon")
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
options->horizon = (int) temp_buf[0];
}
else
{
cout << "You must pass an integer after specifying the 'horizon' option" << endl;
return 1;
}
else if (option_name == "filtered")
options->filtered_probabilities = true;
else if (option_name == "error_bands")
{
free(options->percentiles);
options->num_percentiles = 3;
options->percentiles = new double[3];
options->percentiles[0] = 0.16;
options->percentiles[1] = 0.5;
options->percentiles[2] = 0.84;
// Check if the user specified to turn off error bands
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
if (temp_buf[0] == 0)
{
options->num_percentiles = 1;
options->percentiles = new double[1];
options->percentiles[0] = 0.50;
}
}
}
else if (option_name == "median")
{
free(options->percentiles);
options->num_percentiles = 1;
options->percentiles = new double[1];
options->percentiles[0] = 0.5;
}
else if (option_name == "percentiles")
if (this_option_value)
{
options->num_percentiles = mxGetN(this_option_value)
> mxGetM(this_option_value) ? mxGetN(this_option_value)
: mxGetM(this_option_value);
options->percentiles = mxGetPr(this_option_value);
}
else
{
cout << "You must pass a vector after the 'percentiles' argument with the "
<< "percentiles that you want to have computed, ex "
<< "'percentiles',[.16 .5 .84]" << endl;
return 1;
}
else if (option_name == "parameter_uncertainty")
{
options->parameter_uncertainty = true;
if (shocks_passed == false)
options->shocks = 1;
}
else if (option_name == "shocks_per_parameter")
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
options->shocks = (int) temp_buf[0];
shocks_passed = true;
}
else
{
cout << "You must pass an integer after specifying the 'shocks_per_parameter' option" << endl;
return 1;
}
else if (option_name == "thin")
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
options->thin = (int) temp_buf[0];
}
else
{
cout << "You must pass an integer after specifying the 'thin' option" << endl;
return 1;
}
else if (option_name == "simulation_file")
{
char *posterior_filename = mxArrayToString(this_option_value);
strcpy(options->simulation_filename, posterior_filename);
if (!(options->simulation_file = fopen(posterior_filename, "rt")))
{
cout << "Can not open posterior file " << options->simulation_file
<< " for reading. " << endl;
return 1;
}
mxFree(posterior_filename);
}
else if (option_name == "regimes")
options->regimes = true;
else if (option_name == "regime")
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
options->regime = (int) temp_buf[0];
}
else
{
cout << "You must pass an integer after specifying the 'regime' "
<< "option, or alternatively you can specify 'regimes'" << endl;
return 1;
}
else if (option_name == "number_observations")
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
options->number_observations = (int) temp_buf[0];
}
else
{
cout << "You must pass an integer after specifying the "
<< "'number_observations' option" << endl;
return 1;
}
else if (option_name == "free_parameters")
if (this_option_value && mxIsNumeric(this_option_value))
{
options->num_parameters = mxGetM(this_option_value);
options->free_parameters = mxGetPr(this_option_value);
}
else
{
cout << "You must pass a vector of free parameters after "
<< "specifying 'free_parameters'" << endl;
return 1;
}
else if (option_name == "mean")
{
options->mean = true;
options->num_percentiles = 0;
options->percentiles = (double *) NULL;
}
else if (option_name == "seed")
if (this_option_value && mxIsNumeric(this_option_value))
{
temp_buf = (double *) mxGetData(this_option_value);
options->seed = (long) temp_buf[0];
}
else
{
cout << "You must pass an integer after specifying the 'seed' option" << endl;
return 1;
}
else
{
cout << "set_options error: option '" << option_name << "' not matched" << endl;
return 1;
}
mxFree(option_name_c);
} // End Optional Arguments
return 0;
}
int
print_sbvar_options(SbvarOption *options)
{
using namespace std;
int i;
if (options == NULL)
return 1;
cout << "SBVAR OPTIONS" << endl;
cout << "Number of Shocks: " << options->shocks << endl;
cout << "Thinning Factor: " << options->thin << endl;
cout << "Horizon: " << options->horizon << endl;
cout << "Number of Observations to Show: " << options->number_observations << endl;
cout << "Regime: " << options->regime << endl;
cout << "Regimes: " << options->regimes << endl;
cout << "Number Free parameters: " << options->num_parameters << endl;
cout << "Parameter Uncertainty: " << options->parameter_uncertainty << endl;
cout << "Mean: " << options->mean << endl;
cout << "Number Percentiles: " << options->num_percentiles << endl;
cout << "Percentiles: ";
for (i = 0; i < options->num_percentiles; i++)
cout << options->percentiles[i] << " ";
cout << endl;
cout << "Filtered Probabilities: " << options->filtered_probabilities << endl;
cout << "Simulation Filename: " << options->simulation_filename << endl;
cout << "Random Number Seed: " << options->seed << endl;
return 0;
}
TStateModel *
initialize_model_and_options(SbvarOption **options, const mxArray *prhs[], int *nstates, int *nvars, int *npre, int *nfree)
{
char *name;
TStateModel *model = (TStateModel *) NULL;
SbvarOption *opt;
// Initialize the StateSpace Model with the initialization file
name = mxArrayToString(mxGetCell(mxGetCell(prhs[0],0),1));
model = initialize_ms_model(name);
if (model == NULL)
{
cout << "Could not initialize State Space Switching model with the given tag." << endl;
return (TStateModel *) NULL;
}
if (get_var_dimensions(model, nstates, nvars, npre, nfree) > 0)
{
cout << "Problems Determining the size of the Initialized model." << endl;
return (TStateModel *) NULL;
}
// Process the rest of the options
opt = initialize_sbvar_options(name);
mxFree(name);
if (set_options(opt, prhs) > 0)
{
cout << "There was a problem with the options passed." << endl;
return (TStateModel *) NULL;
}
// Set seed value
try
{
dw_initialize_generator(opt->seed);
}
catch (const char *s)
{
cout << "Exception: " << s << endl;
cout << "Exception thrown initializing Random Seed." << endl;
return (TStateModel *) NULL;
}
// If free parameters have been passed, then set them in the model
if (opt->num_parameters > 0)
{
if (opt->num_parameters == *nfree + 2)
{
opt->free_parameters = opt->free_parameters+2;
opt->num_parameters = opt->num_parameters - 2;
}
if (opt->num_parameters != *nfree)
{
cout << "The Free Parameter vector passed is the wrong size for the given model" << endl;
return (TStateModel *) NULL;
}
// Set the paramters as the current 'theta'
if (set_parameters_in_VAR(model, opt->free_parameters) > 0)
{
cout << "Problem with the free parameters that were passed being set in MS-SBVAR Model." << endl;
return (TStateModel *) NULL;
}
}
*options = opt;
return model;
}
#endif