ADMB Documentation  -a65f1c97
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
hmc.cpp
Go to the documentation of this file.
1 
10 #include "admodel.h"
11 #ifndef OPT_LIB
12 #include <cassert>
13 #endif
14 #include<ctime>
15 
16 void read_empirical_covariance_matrix(int nvar, const dmatrix& S, const adstring& prog_name);
17 void read_hessian_matrix_and_scale1(int nvar, const dmatrix& _SS, double s, int mcmc2_flag);
18 
19 void function_minimizer::shmc_mcmc_routine(int nmcmc,int iseed0,double dscale,
20  int restart_flag) {
21  cerr << endl << endl << "Option -hmc is deprecated, please use option -nuts" << endl << endl;
22  if (nmcmc<=0)
23  {
24  cerr << endl << "Error: Negative iterations for MCMC not meaningful" << endl;
25  ad_exit(1);
26  }
27 
28  uostream * pofs_psave=NULL;
29  if (mcmc2_flag==1)
30  {
32  }
35  int nvar_re=initial_params::nvarcalc();
36  int nvar=initial_params::nvarcalc(); // get the number of active parameters
37  if (mcmc2_flag==0)
38  {
40  nvar=initial_params::nvarcalc(); // get the number of active parameters
41  }
43 
44  independent_variables parsave(1,nvar_re);
45  // dvector x(1,nvar);
46  // initial_params::xinit(x);
47  // dvector pen_vector(1,nvar);
48  // {
49  // initial_params::reset(dvar_vector(x),pen_vector);
50  // }
52 
53  int old_Hybrid_bounded_flag=-1;
54  int on,nopt = 0;
55 
57  // Step size. If not specified, will be adapted. If specified must be >0
58  // and will not be adapted.
59  double eps=0.1;
60  double _eps=-1.0;
61  int useDA=1; // whether to adapt step size
62  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-hyeps",nopt))>-1)
63  {
64  if (!nopt) // not specified means to adapt, using function below to find reasonable one
65  {
66  cerr << "Warning: No step size given after -hyeps, ignoring" << endl;
67  useDA=1;
68  }
69  else // read in specified value and do not adapt
70  {
71  istringstream ist(ad_comm::argv[on+1]);
72  ist >> _eps;
73  if (_eps<=0)
74  {
75  cerr << "Error: step size (-hyeps argument) needs positive number";
76  ad_exit(1);
77  }
78  else
79  {
80  eps=_eps;
81  useDA=0;
82  }
83  }
84  }
85  // Chain number -- for console display purposes only
86  int chain=1;
87  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-chain",nopt))>-1) {
88  if (nopt) {
89  int iii=atoi(ad_comm::argv[on+1]);
90  if (iii <1) {
91  cerr << "Error: chain must be >= 1" << endl;
92  ad_exit(1);
93  } else {
94  chain=iii;
95  }
96  }
97  }
98  // console refresh rate
99  int refresh=1;
100  if(nmcmc>10) refresh = (int)floor(nmcmc/10);
101  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-refresh",nopt))>-1) {
102  int iii=atoi(ad_comm::argv[on+1]);
103  if (iii < -1) {
104  cerr << iii << endl;
105  cerr << "Error: refresh must be >= -1. Use -1 for no refresh or positive integer for rate." << endl;
106  ad_exit(1);
107  } else {
108  refresh=iii;
109  }
110  }
111 
112  // Number of leapfrog steps. Defaults to 10.
113  int L=10;
114  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-hynstep",nopt))>-1)
115  {
116  if (nopt)
117  {
118  int iii = atoi(ad_comm::argv[on+1]);
119  if (iii < 1 )
120  {
121  cerr << "Error: hynstep argument must be integer > 0 " << endl;
122  ad_exit(1);
123  }
124  L = iii;
125  }
126  }
127 
128  // Number of warmup samples if using adaptation of step size. Defaults to
129  // half of iterations.
130  int nwarmup= (int)nmcmc/2;
131  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-nwarmup",nopt))>-1)
132  {
133  if (nopt)
134  {
135  int iii=atoi(ad_comm::argv[on+1]);
136  if (iii <=0 || iii > nmcmc)
137  {
138  cerr << "Error: nwarmup must be 0 < nwarmup < nmcmc" << endl;
139  ad_exit(1);
140  }
141  else
142  {
143  nwarmup=iii;
144  }
145  }
146  }
147 
148  // Target acceptance rate for step size adaptation. Must be
149  // 0<adapt_delta<1. Defaults to 0.8.
150  double adapt_delta=0.8; // target acceptance rate specified by the user
151  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-adapt_delta",nopt))>-1)
152  {
153  if (nopt)
154  {
155  istringstream ist(ad_comm::argv[on+1]);
156  double _adapt_delta;
157  ist >> _adapt_delta;
158  if (_adapt_delta < 0 || _adapt_delta > 1 )
159  {
160  cerr << "Error: adapt_delta must be between 0 and 1"
161  " using default of 0.8" << endl;
162  }
163  else
164  {
165  adapt_delta=_adapt_delta;
166  }
167  }
168  }
169  // Use diagnoal covariance (identity mass matrix)
170  int diag_option=0;
171  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcdiag"))>-1)
172  {
173  diag_option=1;
174  cout << " Setting covariance matrix to diagonal with entries " << dscale
175  << endl;
176  }
177  // Restart chain from previous run?
178  int mcrestart_flag=option_match(ad_comm::argc,ad_comm::argv,"-mcr");
179  if(mcrestart_flag > -1){
180  cerr << endl << "Error: -mcr option not implemented for HMC" << endl;
181  ad_exit(1);
182  }
183 
184  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcec"))>-1)
185  {
186  cerr << endl << "Error: -mcec option not yet implemented with HMC" << endl;
187  ad_exit(1);
188  // use_empirical_flag=1;
189  // read_empirical_covariance_matrix(nvar,S,ad_comm::adprogram_name);
190  }
191 
192  // Prepare the mass matrix for use. Depends on many factors below.
193  dmatrix S(1,nvar,1,nvar);
194  dvector old_scale(1,nvar);
195  // int old_nvar;
196  // Need to grab old_scale values still, since it is scaled below
197  read_covariance_matrix(S,nvar,old_Hybrid_bounded_flag,old_scale);
198  if (diag_option) // set covariance to be diagonal
199  {
200  S.initialize();
201  for (int i=1;i<=nvar;i++)
202  {
203  S(i,i)=dscale;
204  }
205  }
206  diagonal_metric_flag=0; // global flag used in functions to do more efficient calculations
207 
208  // How much to thin, for now fixed at 1.
209  if ( (on=option_match(ad_comm::argc,ad_comm::argv,"-mcsave"))>-1)
210  {
211  cerr << "Option -mcsave does not currently work with HMC -- every iteration is saved" << endl;
212  ad_exit(1);
213  }
215 
216 
218  pofs_psave=
219  new uostream((char*)(ad_comm::adprogram_name + adstring(".psv")));
220  if (!pofs_psave|| !(*pofs_psave))
221  {
222  cerr << "Error trying to open file" <<
224  ad_exit(1);
225  }
226  if (mcrestart_flag == -1 )
227  {
228  (*pofs_psave) << nvar;
229  }
230  // need to rescale the hessian
231  // get the current scale
232  dvector x0(1,nvar);
233  dvector current_scale(1,nvar);
235  int mctmp=initial_params::mc_phase;
237  initial_params::stddev_scale(current_scale,x0);
239  // cout << "old scale=" << old_scale << endl;
240  // cout << "current scale=" << current_scale << endl;
241  // cout << "S before=" << S << endl;
242  // I think this is only needed if mcmc2 is used??
243  // for (int i=1;i<=nvar;i++)
244  // {
245  // for (int j=1;j<=nvar;j++)
246  // {
247  // S(i,j)*=old_scale(i)*old_scale(j);
248  // }
249  // }
250  if(diag_option){
251  for (int i=1;i<=nvar;i++)
252  {
253  for (int j=1;j<=nvar;j++)
254  {
255  S(i,j)*=current_scale(i)*current_scale(j);
256  }
257  }
258  }
259  // cout << "S after=" << S << endl;
261  if (mcmc2_flag==0)
262  {
264  }
265  // Setup random number generator, based on seed passed
266  int iseed=2197;
267  if (iseed0) iseed=iseed0;
268  random_number_generator rng(iseed);
271 
272  // Dual averaging components
273  dvector epsvec(1,nmcmc+1), epsbar(1,nmcmc+1), Hbar(1,nmcmc+1);
274  epsvec.initialize(); epsbar.initialize(); Hbar.initialize();
275  double time_warmup=0;
276  double time_total=0;
277  std::clock_t start = clock();
278  time_t now = time(0);
279  tm* localtm = localtime(&now);
280  cout << endl << "Starting static HMC for model '" << ad_comm::adprogram_name <<
281  "' at " << asctime(localtm);
282  // write sampler parameters
283  ofstream adaptation("adaptation.csv", ios::trunc);
284  adaptation << "accept_stat__,stepsize__,int_time__,energy__,lp__" << endl;
285 
286  // Declare and initialize the variables needed for the algorithm
287  dmatrix chd = choleski_decomp(S); // cholesky decomp of mass matrix
288  dvector y(1,nvar); // unbounded parameters
289  y.initialize();
290  // transformed params
291  independent_variables z(1,nvar); z=chd*y;
292  dvector gr(1,nvar); // gradients in unbounded space
293  // Need to run this to fill gr with current gradients and initial NLL.
294  double nllbegin=get_hybrid_monte_carlo_value(nvar,z,gr);
295  if(std::isnan(nllbegin)){
296  cerr << "Starting MCMC trajectory at NaN -- something is wrong!" << endl;
297  ad_exit(1);
298  }
299  // initial rotated gradient
300  dvector gr2(1,nvar); gr2=gr*chd;
301  dvector p(1,nvar); // momentum vector
302  p.fill_randn(rng);
303  // Copy initial value to parsave in case first trajectory rejected
304  initial_params::copy_all_values(parsave,1.0);
305  double iaccept=0.0;
306  // The gradient and params at beginning of trajectory, in case rejected.
307  dvector gr2begin(1,nvar); gr2begin=gr2;
308  dvector ybegin(1,nvar); ybegin=y;
309  double nll=nllbegin;
310  // if(useDA){
311  // eps=find_reasonable_stepsize(nvar,y,p,chd);
312  // epsvec(1)=eps; epsbar(1)=eps; Hbar(1)=0;
313  // }
314  double mu=log(10*eps);
315 
316  // Start of MCMC chain
317  for (int is=1;is<=nmcmc;is++) {
318  // Random momentum for next iteration, only affects Ham values
319  p.fill_randn(rng);
320  double H0=nll+0.5*norm2(p);
321 
322  // Generate trajectory
323  int divergence=0;
324  for (int i=1;i<=L;i++) {
325  // leapfrog updates gr, p, y, and gr2 by reference
326  nll=leapfrog(nvar, gr, chd, eps, p, y, gr2);
327  // Break trajectory early if a divergence occurs to save computation
328  if(std::isnan(nll)){
329  divergence=1; break;
330  }
331  } // end of trajectory
332 
333  // Test whether to accept the proposed state
334  double Ham=nll+0.5*norm2(p); // Update Hamiltonian for proposed set
335  double alpha=min(1.0, exp(H0-Ham)); // acceptance ratio
336  double rr=randu(rng); // Runif(1)
337  if (rr<alpha && !divergence){ // accept
338  iaccept++;
339  // Update for next iteration: params, Hamiltonian and gr2
340  ybegin=y;
341  gr2begin=gr2;
342  nllbegin=nll;
343  initial_params::copy_all_values(parsave,1.0);
344  } else {
345  // Reject and don't update anything to reuse initials for next trajectory
346  y=ybegin;
347  gr2=gr2begin;
348  nll=nllbegin;
349  }
350  // Save parameters to psv file, duplicated if rejected
351  (*pofs_psave) << parsave;
352 
353  // Adaptation of step size (eps).
354  if(useDA && is <= nwarmup){
355  eps=adapt_eps(is, is, eps, alpha, adapt_delta, mu, epsvec, epsbar, Hbar);
356  }
357  adaptation << alpha << "," << eps << "," << eps*L << "," << H0 << "," << -nll << endl;
358  if(is ==nwarmup) time_warmup = static_cast<double>(std::clock()-start) / CLOCKS_PER_SEC;
359  print_mcmc_progress(is, nmcmc, nwarmup, chain, refresh);
360  } // end of MCMC chain
361 
362  // This final ratio should closely match adapt_delta
363  if(useDA){
364  cout << "Final acceptance ratio=" << iaccept/nmcmc << " and target is " << adapt_delta<<endl;
365  cout << "Final step size=" << eps << "; after " << nwarmup << " warmup iterations"<< endl;
366  } else {
367  cout << "Final acceptance ratio=" << iaccept/nmcmc << endl;
368  }
369 
370  time_total = static_cast<double>(std::clock() - start) / CLOCKS_PER_SEC;
371  print_mcmc_timing(time_warmup, time_total, chain);
372 
373  // I assume this closes the connection to the file??
374  if (pofs_psave)
375  {
376  delete pofs_psave;
377  pofs_psave=NULL;
378  }
379 } // end of HMC function
380 
static void set_NO_DERIVATIVES(void)
Disable accumulation of derivative information.
Definition: gradstrc.cpp:641
static void set_active_random_effects(void)
Definition: model.cpp:267
void shmc_mcmc_routine(int, int, double, int)
Definition: hmc.cpp:19
Vector of double precision numbers.
Definition: dvector.h:50
static char ** argv
Definition: fvar.hpp:8866
void print_mcmc_progress(int is, int nmcmc, int nwarmup, int chain, int refresh)
exitptr ad_exit
Definition: gradstrc.cpp:53
double leapfrog(int nvar, dvector &gr, dmatrix &chd, double eps, dvector &p, dvector &x, dvector &gr2)
Function to take a single HMC leapfrog step, given current position and momentum variables.
static void restore_start_phase(void)
Definition: model.cpp:275
static adstring adprogram_name
Definition: fvar.hpp:8860
int atoi(adstring &s)
Returns a integer converted from input s.
Definition: atoi.cpp:20
df1_one_matrix choleski_decomp(const df1_one_matrix &MM)
Definition: df11fun.cpp:606
static int nvarcalc()
Definition: model.cpp:152
double randu(const random_number_generator &rng)
Uniform random number generator.
Definition: rngen.cpp:198
void fill_randn(long int &n)
Fill vector with random numbers.
Definition: ranfill.cpp:231
Description not yet available.
Definition: fvar.hpp:7951
prnstream & endl(prnstream &)
Description not yet available.
Definition: fvar.hpp:1937
double get_hybrid_monte_carlo_value(int nvar, const independent_variables &y, dvector &g)
Written by Dave, commented by Cole starting 8/31/2016 Description not yet available.
#define min(a, b)
Definition: cbivnorm.cpp:188
Description not yet available.
Definition: fvar.hpp:3398
static int argc
Definition: fvar.hpp:8863
Description not yet available.
static void xinit(const dvector &x)
Definition: model.cpp:226
d3_array exp(const d3_array &arr3)
Returns d3_array results with computed exp from elements in arr3.
Definition: d3arr2a.cpp:28
static void set_inactive_random_effects(void)
Definition: model.cpp:288
Description not yet available.
Definition: fvar.hpp:2819
void read_covariance_matrix(const dmatrix &S, int nvar, int &hbf, dvector &sscale)
Definition: xxmcmc.cpp:1320
void initialize(void)
Initialze all elements of dvector to zero.
Definition: dvect5.cpp:10
double norm2(const d3_array &a)
Return sum of squared elements in a.
Definition: d3arr2a.cpp:167
static void copy_all_values(const dvector &x, const int &ii)
Definition: model3.cpp:9
void read_empirical_covariance_matrix(int nvar, const dmatrix &S, const adstring &prog_name)
Reads the covariance matrix from a file, which is the program name prepended to the extension &#39;...
Definition: xxmcmc.cpp:961
int option_match(int argc, char *argv[], const char *string)
Checks if the program has been invoked with a particular command line argument (&quot;string&quot;).
Definition: optmatch.cpp:25
double adapt_eps(int ii, int iseps, double eps, double alpha, double &adapt_delta, double &mu, dvector &epsvec, dvector &epsbar, dvector &Hbar)
void print_mcmc_timing(double time_warmup, double time_total, int chain)
double eps
Definition: ftweak.cpp:13
static void set_YES_DERIVATIVES(void)
Enable accumulation of derivative information.
Definition: gradstrc.cpp:650
int diagonal_metric_flag
Definition: admodel.h:1887
void read_hessian_matrix_and_scale1(int nvar, const dmatrix &_SS, double s, int mcmc2_flag)
Definition: xxmcmc.cpp:1453
static int stddev_scale(const dvector &d, const dvector &x)
Definition: model.cpp:202
static int mc_phase
Definition: admodel.h:846
void initialize(void)
Author: David Fournier Copyright (c) 2008-2012 Regents of the University of California.
Definition: dmat7.cpp:12
d3_array log(const d3_array &arr3)
Author: David Fournier Copyright (c) 2008-2012 Regents of the University of California.
Definition: d3arr2a.cpp:13