/* * Copyright (C) 2010-2017 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 . */ #include #include #include #include #include #include "Vector.hh" #include "Matrix.hh" #include "LogPosteriorDensity.hh" #include class LogposteriorMexErrMsgTxtException { public: std::string errMsg; LogposteriorMexErrMsgTxtException(const std::string &msg) : errMsg(msg) { } inline const char * getErrMsg() { return errMsg.c_str(); } }; void fillEstParamsInfo(const mxArray *bayestopt_, const mxArray *estim_params_info, EstimatedParameter::pType type, std::vector &estParamsInfo) { const mxArray *bayestopt_ubp = mxGetField(bayestopt_, 0, "ub"); // upper bound const mxArray *bayestopt_lbp = mxGetField(bayestopt_, 0, "lb"); // lower bound const mxArray *bayestopt_p1p = mxGetField(bayestopt_, 0, "p1"); // prior mean const mxArray *bayestopt_p2p = mxGetField(bayestopt_, 0, "p2"); // prior standard deviation const mxArray *bayestopt_p3p = mxGetField(bayestopt_, 0, "p3"); // lower bound const mxArray *bayestopt_p4p = mxGetField(bayestopt_, 0, "p4"); // upper bound const mxArray *bayestopt_p6p = mxGetField(bayestopt_, 0, "p6"); // first hyper-parameter (\alpha for the BETA and GAMMA distributions, s for the INVERSE GAMMAs, expectation for the GAUSSIAN distribution, lower bound for the UNIFORM distribution). const mxArray *bayestopt_p7p = mxGetField(bayestopt_, 0, "p7"); // second hyper-parameter (\beta for the BETA and GAMMA distributions, \nu for the INVERSE GAMMAs, standard deviation for the GAUSSIAN distribution, upper bound for the UNIFORM distribution). const mxArray *bayestopt_jscalep = mxGetField(bayestopt_, 0, "jscale"); // MCMC jump scale const size_t bayestopt_size = mxGetM(bayestopt_); const VectorConstView bayestopt_ub(mxGetPr(bayestopt_ubp), bayestopt_size, 1); const VectorConstView bayestopt_lb(mxGetPr(bayestopt_lbp), bayestopt_size, 1); const VectorConstView bayestopt_p1(mxGetPr(bayestopt_p1p), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "p1"); const VectorConstView bayestopt_p2(mxGetPr(bayestopt_p2p), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "p2"); const VectorConstView bayestopt_p3(mxGetPr(bayestopt_p3p), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "p3"); const VectorConstView bayestopt_p4(mxGetPr(bayestopt_p4p), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "p4"); const VectorConstView bayestopt_p6(mxGetPr(bayestopt_p6p), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "p6"); const VectorConstView bayestopt_p7(mxGetPr(bayestopt_p7p), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "p7"); const VectorConstView bayestopt_jscale(mxGetPr(bayestopt_jscalep), bayestopt_size, 1); //=mxGetField(bayestopt_, 0, "jscale"); // loop processsing size_t m = mxGetM(estim_params_info), n = mxGetN(estim_params_info); MatrixConstView epi(mxGetPr(estim_params_info), m, n, m); size_t bayestopt_count = estParamsInfo.size(); for (size_t i = 0; i < m; i++) { size_t col = 0; size_t id1 = (size_t) epi(i, col++) - 1; size_t id2 = 0; if (type == EstimatedParameter::shock_Corr || type == EstimatedParameter::measureErr_Corr) id2 = (size_t) epi(i, col++) - 1; col++; // Skip init_val #2 or #3 double par_low_bound = bayestopt_lb(bayestopt_count); col++; //#3 epi(i, col++); double par_up_bound = bayestopt_ub(bayestopt_count); col++; //#4 epi(i, col++); Prior::pShape shape = (Prior::pShape) epi(i, col++); double mean = epi(i, col++); double std = epi(i, col++); double low_bound = bayestopt_p3(bayestopt_count); double up_bound = bayestopt_p4(bayestopt_count); double fhp = bayestopt_p6(bayestopt_count); // double p3 = epi(i, col++); double shp = bayestopt_p7(bayestopt_count); // double p4 = epi(i, col++); Prior *p = Prior::constructPrior(shape, mean, std, low_bound, up_bound, fhp, shp); //1.0,INFINITY);//p3, p4); // Only one subsample std::vector subSampleIDs; subSampleIDs.push_back(0); estParamsInfo.push_back(EstimatedParameter(type, id1, id2, subSampleIDs, par_low_bound, par_up_bound, p)); bayestopt_count++; } } template double logposterior(VEC1 &estParams, const MatrixConstView &data, const mxArray *options_, const mxArray *M_, const mxArray *estim_params_, const mxArray *bayestopt_, const mxArray *oo_, VEC2 &steadyState, double *trend_coeff, VectorView &deepParams, Matrix &H, MatrixView &Q) { double loglinear = *mxGetPr(mxGetField(options_, 0, "loglinear")); if (loglinear == 1) throw LogposteriorMexErrMsgTxtException("Option loglinear is not supported"); if (*mxGetPr(mxGetField(options_, 0, "endogenous_prior")) == 1) throw LogposteriorMexErrMsgTxtException("Option endogenous_prior is not supported"); double with_trend = *mxGetPr(mxGetField(bayestopt_, 0, "with_trend")); if (with_trend == 1) throw LogposteriorMexErrMsgTxtException("Observation trends are not supported"); // Construct arguments of constructor of LogLikelihoodMain char *fName = mxArrayToString(mxGetField(M_, 0, "fname")); std::string basename(fName); mxFree(fName); size_t n_endo = (size_t) *mxGetPr(mxGetField(M_, 0, "endo_nbr")); size_t n_exo = (size_t) *mxGetPr(mxGetField(M_, 0, "exo_nbr")); std::vector zeta_fwrd, zeta_back, zeta_mixed, zeta_static; const mxArray *lli_mx = mxGetField(M_, 0, "lead_lag_incidence"); MatrixConstView lli(mxGetPr(lli_mx), mxGetM(lli_mx), mxGetN(lli_mx), mxGetM(lli_mx)); if (lli.getRows() != 3) throw LogposteriorMexErrMsgTxtException("Purely backward or purely forward models are not supported"); if (lli.getCols() != n_endo) throw LogposteriorMexErrMsgTxtException("Incorrect lead/lag incidence matrix"); for (size_t i = 0; i < n_endo; i++) { if (lli(0, i) == 0 && lli(2, i) == 0) zeta_static.push_back(i); else if (lli(0, i) != 0 && lli(2, i) == 0) zeta_back.push_back(i); else if (lli(0, i) == 0 && lli(2, i) != 0) zeta_fwrd.push_back(i); else zeta_mixed.push_back(i); } double qz_criterium = *mxGetPr(mxGetField(options_, 0, "qz_criterium")); double lyapunov_tol = *mxGetPr(mxGetField(options_, 0, "lyapunov_complex_threshold")); double riccati_tol = *mxGetPr(mxGetField(options_, 0, "riccati_tol")); size_t presample = (size_t) *mxGetPr(mxGetField(options_, 0, "presample")); std::vector varobs; const mxArray *varobs_mx = mxGetField(options_, 0, "varobs_id"); if (mxGetM(varobs_mx) != 1) throw LogposteriorMexErrMsgTxtException("options_.varobs_id must be a row vector"); size_t n_varobs = mxGetN(varobs_mx); // substract 1.0 from obsverved variables index std::transform(mxGetPr(varobs_mx), mxGetPr(varobs_mx) + n_varobs, back_inserter(varobs), std::bind2nd(std::minus(), 1)); if (data.getRows() != n_varobs) throw LogposteriorMexErrMsgTxtException("Data does not have as many rows as there are observed variables"); std::vector estSubsamples; estSubsamples.push_back(EstimationSubsample(0, data.getCols() - 1)); std::vector estParamsInfo; fillEstParamsInfo(bayestopt_, mxGetField(estim_params_, 0, "var_exo"), EstimatedParameter::shock_SD, estParamsInfo); fillEstParamsInfo(bayestopt_, mxGetField(estim_params_, 0, "var_endo"), EstimatedParameter::measureErr_SD, estParamsInfo); fillEstParamsInfo(bayestopt_, mxGetField(estim_params_, 0, "corrx"), EstimatedParameter::shock_Corr, estParamsInfo); fillEstParamsInfo(bayestopt_, mxGetField(estim_params_, 0, "corrn"), EstimatedParameter::measureErr_Corr, estParamsInfo); fillEstParamsInfo(bayestopt_, mxGetField(estim_params_, 0, "param_vals"), EstimatedParameter::deepPar, estParamsInfo); EstimatedParametersDescription epd(estSubsamples, estParamsInfo); bool noconstant = (bool) *mxGetPr(mxGetField(options_, 0, "noconstant")); // Allocate LogPosteriorDensity object LogPosteriorDensity lpd(basename, epd, n_endo, n_exo, zeta_fwrd, zeta_back, zeta_mixed, zeta_static, qz_criterium, varobs, riccati_tol, lyapunov_tol, noconstant); // Construct arguments of compute() method // Compute the posterior double logPD = lpd.compute(steadyState, estParams, deepParams, data, Q, H, presample); // Cleanups for (std::vector::iterator it = estParamsInfo.begin(); it != estParamsInfo.end(); it++) delete it->prior; return logPD; } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if (nrhs != 7) DYN_MEX_FUNC_ERR_MSG_TXT("logposterior: exactly 7 input arguments are required."); if (nlhs > 9) DYN_MEX_FUNC_ERR_MSG_TXT("logposterior returns 8 output arguments at the most."); // Check and retrieve the RHS arguments if (!mxIsDouble(prhs[0]) || mxGetN(prhs[0]) != 1) DYN_MEX_FUNC_ERR_MSG_TXT("logposterior: First argument must be a column vector of double-precision numbers"); VectorConstView estParams(mxGetPr(prhs[0]), mxGetM(prhs[0]), 1); for (int i = 1; i < 7; ++i) if (!mxIsStruct(prhs[i])) { std::stringstream msg; msg << "logposterior: argument " << i+1 << " must be a Matlab structure"; DYN_MEX_FUNC_ERR_MSG_TXT(msg.str().c_str()); } const mxArray *dataset = prhs[1]; const mxArray *options_ = prhs[2]; const mxArray *M_ = prhs[3]; const mxArray *estim_params_ = prhs[4]; const mxArray *bayestopt_ = prhs[5]; const mxArray *oo_ = prhs[6]; const mxArray *dataset_data = mxGetField(dataset, 0, "data"); MatrixConstView data(mxGetPr(dataset_data), mxGetM(dataset_data), mxGetN(dataset_data), mxGetM(dataset_data)); // Creaete LHS arguments size_t endo_nbr = (size_t) *mxGetPr(mxGetField(M_, 0, "endo_nbr")); size_t exo_nbr = (size_t) *mxGetPr(mxGetField(M_, 0, "exo_nbr")); size_t param_nbr = (size_t) *mxGetPr(mxGetField(M_, 0, "param_nbr")); size_t varobs_nbr = mxGetM(mxGetField(options_, 0, "varobs")); plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); plhs[2] = mxCreateDoubleMatrix(endo_nbr, 1, mxREAL); plhs[3] = mxCreateDoubleMatrix(varobs_nbr, 1, mxREAL); plhs[4] = mxCreateDoubleMatrix(1, 1, mxREAL); plhs[5] = mxCreateDoubleMatrix(param_nbr, 1, mxREAL); plhs[6] = mxCreateDoubleMatrix(varobs_nbr, varobs_nbr, mxREAL); plhs[7] = mxCreateDoubleMatrix(exo_nbr, exo_nbr, mxREAL); double *lik = mxGetPr(plhs[0]); double *exit_flag = mxGetPr(plhs[1]); VectorView steadyState(mxGetPr(mxGetField(oo_, 0, "steady_state")), endo_nbr, 1); VectorView deepParams(mxGetPr(mxGetField(M_, 0, "params")), param_nbr, 1); MatrixView Q(mxGetPr(mxGetField(M_, 0, "Sigma_e")), exo_nbr, exo_nbr, exo_nbr); Matrix H(varobs_nbr, varobs_nbr); const mxArray *H_mx = mxGetField(M_, 0, "H"); if (mxGetM(H_mx) == 1 && mxGetN(H_mx) == 1 && *mxGetPr(H_mx) == 0) H.setAll(0.0); else H = MatrixConstView(mxGetPr(H_mx), varobs_nbr, varobs_nbr, varobs_nbr); double *trend_coeff = mxGetPr(plhs[3]); double *info_mx = mxGetPr(plhs[4]); // Compute and return the value try { *lik = logposterior(estParams, data, options_, M_, estim_params_, bayestopt_, oo_, steadyState, trend_coeff, deepParams, H, Q); *info_mx = 0; *exit_flag = 0; } catch (LogposteriorMexErrMsgTxtException e) { DYN_MEX_FUNC_ERR_MSG_TXT(e.getErrMsg()); } catch (SteadyStateSolver::SteadyStateException e) { DYN_MEX_FUNC_ERR_MSG_TXT(e.message.c_str()); } }