Stan  1.3
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
adaptive_cdhmc.hpp
Go to the documentation of this file.
1 #ifndef __STAN__MCMC__ADAPTIVE_CDHMC_H__
2 #define __STAN__MCMC__ADAPTIVE_CDHMC_H__
3 
4 #include <ctime>
5 #include <cstddef>
6 #include <vector>
7 #include <boost/random/normal_distribution.hpp>
8 #include <boost/random/mersenne_twister.hpp>
9 #include <boost/random/variate_generator.hpp>
10 #include <boost/random/uniform_01.hpp>
11 
16 #include <stan/mcmc/util.hpp>
17 #include <stan/model/prob_grad.hpp>
18 
19 
20 namespace stan {
21 
22  namespace mcmc {
23 
42  private:
43  // Provides the target distribution we're trying to sample from
44  stan::model::prob_grad& _model;
45 
46  // The most recent setting of the real-valued parameters
47  std::vector<double> _x;
48  // The most recent setting of the discrete parameters
49  std::vector<int> _z;
50  // The most recent gradient with respect to the real parameters
51  std::vector<double> _g;
52  // The most recent log-likelihood
53  double _logp;
54 
55  // The step size used in the Hamiltonian simulation
56  double _epsilon;
57  // The number of steps used in the Hamiltonian simulation
58  unsigned int _L;
59  // The desired value of epsilon*L
60  double _epsilonL;
61  // The desired value of E[acceptance probability]
62  double _delta;
63 
64  boost::mt19937 _rand_int;
65  boost::variate_generator<boost::mt19937&, boost::normal_distribution<> > _rand_unit_norm;
66  boost::uniform_01<boost::mt19937&> _rand_uniform_01;
67 
68  // Class implementing Nesterov's primal-dual averaging
69  DualAverage _da;
70  // Gamma parameter for dual averaging.
71  inline static double da_gamma() { return 0.05; }
72 
73  public:
74 
82  void set_epsilon(double epsilon) {
83  _epsilon = epsilon;
84  _L = lround(_epsilonL / epsilon);
85  }
86 
110  double epsilonL,
111  double delta = 0.651,
112  double epsilon = -1,
113  unsigned int random_seed = static_cast<unsigned int>(std::time(0)))
114  : adaptive_sampler(epsilon < 0.0),
115  _model(model),
116  _x(model.num_params_r()),
117  _z(model.num_params_i()),
118  _g(model.num_params_r()),
119 
120  _epsilonL(epsilonL),
121  _delta(delta),
122 
123  _rand_int(random_seed),
124  _rand_unit_norm(_rand_int,
125  boost::normal_distribution<>()),
126  _rand_uniform_01(_rand_int),
127 
128  _da(da_gamma(), std::vector<double>(1, 0)) {
129  set_epsilon(_epsilon);
130  model.init(_x,_z);
131  _logp = model.grad_log_prob(_x,_z,_g);
132  if (_epsilon <= 0)
134  _da.setx0(std::vector<double>(1, log(_epsilon)));
135  }
136 
140  virtual ~adaptive_cdhmc() {
141  }
142 
153  virtual void set_params(const std::vector<double>& x,
154  const std::vector<int>& z) {
155  if (x.size() != _x.size())
156  throw std::invalid_argument("adaptive_cdhmc::set_params: double params must match in size");
157  if (z.size() != _z.size())
158  throw std::invalid_argument("adaptive_cdhmc::set_params: int params must match in size");
159  _x = x;
160  _z = z;
161  _logp = _model.grad_log_prob(_x,_z,_g);
162  }
163 
175  void set_params_r(const std::vector<double>& x) {
176  if (x.size() != _model.num_params_r())
177  throw std::invalid_argument("x.size() must match the number of parameters of the model.");
178  _x = x;
179  _logp = _model.grad_log_prob(_x,_z,_g);
180  }
181 
193  void set_params_i(const std::vector<int>& z) {
194  if (z.size() != _model.num_params_i())
195  throw std::invalid_argument("z.size() must match the number of parameters of the model.");
196  _z = z;
197  _logp = _model.grad_log_prob(_x,_z,_g);
198  }
199 
204  virtual void find_reasonable_parameters() {
205  _epsilon = 1;
206  std::vector<double> x = _x;
207  std::vector<double> m(_model.num_params_r());
208  for (size_t i = 0; i < m.size(); ++i)
209  m[i] = _rand_unit_norm();
210  std::vector<double> g = _g;
211  double lastlogp = _logp;
212  double logp = leapfrog(_model, _z, x, m, g, _epsilon);
213  double H = logp - lastlogp;
214  int direction = H > log(0.5) ? 1 : -1;
215  // fprintf(stderr, "epsilon = %f. initial logp = %f, lf logp = %f\n",
216  // _epsilon, lastlogp, logp);
217  while (1) {
218  x = _x;
219  g = _g;
220  for (size_t i = 0; i < m.size(); ++i)
221  m[i] = _rand_unit_norm();
222  logp = leapfrog(_model, _z, x, m, g, _epsilon);
223  H = logp - lastlogp;
224 // fprintf(stderr, "epsilon = %f. initial logp = %f, lf logp = %f\n",
225 // _epsilon, lastlogp, logp);
226  if ((direction == 1) && (H < log(0.5)))
227  break;
228  else if ((direction == -1) && (H > log(0.5)))
229  break;
230  else
231  _epsilon = direction == 1 ? 2 * _epsilon : 0.5 * _epsilon;
232  }
233  set_epsilon(_epsilon);
234  }
235 
241  virtual sample next_impl() {
242  // Gibbs for discrete
243  std::vector<double> probs;
244  for (size_t m = 0; m < _model.num_params_i(); ++m) {
245  probs.resize(0);
246  for (int k = _model.param_range_i_lower(m);
247  k < _model.param_range_i_upper(m);
248  ++k)
249  probs.push_back(_model.log_prob_star(m,k,_x,_z));
250  _z[m] = sample_unnorm_log(probs,_rand_uniform_01);
251  }
252 
253  // HMC for continuous
254  std::vector<double> m(_model.num_params_r());
255  for (size_t i = 0; i < m.size(); ++i)
256  m[i] = _rand_unit_norm();
257  double H = -(stan::math::dot_self(m) / 2.0) + _logp;
258 
259  std::vector<double> g_new(_g);
260  std::vector<double> x_new(_x);
261  double logp_new = -1e100;
262  for (unsigned int l = 0; l < _L; ++l)
263  logp_new = leapfrog(_model, _z, x_new, m, g_new, _epsilon);
264  nfevals_plus_eq(_L);
265 
266  double H_new = -(stan::math::dot_self(m) / 2.0) + logp_new;
267  double dH = H_new - H;
268  if (_rand_uniform_01() < exp(dH)) {
269  _x = x_new;
270  _g = g_new;
271  _logp = logp_new;
272  }
273 
274  // Now we just have to update epsilon, if adaptation is on.
275  double adapt_stat = stan::math::min(1, exp(dH));
276  if (adapt_stat != adapt_stat)
277  adapt_stat = 0;
278  if (adapting()) {
279  double adapt_g = adapt_stat - _delta;
280  std::vector<double> gvec(1, -adapt_g);
281  std::vector<double> result;
282  _da.update(gvec, result);
283  set_epsilon(exp(result[0]));
284  }
285  std::vector<double> result;
286  _da.xbar(result);
287 // fprintf(stderr, "xbar = %f\n", exp(result[0]));
288  double avg_eta = 1.0 / n_steps();
289  update_mean_stat(avg_eta,adapt_stat);
290 
291  mcmc::sample s(_x, _z, _logp);
292  return s;
293  }
294 
302  virtual void adapt_off() {
304  std::vector<double> result;
305  _da.xbar(result);
306  set_epsilon(exp(result[0]));
307  }
308 
314  virtual void get_parameters(std::vector<double>& params) {
315  params.assign(1, _epsilon);
316  }
317 
318  };
319 
320  }
321 
322 }
323 
324 #endif

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