Stan  1.3
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/mcmc/util.hpp>
14 #include <stan/model/prob_grad.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  const std::vector<double>& params_r,
117  const std::vector<int>& params_i,
118  double epsilon=-1,
119  double epsilon_pm = 0.0,
120  bool epsilon_adapt = true,
121  double delta = 0.651,
122  double gamma = 0.05,
123  BaseRNG rand_int = BaseRNG(std::time(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.size() != model.num_params_r())
142  throw std::invalid_argument("hmc_base ctor: double params must match in size");
143  _x = params_r;
144  if (params_i.size() != model.num_params_i())
145  throw std::invalid_argument("hmc_base ctor: int params must match in size");
146  _z = params_i;
147  _logp = model.grad_log_prob(_x,_z,_g);
148  if (epsilon_adapt)
150  }
151 
152  virtual ~hmc_base() { }
153 
164  virtual void set_params(const std::vector<double>& x,
165  const std::vector<int>& z) {
166  if (x.size() != this->_x.size())
167  throw std::invalid_argument("hmc_base::set_params double params must match in size");
168  if (z.size() != this->_z.size())
169  throw std::invalid_argument("hmc_base::set_params int params must match in size");
170  this->_x = x;
171  this->_z = z;
172  this->_logp = this->_model.grad_log_prob(this->_x,this->_z,this->_g);
173  }
174 
186  void set_params_r(const std::vector<double>& x) {
187  if (x.size() != this->_model.num_params_r())
188  throw std::invalid_argument("x.size() must match num model params.");
189  this->_x = x;
190  this->_logp = this->_model.grad_log_prob(this->_x,this->_z,this->_g);
191  }
192 
193 
205  void set_params_i(const std::vector<int>& z) {
206  if (z.size() != this->_model.num_params_i())
207  throw std::invalid_argument("z.size() must match num params");
208  this->_z = z;
209  this->_logp = this->_model.grad_log_prob(this->_x,this->_z,this->_g);
210  }
211 
213  return this->_epsilon_pm != 0;
214  }
215 
224  virtual void adapt_off() {
225  if (!this->adapting()) return;
227  std::vector<double> result;
228  this->_da.xbar(result);
229  this->_epsilon = exp(result[0]);
230  }
231 
237  virtual void get_parameters(std::vector<double>& params) {
238  params.assign(1, this->_epsilon);
239  }
240 
241 
242 
243 
244 
245 
246  }; // class hmc_base
247 
248  }
249 }
250 
251 
252 #endif

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