Stan  1.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
hmc_base.hpp
Go to the documentation of this file.
1 #ifndef __STAN__MCMC__HMC_BASE_H__
2 #define __STAN__MCMC__HMC_BASE_H__
3 
4 #include <ctime>
5 
6 #include <boost/random/normal_distribution.hpp>
7 #include <boost/random/mersenne_twister.hpp>
8 #include <boost/random/variate_generator.hpp>
9 #include <boost/random/uniform_01.hpp>
10 
13 #include <stan/model/prob_grad.hpp>
14 #include <stan/mcmc/util.hpp>
15 
16 
17 namespace stan {
18 
19  namespace mcmc {
20 
21  template <class BaseRNG = boost::mt19937>
22  class hmc_base : public adaptive_sampler {
23 
24  protected:
25 
26  // model from which to sample
27  stan::model::prob_grad& _model; // model to sample
28 
29  double _epsilon; // step size for Hamiltonian sim
30  double _epsilon_pm; // +/- around epsilon
31  double _epsilon_last; // last value of epsilon used
32  bool _epsilon_adapt; // true if adapt(ed) epsilon
33 
34  const double _delta; // target E[accept]
35  const double _gamma; // tuning param for dual avg
36  DualAverage _da; // impl of dual avg adaptation
37 
38  BaseRNG _rand_int; // base random number generator
39 
40  boost::variate_generator<BaseRNG&,
41  boost::normal_distribution<> > _rand_unit_norm;
42  // normal(0,1) RNG
43 
44  boost::uniform_01<BaseRNG&> _rand_uniform_01;
45  // uniform(0,1) RNG
46 
47  std::vector<double> _x; // most recent real params
48  std::vector<int> _z; // most recent discrete params
49  std::vector<double> _g; // most recent gradient
50  double _logp; // most recent log prob
51 
56  virtual void find_reasonable_parameters() {
57  this->_epsilon = 1.0;
58  std::vector<double> x = this->_x;
59  std::vector<double> m(this->_model.num_params_r());
60  for (size_t i = 0; i < m.size(); ++i)
61  m[i] = this->_rand_unit_norm();
62  std::vector<double> g = this->_g;
63  double lastlogp = this->_logp;
64  double logp = leapfrog(this->_model, this->_z, x, m, g, this->_epsilon);
65  double H = logp - lastlogp;
66  int direction = H > log(0.5) ? 1 : -1;
67  while (1) {
68  x = this->_x;
69  g = this->_g;
70  for (size_t i = 0; i < m.size(); ++i)
71  m[i] = this->_rand_unit_norm();
72  logp = leapfrog(this->_model, this->_z, x, m, g, this->_epsilon);
73  H = logp - lastlogp;
74  if ((direction == 1) && !(H > log(0.5)))
75  break;
76  else if ((direction == -1) && !(H < log(0.5)))
77  break;
78  else
79  this->_epsilon = ( (direction == 1)
80  ? 2.0 * this->_epsilon
81  : 0.5 * this->_epsilon );
82 
83  if (this->_epsilon > 1e300)
84  throw std::runtime_error("Posterior is improper. Please check your model.");
85  if (this->_epsilon == 0)
86  throw std::runtime_error("No acceptably small step size could be found. Perhaps the posterior is not continuous?");
87  }
88  }
89 
90  void adaptation_init(double epsilon_scale) {
91  if (this->adapting())
92  this->_da.setx0(std::vector<double>(1, log(epsilon_scale * _epsilon)));
93  }
94 
95  public:
96 
116  double epsilon=-1,
117  double epsilon_pm = 0.0,
118  bool epsilon_adapt = true,
119  double delta = 0.651,
120  double gamma = 0.05,
121  BaseRNG rand_int = BaseRNG(std::time(0)),
122  const std::vector<double>* params_r = 0,
123  const std::vector<int>* params_i = 0)
124  : adaptive_sampler(epsilon_adapt),
125  _model(model),
126  _epsilon(epsilon),
127  _epsilon_pm(epsilon_pm),
129  _epsilon_adapt(epsilon_adapt),
130  _delta(delta),
131  _gamma(gamma),
132  _da(gamma, std::vector<double>(1, 0.0)),
133  _rand_int(rand_int),
134  _rand_unit_norm(_rand_int, boost::normal_distribution<>()),
136  _x(model.num_params_r()),
137  _z(model.num_params_i()),
138  _g(model.num_params_r())
139  {
140  model.init(_x,_z);
141  if (params_r) {
142  if (params_r->size() != model.num_params_r())
143  throw std::invalid_argument("hmc_base ctor: double params must match in size");
144  _x = *params_r;
145  }
146  if (params_i) {
147  if (params_i->size() != model.num_params_i())
148  throw std::invalid_argument("hmc_base ctor: int params must match in size");
149  _z = *params_i;
150  }
151  _logp = model.grad_log_prob(_x,_z,_g);
152  if (epsilon_adapt)
154  }
155 
156  virtual ~hmc_base() { }
157 
168  virtual void set_params(const std::vector<double>& x,
169  const std::vector<int>& z) {
170  if (x.size() != this->_x.size())
171  throw std::invalid_argument("hmc_base::set_params double params must match in size");
172  if (z.size() != this->_z.size())
173  throw std::invalid_argument("hmc_base::set_params int params must match in size");
174  this->_x = x;
175  this->_z = z;
176  this->_logp = this->_model.grad_log_prob(this->_x,this->_z,this->_g);
177  }
178 
190  void set_params_r(const std::vector<double>& x) {
191  if (x.size() != this->_model.num_params_r())
192  throw std::invalid_argument("x.size() must match num model params.");
193  this->_x = x;
194  this->_logp = this->_model.grad_log_prob(this->_x,this->_z,this->_g);
195  }
196 
197 
209  void set_params_i(const std::vector<int>& z) {
210  if (z.size() != this->_model.num_params_i())
211  throw std::invalid_argument("z.size() must match num params");
212  this->_z = z;
213  this->_logp = this->_model.grad_log_prob(this->_x,this->_z,this->_g);
214  }
215 
217  return this->_epsilon_pm != 0;
218  }
219 
228  virtual void adapt_off() {
229  if (!this->adapting()) return;
231  std::vector<double> result;
232  this->_da.xbar(result);
233  this->_epsilon = exp(result[0]);
234  }
235 
241  virtual void get_parameters(std::vector<double>& params) {
242  params.assign(1, this->_epsilon);
243  }
244 
245 
246 
247 
248 
249 
250  }; // class hmc_base
251 
252  }
253 }
254 
255 
256 #endif

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