1 #ifndef __STAN__MCMC__CHAINS_HPP__
2 #define __STAN__MCMC__CHAINS_HPP__
16 #include <boost/accumulators/accumulators.hpp>
17 #include <boost/accumulators/statistics/stats.hpp>
18 #include <boost/accumulators/statistics/mean.hpp>
19 #include <boost/accumulators/statistics/tail_quantile.hpp>
20 #include <boost/accumulators/statistics/p_square_quantile.hpp>
21 #include <boost/accumulators/statistics/variance.hpp>
22 #include <boost/accumulators/statistics/covariance.hpp>
23 #include <boost/accumulators/statistics/variates/covariate.hpp>
26 #include <boost/random/uniform_int_distribution.hpp>
27 #include <boost/random/additive_combine.hpp>
54 template <
typename RNG = boost::random::ecuyer1988>
57 Eigen::Matrix<std::string, Eigen::Dynamic, 1> param_names_;
58 Eigen::Matrix<Eigen::MatrixXd, Eigen::Dynamic, 1> samples_;
59 Eigen::VectorXi warmup_;
61 double mean(
const Eigen::VectorXd& x) {
62 return (x.array() / x.size()).
sum();
65 double variance(
const Eigen::VectorXd& x) {
67 return ((x.array() - m) /
std::sqrt((x.size() - 1.0))).square().sum();
70 double sd(
const Eigen::VectorXd& x) {
75 double covariance(
const Eigen::VectorXd& x,
const Eigen::VectorXd& y) {
76 if (x.rows() != y.rows())
77 std::cerr <<
"warning: covariance of different length chains";
78 using boost::accumulators::accumulator_set;
79 using boost::accumulators::stats;
81 using boost::accumulators::tag::covariance;
82 using boost::accumulators::tag::covariate1;
84 accumulator_set<double, stats<covariance<double, covariate1> > > acc;
86 int M =
std::min(x.size(), y.size());
87 for (
int i = 0; i < M; i++)
88 acc(x(i), boost::accumulators::covariate1=y(i));
90 return boost::accumulators::covariance(acc) * M / (M-1);
93 double correlation(
const Eigen::VectorXd& x,
const Eigen::VectorXd& y) {
94 if (x.rows() != y.rows())
95 std::cerr <<
"warning: covariance of different length chains";
96 using boost::accumulators::accumulator_set;
97 using boost::accumulators::stats;
99 using boost::accumulators::tag::covariance;
100 using boost::accumulators::tag::covariate1;
102 accumulator_set<double, stats<variance, covariance<double, covariate1> > > acc_xy;
103 accumulator_set<double, stats<variance> > acc_y;
105 int M =
std::min(x.size(), y.size());
106 for (
int i = 0; i < M; i++) {
107 acc_xy(x(i), boost::accumulators::covariate1=y(i));
111 double cov = boost::accumulators::covariance(acc_xy);
112 if (cov > -1
e-8 && cov < 1
e-8)
117 double quantile(
const Eigen::VectorXd& x,
const double prob) {
118 using boost::accumulators::accumulator_set;
119 using boost::accumulators::left;
120 using boost::accumulators::quantile_probability;
121 using boost::accumulators::right;
122 using boost::accumulators::stats;
123 using boost::accumulators::tag::tail;
124 using boost::accumulators::tag::tail_quantile;
127 size_t cache_size = M;
130 accumulator_set<double, stats<tail_quantile<left> > >
131 acc(tail<left>::cache_size = cache_size);
132 for (
int i = 0; i < M; i++)
134 return boost::accumulators::quantile(acc, quantile_probability=prob);
136 accumulator_set<double, stats<tail_quantile<right> > >
137 acc(tail<right>::cache_size = cache_size);
138 for (
int i = 0; i < M; i++)
140 return boost::accumulators::quantile(acc, quantile_probability=prob);
143 Eigen::VectorXd quantiles(
const Eigen::VectorXd& x,
const Eigen::VectorXd& probs) {
144 using boost::accumulators::accumulator_set;
145 using boost::accumulators::left;
146 using boost::accumulators::quantile_probability;
147 using boost::accumulators::right;
148 using boost::accumulators::stats;
149 using boost::accumulators::tag::tail;
150 using boost::accumulators::tag::tail_quantile;
154 size_t cache_size = M;
156 accumulator_set<double, stats<tail_quantile<left> > >
157 acc_left(tail<left>::cache_size = cache_size);
158 accumulator_set<double, stats<tail_quantile<right> > >
159 acc_right(tail<right>::cache_size = cache_size);
161 for (
int i = 0; i < M; i++) {
166 Eigen::VectorXd q(probs.size());
167 for (
int i = 0; i < probs.size(); i++) {
169 q(i) = boost::accumulators::quantile(acc_left, quantile_probability=probs(i));
171 q(i) = boost::accumulators::quantile(acc_right, quantile_probability=probs(i));
176 Eigen::VectorXd autocorrelation(
const Eigen::VectorXd& x) {
177 std::vector<double> ac;
178 std::vector<double>
sample(x.size());
179 for (
int i = 0; i < x.size(); i++)
183 Eigen::VectorXd ac2(ac.size());
184 for (
int i = 0; i < ac.size(); i++)
189 Eigen::VectorXd autocovariance(
const Eigen::VectorXd& x) {
190 std::vector<double> ac;
191 std::vector<double>
sample(x.size());
192 for (
int i = 0; i < x.size(); i++)
196 Eigen::VectorXd ac2(ac.size());
197 for (
int i = 0; i < ac.size(); i++)
217 double effective_sample_size(
const Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> &
samples) {
218 int chains = samples.size();
221 int n_samples =
samples(0).size();
222 for (
int chain = 1; chain <
chains; chain++) {
226 Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> acov(chains);
227 for (
int chain = 0; chain <
chains; chain++) {
228 acov(chain) = autocovariance(
samples(chain));
231 Eigen::VectorXd chain_mean(chains);
232 Eigen::VectorXd chain_var(chains);
233 for (
int chain = 0; chain <
chains; chain++) {
235 chain_mean(chain) = mean(
samples(chain));
236 chain_var(chain) = acov(chain)(0)*n_kept_samples/(n_kept_samples-1);
239 double mean_var = mean(chain_var);
240 double var_plus = mean_var*(n_samples-1)/n_samples;
242 var_plus += variance(chain_mean);
243 Eigen::VectorXd rho_hat_t(n_samples);
247 for (
int t = 1; (t < n_samples && rho_hat >= 0); t++) {
248 Eigen::VectorXd acov_t(chains);
249 for (
int chain = 0; chain <
chains; chain++) {
250 acov_t(chain) = acov(chain)(t);
252 rho_hat = 1 - (mean_var - mean(acov_t)) / var_plus;
254 rho_hat_t(t) = rho_hat;
257 double ess = chains * n_samples;
259 ess /= 1 + 2 * rho_hat_t.sum();
277 double split_potential_scale_reduction(
const Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> &samples) {
278 int chains = samples.size();
279 int n_samples =
samples(0).size();
280 for (
int chain = 1; chain <
chains; chain++) {
283 if (n_samples % 2 == 1)
285 int n = n_samples / 2;
287 Eigen::VectorXd split_chain_mean(2*chains);
288 Eigen::VectorXd split_chain_var(2*chains);
290 for (
int chain = 0; chain <
chains; chain++) {
291 split_chain_mean(2*chain) = mean(
samples(chain).topRows(n));
292 split_chain_mean(2*chain+1) = mean(
samples(chain).bottomRows(n));
294 split_chain_var(2*chain) = variance(
samples(chain).topRows(n));
295 split_chain_var(2*chain+1) = variance(
samples(chain).bottomRows(n));
299 double var_between = n * variance(split_chain_mean);
300 double var_within = mean(split_chain_var);
303 return sqrt((var_between/var_within + n-1)/n);
308 : param_names_(param_names) { }
311 : param_names_(stan_csv.header) {
312 if (stan_csv.
samples.rows() > 0)
317 return samples_.size();
321 return param_names_.size();
324 const Eigen::Matrix<std::string, Eigen::Dynamic, 1>&
param_names() {
329 return param_names_(j);
332 const int index(
const std::string& name) {
334 for (
int i = 0; i < param_names_.size(); i++)
335 if (param_names_(i) == name)
345 warmup_.setConstant(warmup);
353 return warmup_(chain);
357 return samples_(chain).rows();
362 for (
int chain = 0; chain <
num_chains(); chain++)
373 for (
int chain = 0; chain <
num_chains(); chain++)
379 const Eigen::MatrixXd&
sample) {
381 throw std::invalid_argument(
"add(chain,sample): number of columns in sample does not match chains");
386 Eigen::Matrix<Eigen::MatrixXd, Eigen::Dynamic, 1> samples_copy(
num_chains());
388 for (
int i = 0; i < n; i++) {
389 samples_copy(i) = samples_(i);
390 warmup_copy(i) = warmup_(i);
393 samples_.resize(chain+1);
394 warmup_.resize(chain+1);
395 for (
int i = 0; i < n; i++) {
396 samples_(i) = samples_copy(i);
397 warmup_(i) = warmup_copy(i);
399 for (
int i = n; i < chain+1; i++) {
400 samples_(i) = Eigen::MatrixXd(0,
num_params());
404 int row = samples_(chain).rows();
405 Eigen::MatrixXd new_samples(row+sample.rows(),
num_params());
406 new_samples << samples_(chain), sample;
407 samples_(chain) = new_samples;
411 if (sample.rows() == 0)
414 throw std::invalid_argument(
"add(sample): number of columns in sample does not match chains");
420 throw std::invalid_argument(
"add(stan_csv): number of columns in sample does not match chains");
421 if (!param_names_.cwiseEqual(stan_csv.
header).all()) {
422 throw std::invalid_argument(
"add(stan_csv): header does not match chain's header");
436 for (
int chain = 0; chain <
num_chains(); chain++) {
438 s.middleRows(start,n) = samples_(chain).col(index).bottomRows(n);
444 Eigen::VectorXd
samples(
const int chain,
const std::string& name) {
448 Eigen::VectorXd
samples(
const std::string& name) {
453 return mean(
samples(chain,index));
460 double mean(
const int chain,
const std::string& name) {
461 return mean(chain,
index(name));
464 double mean(
const std::string& name) {
465 return mean(
index(name));
469 return sd(
samples(chain,index));
476 double sd(
const int chain,
const std::string& name) {
477 return sd(chain,
index(name));
480 double sd(
const std::string& name) {
481 return sd(
index(name));
485 return variance(
samples(chain,index));
489 return variance(
samples(index));
492 double variance(
const int chain,
const std::string& name) {
493 return variance(chain,
index(name));
497 return variance(
index(name));
500 double covariance(
const int chain,
const int index1,
const int index2) {
508 double covariance(
const int chain,
const std::string& name1,
const std::string& name2) {
509 return covariance(chain,
index(name1),
index(name2));
512 double covariance(
const std::string& name1,
const std::string& name2) {
513 return covariance(
index(name1),
index(name2));
516 double correlation(
const int chain,
const int index1,
const int index2) {
524 double correlation(
const int chain,
const std::string& name1,
const std::string& name2) {
525 return correlation(chain,
index(name1),
index(name2));
528 double correlation(
const std::string& name1,
const std::string& name2) {
529 return correlation(
index(name1),
index(name2));
533 return quantile(
samples(chain,index), prob);
537 return quantile(
samples(index), prob);
540 double quantile(
const int chain,
const std::string& name,
const double prob) {
541 return quantile(chain,
index(name), prob);
544 double quantile(
const std::string& name,
const double prob) {
545 return quantile(
index(name), prob);
548 Eigen::VectorXd
quantiles(
const int chain,
const int index,
const Eigen::VectorXd& probs) {
549 return quantiles(
samples(chain,index), probs);
553 return quantiles(
samples(index), probs);
556 Eigen::VectorXd quantiles(
const int chain,
557 const std::string& name,
const Eigen::VectorXd& probs) {
558 return quantiles(chain,
index(name), probs);
561 Eigen::VectorXd
quantiles(
const std::string& name,
const Eigen::VectorXd& probs) {
562 return quantiles(
index(name), probs);
566 double low_prob = (1-prob)/2;
567 double high_prob = 1-low_prob;
569 Eigen::Vector2d interval;
570 interval << quantile(chain,index,low_prob), quantile(chain,index,high_prob);
575 double low_prob = (1-prob)/2;
576 double high_prob = 1-low_prob;
578 Eigen::Vector2d interval;
579 interval << quantile(index,low_prob), quantile(index,high_prob);
584 const std::string& name,
const double prob) {
593 return autocorrelation(
samples(chain, index));
597 return autocorrelation(chain,
index(name));
601 return autocovariance(
samples(chain,index));
605 return autocovariance(chain,
index(name));
611 for (
int chain = 0; chain <
num_chains(); chain++) {
614 return effective_sample_size(samples);
618 return effective_sample_size(
index(name));
623 for (
int chain = 0; chain <
num_chains(); chain++) {
626 return split_potential_scale_reduction(samples);
630 return split_potential_scale_reduction(
index(name));