1 #ifndef __STAN__MCMC__NUTS_NONDIAG_H__
2 #define __STAN__MCMC__NUTS_NONDIAG_H__
9 #include <boost/random/normal_distribution.hpp>
10 #include <boost/random/mersenne_twister.hpp>
11 #include <boost/random/variate_generator.hpp>
12 #include <boost/random/uniform_01.hpp>
19 #include <Eigen/Dense>
33 template <
class BaseRNG = boost::mt19937>
38 const double _maxchange;
49 Eigen::MatrixXd _cov_mat;
51 Eigen::MatrixXd _cov_L;
53 Eigen::MatrixXd _x_sum;
54 Eigen::MatrixXd _xsq_sum;
68 inline bool compute_criterion(std::vector<double>& xplus,
69 std::vector<double>& xminus,
70 std::vector<double>& mplus,
71 std::vector<double>& mminus) {
72 std::vector<double> total_direction;
74 Eigen::Map<Eigen::VectorXd> total_direction_mat(&total_direction[0],total_direction.size());
75 Eigen::Map<Eigen::VectorXd> mplus_mat(&mplus[0],mplus.size());
76 Eigen::Map<Eigen::VectorXd> mminus_mat(&mminus[0],mminus.size());
77 _cov_L.triangularView<Eigen::Lower>().solveInPlace(total_direction_mat);
78 return total_direction_mat.dot(mplus_mat) > 0
79 && total_direction_mat.dot(mminus_mat) > 0;
111 const std::vector<double>& params_r,
112 const std::vector<int>& params_i,
115 double epsilon_pm = 0.0,
116 bool epsilon_adapt =
true,
119 BaseRNG base_rng = BaseRNG(std::time(0)))
134 _next_diag_adapt(10 + model.num_params_r())
138 _x_sum = Eigen::MatrixXd::Zero(model.
num_params_r(), 1);
160 for (
size_t i = 0; i < mminus.size(); ++i)
162 std::vector<double> mplus(mminus);
167 std::vector<double> gradminus(this->
_g);
168 std::vector<double> gradplus(this->
_g);
169 std::vector<double> xminus(this->
_x);
170 std::vector<double> xplus(this->
_x);
176 bool criterion =
true;
179 std::vector<double> newx, newgrad, dummy1, dummy2, dummy3;
181 double prob_sum = -1;
183 int n_considered = 0;
192 double range = high - low;
197 while (criterion && (_maxdepth < 0 || depth <= _maxdepth)) {
200 build_tree(xminus, mminus, gradminus, u, direction, depth,
201 H0, xminus, mminus, gradminus, dummy1, dummy2, dummy3,
202 newx, newgrad, newlogp, newnvalid, criterion, prob_sum,
205 build_tree(xplus, mplus, gradplus, u, direction, depth,
206 H0, dummy1, dummy2, dummy3, xplus, mplus, gradplus,
207 newx, newgrad, newlogp, newnvalid, criterion, prob_sum,
212 criterion = compute_criterion(xplus, xminus, mplus, mminus);
218 this->
_logp = newlogp;
223 for (
size_t i = 0; i < newx.size(); i++) {
224 _x_sum(i) += this->
_x[i];
225 for (
size_t j = 0; j < newx.size(); j++){
226 _xsq_sum(i,j) += this->
_x[i] * this->
_x[j];
237 double adapt_stat = prob_sum / float(n_considered);
240 double adapt_g = adapt_stat - this->
_delta;
241 std::vector<double> gvec(1, -adapt_g);
242 std::vector<double> result;
247 _next_diag_adapt *= 2;
250 _x_sum = _x_sum / _x_sum_n;
251 _xsq_sum = _xsq_sum / _x_sum_n;
252 _cov_mat = _xsq_sum - _x_sum * _x_sum.transpose();
253 double _norm = _cov_mat.trace() / _cov_mat.rows();
255 _cov_mat = Eigen::MatrixXd::Identity(_cov_mat.rows(),_cov_mat.cols());
257 _cov_mat = _cov_mat * (_x_sum_n / _norm / (_x_sum_n + 5)) ;
258 for(
int i = 0; i < _cov_mat.rows(); i++)
259 _cov_mat(i,i) = _cov_mat(i,i) * ((_x_sum_n + 2) / _x_sum_n) + (3 / (_x_sum_n + 5));
261 _cov_L = _cov_mat.selfadjointView<Eigen::Upper>().llt().matrixL();
267 std::vector<double> result;
269 double avg_eta = 1.0 / this->
n_steps();
286 o << _lastdepth <<
',';
292 o <<
"# (mcmc::nuts_nondiag) adaptation finished" <<
'\n';
293 o <<
"# step size=" << this->
_epsilon <<
'\n';
294 o <<
"# estimated covariance matrix:\n";
295 for(
int i=0; i<_cov_mat.rows(); i++){
297 for(
int j=0; j<_cov_mat.cols(); j++)
298 o << _cov_mat(i,j) <<
",";
305 names.push_back(
"treedepth__");
307 names.push_back(
"stepsize__");
312 values.push_back(_lastdepth);
352 const std::vector<double>& m,
353 const std::vector<double>&
grad,
358 std::vector<double>& xminus,
359 std::vector<double>& mminus,
360 std::vector<double>& gradminus,
361 std::vector<double>& xplus,
362 std::vector<double>& mplus,
363 std::vector<double>& gradplus,
364 std::vector<double>& newx,
365 std::vector<double>& newgrad,
376 xminus, mminus, gradminus,
383 gradplus = gradminus;
386 newH = -std::numeric_limits<double>::infinity();
388 criterion = newH - u > _maxchange;
404 build_tree(x, m, grad, u, direction, depth-1, H0, xminus, mminus,
405 gradminus, xplus, mplus, gradplus, newx, newgrad, newlogp,
406 nvalid, criterion, prob_sum, n_considered);
408 std::vector<double> dummy1, dummy2, dummy3;
409 std::vector<double> newx2;
410 std::vector<double> newgrad2;
417 build_tree(xminus, mminus, gradminus, u, direction, depth-1, H0,
418 xminus, mminus, gradminus, dummy1, dummy2, dummy3,
419 newx2, newgrad2, newlogp2, nvalid2, criterion2,
420 prob_sum2, n_considered2);
422 build_tree(xplus, mplus, gradplus, u, direction, depth-1, H0,
423 dummy1, dummy2, dummy3, xplus, mplus, gradplus,
424 newx2, newgrad2, newlogp2, nvalid2, criterion2,
425 prob_sum2, n_considered2);
428 <
float(nvalid2) /
float(nvalid+nvalid2))){
433 n_considered += n_considered2;
434 prob_sum += prob_sum2;
435 criterion &= criterion2;
438 criterion &= compute_criterion(xplus, xminus, mplus, mminus);