Stan  1.3
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
chains.hpp
Go to the documentation of this file.
1 #ifndef __STAN__MCMC__CHAINS_HPP__
2 #define __STAN__MCMC__CHAINS_HPP__
3 
4 #include <algorithm>
5 #include <cmath>
6 #include <iostream>
7 #include <map>
8 #include <stdexcept>
9 #include <string>
10 #include <sstream>
11 #include <utility>
12 #include <vector>
13 #include <fstream>
14 #include <cstdlib>
15 
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>
24 
25 
26 #include <boost/random/uniform_int_distribution.hpp>
27 #include <boost/random/additive_combine.hpp>
28 
29 #include <stan/math/matrix.hpp>
33 
35 
36 namespace stan {
37 
38  namespace mcmc {
39 
54  template <typename RNG = boost::random::ecuyer1988>
55  class chains {
56  private:
57  Eigen::Matrix<std::string, Eigen::Dynamic, 1> param_names_;
58  Eigen::Matrix<Eigen::MatrixXd, Eigen::Dynamic, 1> samples_;
59  Eigen::VectorXi warmup_;
60 
61  double mean(const Eigen::VectorXd& x) {
62  return (x.array() / x.size()).sum();
63  }
64 
65  double variance(const Eigen::VectorXd& x) {
66  double m = mean(x);
67  return ((x.array() - m) / std::sqrt((x.size() - 1.0))).square().sum();
68  }
69 
70  double sd(const Eigen::VectorXd& x) {
71  return std::sqrt(variance(x));
72  }
73 
74 
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;
83 
84  accumulator_set<double, stats<covariance<double, covariate1> > > acc;
85 
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));
89 
90  return boost::accumulators::covariance(acc) * M / (M-1);
91  }
92 
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;
101 
102  accumulator_set<double, stats<variance, covariance<double, covariate1> > > acc_xy;
103  accumulator_set<double, stats<variance> > acc_y;
104 
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));
108  acc_y(y(i));
109  }
110 
111  double cov = boost::accumulators::covariance(acc_xy);
112  if (cov > -1e-8 && cov < 1e-8)
113  return cov;
115  }
116 
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;
125  double M = x.rows();
126  //size_t cache_size = std::min(prob, 1-prob)*M + 2;
127  size_t cache_size = M;
128 
129  if (prob < 0.5) {
130  accumulator_set<double, stats<tail_quantile<left> > >
131  acc(tail<left>::cache_size = cache_size);
132  for (int i = 0; i < M; i++)
133  acc(x(i));
134  return boost::accumulators::quantile(acc, quantile_probability=prob);
135  }
136  accumulator_set<double, stats<tail_quantile<right> > >
137  acc(tail<right>::cache_size = cache_size);
138  for (int i = 0; i < M; i++)
139  acc(x(i));
140  return boost::accumulators::quantile(acc, quantile_probability=prob);
141  }
142 
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;
151  double M = x.rows();
152 
153  //size_t cache_size = M/2 + 2;
154  size_t cache_size = M;
155 
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);
160 
161  for (int i = 0; i < M; i++) {
162  acc_left(x(i));
163  acc_right(x(i));
164  }
165 
166  Eigen::VectorXd q(probs.size());
167  for (int i = 0; i < probs.size(); i++) {
168  if (probs(i) < 0.5)
169  q(i) = boost::accumulators::quantile(acc_left, quantile_probability=probs(i));
170  else
171  q(i) = boost::accumulators::quantile(acc_right, quantile_probability=probs(i));
172  }
173  return q;
174  }
175 
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++)
180  sample[i] = x(i);
182 
183  Eigen::VectorXd ac2(ac.size());
184  for (int i = 0; i < ac.size(); i++)
185  ac2(i) = ac[i];
186  return ac2;
187  }
188 
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++)
193  sample[i] = x(i);
195 
196  Eigen::VectorXd ac2(ac.size());
197  for (int i = 0; i < ac.size(); i++)
198  ac2(i) = ac[i];
199  return ac2;
200  }
201 
217  double effective_sample_size(const Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> &samples) {
218  int chains = samples.size();
219 
220  // need to generalize to each jagged samples per chain
221  int n_samples = samples(0).size();
222  for (int chain = 1; chain < chains; chain++) {
223  n_samples = std::min(n_samples, int(samples(chain).size()));
224  }
225 
226  Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> acov(chains);
227  for (int chain = 0; chain < chains; chain++) {
228  acov(chain) = autocovariance(samples(chain));
229  }
230 
231  Eigen::VectorXd chain_mean(chains);
232  Eigen::VectorXd chain_var(chains);
233  for (int chain = 0; chain < chains; chain++) {
234  double n_kept_samples = num_kept_samples(chain);
235  chain_mean(chain) = mean(samples(chain));
236  chain_var(chain) = acov(chain)(0)*n_kept_samples/(n_kept_samples-1);
237  }
238 
239  double mean_var = mean(chain_var);
240  double var_plus = mean_var*(n_samples-1)/n_samples;
241  if (chains > 1)
242  var_plus += variance(chain_mean);
243  Eigen::VectorXd rho_hat_t(n_samples);
244  rho_hat_t.setZero();
245  double rho_hat = 0;
246  int max_t = 0;
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);
251  }
252  rho_hat = 1 - (mean_var - mean(acov_t)) / var_plus;
253  if (rho_hat >= 0)
254  rho_hat_t(t) = rho_hat;
255  max_t = t;
256  }
257  double ess = chains * n_samples;
258  if (max_t > 1) {
259  ess /= 1 + 2 * rho_hat_t.sum();
260  }
261  return ess;
262  }
263 
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++) {
281  n_samples = std::min(n_samples, int(samples(chain).size()));
282  }
283  if (n_samples % 2 == 1)
284  n_samples--;
285  int n = n_samples / 2;
286 
287  Eigen::VectorXd split_chain_mean(2*chains);
288  Eigen::VectorXd split_chain_var(2*chains);
289 
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));
293 
294  split_chain_var(2*chain) = variance(samples(chain).topRows(n));
295  split_chain_var(2*chain+1) = variance(samples(chain).bottomRows(n));
296  }
297 
298 
299  double var_between = n * variance(split_chain_mean);
300  double var_within = mean(split_chain_var);
301 
302  // rewrote [(n-1)*W/n + B/n]/W as (n-1+ B/W)/n
303  return sqrt((var_between/var_within + n-1)/n);
304  }
305 
306  public:
307  chains(const Eigen::Matrix<std::string, Eigen::Dynamic, 1>& param_names)
308  : param_names_(param_names) { }
309 
310  chains(const stan::io::stan_csv& stan_csv)
311  : param_names_(stan_csv.header) {
312  if (stan_csv.samples.rows() > 0)
313  add(stan_csv);
314  }
315 
316  inline const int num_chains() {
317  return samples_.size();
318  }
319 
320  inline const int num_params() {
321  return param_names_.size();
322  }
323 
324  const Eigen::Matrix<std::string, Eigen::Dynamic, 1>& param_names() {
325  return param_names_;
326  }
327 
328  const std::string& param_name(int j) {
329  return param_names_(j);
330  }
331 
332  const int index(const std::string& name) {
333  int index = -1;
334  for (int i = 0; i < param_names_.size(); i++)
335  if (param_names_(i) == name)
336  return i;
337  return index;
338  }
339 
340  void set_warmup(const int chain, const int warmup) {
341  warmup_(chain) = warmup;
342  }
343 
344  void set_warmup(const int warmup) {
345  warmup_.setConstant(warmup);
346  }
347 
348  const Eigen::VectorXi& warmup() {
349  return warmup_;
350  }
351 
352  const int warmup(const int chain) {
353  return warmup_(chain);
354  }
355 
356  const int num_samples(const int chain) {
357  return samples_(chain).rows();
358  }
359 
360  const int num_samples() {
361  int n = 0;
362  for (int chain = 0; chain < num_chains(); chain++)
363  n += num_samples(chain);
364  return n;
365  }
366 
367  const int num_kept_samples(const int chain) {
368  return num_samples(chain) - warmup(chain);
369  }
370 
371  const int num_kept_samples() {
372  int n = 0;
373  for (int chain = 0; chain < num_chains(); chain++)
374  n += num_kept_samples(chain);
375  return n;
376  }
377 
378  void add(const int chain,
379  const Eigen::MatrixXd& sample) {
380  if (sample.cols() != num_params())
381  throw std::invalid_argument("add(chain,sample): number of columns in sample does not match chains");
382  if (num_chains() == 0 || chain >= num_chains()) {
383  int n = num_chains();
384 
385  // Need this block for Windows. conservativeResize does not keep the references.
386  Eigen::Matrix<Eigen::MatrixXd, Eigen::Dynamic, 1> samples_copy(num_chains());
387  Eigen::VectorXi warmup_copy(num_chains());
388  for (int i = 0; i < n; i++) {
389  samples_copy(i) = samples_(i);
390  warmup_copy(i) = warmup_(i);
391  }
392 
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);
398  }
399  for (int i = n; i < chain+1; i++) {
400  samples_(i) = Eigen::MatrixXd(0, num_params());
401  warmup_(i) = 0;
402  }
403  }
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;
408  }
409 
410  void add(const Eigen::MatrixXd& sample) {
411  if (sample.rows() == 0)
412  return;
413  if (sample.cols() != num_params())
414  throw std::invalid_argument("add(sample): number of columns in sample does not match chains");
415  add(num_chains(), sample);
416  }
417 
418  void add(const stan::io::stan_csv& stan_csv) {
419  if (stan_csv.header.size() != num_params())
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");
423  }
424  add(stan_csv.samples);
425  if (stan_csv.metadata.save_warmup)
426  set_warmup(num_chains()-1, stan_csv.metadata.warmup);
427  }
428 
429  Eigen::VectorXd samples(const int chain, const int index) {
430  return samples_(chain).col(index).bottomRows(num_kept_samples(chain));
431  }
432 
433  Eigen::VectorXd samples(const int index) {
434  Eigen::VectorXd s(num_kept_samples());
435  int start = 0;
436  for (int chain = 0; chain < num_chains(); chain++) {
437  int n = num_kept_samples(chain);
438  s.middleRows(start,n) = samples_(chain).col(index).bottomRows(n);
439  start += n;
440  }
441  return s;
442  }
443 
444  Eigen::VectorXd samples(const int chain, const std::string& name) {
445  return samples(chain,index(name));
446  }
447 
448  Eigen::VectorXd samples(const std::string& name) {
449  return samples(index(name));
450  }
451 
452  double mean(const int chain, const int index) {
453  return mean(samples(chain,index));
454  }
455 
456  double mean(const int index) {
457  return mean(samples(index));
458  }
459 
460  double mean(const int chain, const std::string& name) {
461  return mean(chain, index(name));
462  }
463 
464  double mean(const std::string& name) {
465  return mean(index(name));
466  }
467 
468  double sd(const int chain, const int index) {
469  return sd(samples(chain,index));
470  }
471 
472  double sd(const int index) {
473  return sd(samples(index));
474  }
475 
476  double sd(const int chain, const std::string& name) {
477  return sd(chain, index(name));
478  }
479 
480  double sd(const std::string& name) {
481  return sd(index(name));
482  }
483 
484  double variance(const int chain, const int index) {
485  return variance(samples(chain,index));
486  }
487 
488  double variance(const int index) {
489  return variance(samples(index));
490  }
491 
492  double variance(const int chain, const std::string& name) {
493  return variance(chain, index(name));
494  }
495 
496  double variance(const std::string& name) {
497  return variance(index(name));
498  }
499 
500  double covariance(const int chain, const int index1, const int index2) {
501  return covariance(samples(chain,index1), samples(chain,index2));
502  }
503 
504  double covariance(const int index1, const int index2) {
505  return covariance(samples(index1), samples(index2));
506  }
507 
508  double covariance(const int chain, const std::string& name1, const std::string& name2) {
509  return covariance(chain, index(name1), index(name2));
510  }
511 
512  double covariance(const std::string& name1, const std::string& name2) {
513  return covariance(index(name1), index(name2));
514  }
515 
516  double correlation(const int chain, const int index1, const int index2) {
517  return correlation(samples(chain,index1),samples(chain,index2));
518  }
519 
520  double correlation(const int index1, const int index2) {
521  return correlation(samples(index1),samples(index2));
522  }
523 
524  double correlation(const int chain, const std::string& name1, const std::string& name2) {
525  return correlation(chain, index(name1), index(name2));
526  }
527 
528  double correlation(const std::string& name1, const std::string& name2) {
529  return correlation(index(name1), index(name2));
530  }
531 
532  double quantile(const int chain, const int index, const double prob) {
533  return quantile(samples(chain,index), prob);
534  }
535 
536  double quantile(const int index, const double prob) {
537  return quantile(samples(index), prob);
538  }
539 
540  double quantile(const int chain, const std::string& name, const double prob) {
541  return quantile(chain, index(name), prob);
542  }
543 
544  double quantile(const std::string& name, const double prob) {
545  return quantile(index(name), prob);
546  }
547 
548  Eigen::VectorXd quantiles(const int chain, const int index, const Eigen::VectorXd& probs) {
549  return quantiles(samples(chain,index), probs);
550  }
551 
552  Eigen::VectorXd quantiles(const int index, const Eigen::VectorXd& probs) {
553  return quantiles(samples(index), probs);
554  }
555 
556  Eigen::VectorXd quantiles(const int chain,
557  const std::string& name, const Eigen::VectorXd& probs) {
558  return quantiles(chain, index(name), probs);
559  }
560 
561  Eigen::VectorXd quantiles(const std::string& name, const Eigen::VectorXd& probs) {
562  return quantiles(index(name), probs);
563  }
564 
565  Eigen::Vector2d central_interval(const int chain, const int index, const double prob) {
566  double low_prob = (1-prob)/2;
567  double high_prob = 1-low_prob;
568 
569  Eigen::Vector2d interval;
570  interval << quantile(chain,index,low_prob), quantile(chain,index,high_prob);
571  return interval;
572  }
573 
574  Eigen::Vector2d central_interval(const int index, const double prob) {
575  double low_prob = (1-prob)/2;
576  double high_prob = 1-low_prob;
577 
578  Eigen::Vector2d interval;
579  interval << quantile(index,low_prob), quantile(index,high_prob);
580  return interval;
581  }
582 
583  Eigen::Vector2d central_interval(const int chain,
584  const std::string& name, const double prob) {
585  return central_interval(chain, index(name), prob);
586  }
587 
588  Eigen::Vector2d central_interval(const std::string& name, const double prob) {
589  return central_interval(index(name), prob);
590  }
591 
592  Eigen::VectorXd autocorrelation(const int chain, const int index) {
593  return autocorrelation(samples(chain, index));
594  }
595 
596  Eigen::VectorXd autocorrelation(const int chain, const std::string& name) {
597  return autocorrelation(chain, index(name));
598  }
599 
600  Eigen::VectorXd autocovariance(const int chain, const int index) {
601  return autocovariance(samples(chain,index));
602  }
603 
604  Eigen::VectorXd autocovariance(const int chain, const std::string& name) {
605  return autocovariance(chain, index(name));
606  }
607 
608  // FIXME: reimplement using autocorrelation.
609  double effective_sample_size(const int index) {
610  Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> samples(num_chains());
611  for (int chain = 0; chain < num_chains(); chain++) {
612  samples(chain) = this->samples(chain, index);
613  }
614  return effective_sample_size(samples);
615  }
616 
617  double effective_sample_size(const std::string& name) {
618  return effective_sample_size(index(name));
619  }
620 
622  Eigen::Matrix<Eigen::VectorXd, Eigen::Dynamic, 1> samples(num_chains());
623  for (int chain = 0; chain < num_chains(); chain++) {
624  samples(chain) = this->samples(chain, index);
625  }
626  return split_potential_scale_reduction(samples);
627  }
628 
629  double split_potential_scale_reduction(const std::string& name) {
630  return split_potential_scale_reduction(index(name));
631  }
632  };
633 
634  }
635 }
636 
637 
638 #endif
639 
640 
641 /*
642 
643 
644  pair<double,double> smallest_interval(size_t n,
645  double prob);
646 
647  double potential_scale_reduction(size_t n)
648 
649  double mcmc_error_mean(size_t n);
650 
651  void print(ostream&);
652 
653  ostream& operator<<(ostream&, const chains&);
654 */

     [ Stan Home Page ] © 2011–2013, Stan Development Team.