1 #ifndef __STAN__GM__COMMAND_HPP__
2 #define __STAN__GM__COMMAND_HPP__
6 #include <boost/math/special_functions/fpclassify.hpp>
7 #include <boost/date_time/posix_time/posix_time_types.hpp>
13 #include <boost/random/additive_combine.hpp>
14 #include <boost/random/mersenne_twister.hpp>
15 #include <boost/random/uniform_01.hpp>
16 #include <boost/random/uniform_real_distribution.hpp>
37 std::cout << std::endl;
38 std::cout <<
"Compiled Stan Graphical Model Command" << std::endl;
39 std::cout << std::endl;
41 std::cout <<
"USAGE: " << cmd <<
" [options]" << std::endl;
42 std::cout << std::endl;
44 std::cout <<
"OPTIONS:" << std::endl;
45 std::cout << std::endl;
49 "Display this information");
53 "Read data from specified dump-format file",
54 "required if model declares data");
58 "Use initial values from specified file or zero values if <file>=0",
59 "default is random initialization");
63 "File into which samples are written",
64 "default = samples.csv");
68 "Append samples to existing file if it exists",
69 "does not write header in append mode");
73 "Random number generation seed",
74 "default = randomly generated from time");
78 "Markov chain identifier",
83 "Total number of iterations, including warmup",
88 "Discard the specified number of initial samples",
89 "default = iter / 2");
93 "Period between saved samples after warm up",
94 "default = max(1, floor(iter - warmup) / 1000)");
98 "Period between samples updating progress report print (0 for no printing)",
99 "default = max(1,iter/200))");
102 "leapfrog_steps",
"int",
103 "Number of leapfrog steps; -1 for no-U-turn adaptation",
107 "max_treedepth",
"int",
108 "Limit NUTS leapfrog steps to 2^max_tree_depth; -1 for no limit",
113 "Initial value for step size, or -1 to set automatically",
117 "epsilon_pm",
"[0,1]",
118 "Sample epsilon +/- epsilon * epsilon_pm",
122 "equal_step_sizes",
"",
123 "Use same step size for every parameter with NUTS",
124 "default is to estimate varying step sizes during warmup");
128 "Initial step size for step-size adaptation",
133 "Gamma parameter for dual averaging step-size adaptation",
138 "Save the warmup samples");
142 "Test gradient calculations using finite differences");
144 std::cout << std::endl;
150 || ((n + 1) % refresh == 0) );
153 template <
class Sampler,
class Model>
161 std::ostream& sample_file_stream,
162 std::vector<double>& params_r,
163 std::vector<int>& params_i,
166 sampler.set_params(params_r,params_i);
169 std::cout << std::endl;
173 for (
int m = 0; m < num_iterations; ++m) {
175 std::cout <<
"Iteration: ";
176 std::cout << std::setw(it_print_width) << (m + 1)
177 <<
" / " << num_iterations;
178 std::cout <<
" [" << std::setw(3)
179 <<
static_cast<int>((100.0 * (m + 1))/num_iterations)
181 std::cout << ((m < num_warmup) ?
" (Adapting)" :
" (Sampling)");
182 std::cout << std::endl;
185 if (m < num_warmup) {
186 if (save_warmup && (m % num_thin) == 0) {
190 sample_file_stream << sample.
log_prob() <<
',';
191 sampler.write_sampler_params(sample_file_stream);
194 model.write_csv(params_r,params_i,sample_file_stream);
199 if (epsilon_adapt && sampler.adapting()) {
201 sampler.write_adaptation_params(sample_file_stream);
203 if (((m - num_warmup) % num_thin) != 0) {
210 sample_file_stream << sample.
log_prob() <<
',';
211 sampler.write_sampler_params(sample_file_stream);
214 model.write_csv(params_r,params_i,sample_file_stream);
221 o <<
"#" << std::endl;
223 template <
typename M>
226 o <<
"# " << msg << std::endl;
228 template <
typename K,
typename V>
232 o <<
"# " << key <<
"=" << val << std::endl;
235 template <
class Model>
245 std::string data_file;
246 command.
val(
"data",data_file);
247 std::fstream data_stream(data_file.c_str(),
253 Model model(data_var_context, &std::cout);
255 std::string sample_file =
"samples.csv";
256 command.
val(
"samples",sample_file);
258 unsigned int num_iterations = 2000U;
259 command.
val(
"iter",num_iterations);
261 unsigned int num_warmup = num_iterations / 2;
262 command.
val(
"warmup",num_warmup);
264 unsigned int calculated_thin = (num_iterations - num_warmup) / 1000U;
265 unsigned int num_thin = (calculated_thin > 1) ? calculated_thin : 1U;
266 command.
val(
"thin",num_thin);
268 bool user_supplied_thin = command.
has_key(
"thin");
270 int leapfrog_steps = -1;
271 command.
val(
"leapfrog_steps",leapfrog_steps);
274 command.
val(
"epsilon",epsilon);
276 int max_treedepth = 10;
277 command.
val(
"max_treedepth",max_treedepth);
279 double epsilon_pm = 0.0;
280 command.
val(
"epsilon_pm",epsilon_pm);
282 bool epsilon_adapt = epsilon <= 0.0;
284 bool equal_step_sizes = command.
has_flag(
"equal_step_sizes");
287 command.
val(
"delta", delta);
290 command.
val(
"gamma", gamma);
292 int refresh = num_iterations / 200;
293 refresh = refresh <= 0 ? 1 : refresh;
294 command.
val(
"refresh",refresh);
296 unsigned int random_seed = 0;
298 bool well_formed = command.
val(
"seed",random_seed);
300 std::string seed_val;
301 command.
val(
"seed",seed_val);
302 std::cerr <<
"value for seed must be integer"
303 <<
"; found value=" << seed_val << std::endl;
308 = (boost::posix_time::microsec_clock::universal_time() -
309 boost::posix_time::ptime(boost::posix_time::min_date_time))
310 .total_milliseconds();
314 if (command.
has_key(
"chain_id")) {
315 bool well_formed = command.
val(
"chain_id",chain_id);
316 if (!well_formed || chain_id < 0) {
317 std::string chain_id_val;
318 command.
val(
"chain_id",chain_id_val);
319 std::cerr <<
"value for chain_id must be positive integer"
320 <<
"; found chain_id=" << chain_id_val
330 typedef boost::ecuyer1988 rng_t;
331 rng_t base_rng(random_seed);
333 static boost::uintmax_t DISCARD_STRIDE =
static_cast<boost::uintmax_t
>(1) << 50;
335 base_rng.discard(DISCARD_STRIDE * (chain_id - 1));
337 std::vector<int> params_i;
338 std::vector<double> params_r;
340 std::string init_val;
342 int num_init_tries = 1;
345 command.
val(
"init",init_val);
346 if (init_val ==
"0") {
347 params_i = std::vector<int>(model.num_params_i(),0);
348 params_r = std::vector<double>(model.num_params_r(),0.0);
350 std::fstream init_stream(init_val.c_str(),std::fstream::in);
353 model.transform_inits(init_var_context,params_i,params_r);
356 init_val =
"random initialization";
358 boost::random::uniform_real_distribution<double>
359 init_range_distribution(-2.0,2.0);
360 boost::variate_generator<rng_t&,
361 boost::random::uniform_real_distribution<double> >
362 init_rng(base_rng,init_range_distribution);
364 params_i = std::vector<int>(model.num_params_i(),0);
365 params_r = std::vector<double>(model.num_params_r());
368 std::vector<double> init_grad;
369 static int MAX_INIT_TRIES = 100;
370 for (num_init_tries = 1; num_init_tries <= MAX_INIT_TRIES; ++num_init_tries) {
371 for (
size_t i = 0; i < params_r.size(); ++i)
372 params_r[i] = init_rng();
374 double init_log_prob = model.grad_log_prob(params_r,params_i,init_grad,&std::cout);
377 for (
size_t i = 0; i < init_grad.size(); ++i)
382 if (num_init_tries > MAX_INIT_TRIES) {
383 std::cout <<
"Initialization failed after " << MAX_INIT_TRIES
385 <<
" Try specifying initial values,"
386 <<
" reducing ranges of constrained values,"
387 <<
" or reparameterizing the model."
393 bool save_warmup = command.
has_flag(
"save_warmup");
395 bool append_samples = command.
has_flag(
"append_samples");
396 std::ios_base::openmode samples_append_mode
398 ? (std::fstream::out | std::fstream::app)
402 std::cout <<
"STAN SAMPLING COMMAND" << std::endl;
404 std::cout <<
"data = (specified model requires no data)" << std::endl;
406 std::cout <<
"data = " << data_file << std::endl;
408 std::cout <<
"init = " << init_val << std::endl;
409 if (num_init_tries > 0)
410 std::cout <<
"init tries = " << num_init_tries << std::endl;
412 std::cout <<
"samples = " << sample_file << std::endl;
413 std::cout <<
"append_samples = " << append_samples << std::endl;
414 std::cout <<
"save_warmup = " << save_warmup<< std::endl;
416 std::cout <<
"seed = " << random_seed
417 <<
" (" << (command.
has_key(
"seed")
419 :
"randomly generated") <<
")"
421 std::cout <<
"chain_id = " << chain_id
422 <<
" (" << (command.
has_key(
"chain_id")
427 std::cout <<
"iter = " << num_iterations << std::endl;
428 std::cout <<
"warmup = " << num_warmup << std::endl;
429 std::cout <<
"thin = " << num_thin
430 << (user_supplied_thin ?
" (user supplied)" :
" (default)")
433 std::cout <<
"equal_step_sizes = " << equal_step_sizes << std::endl;
434 std::cout <<
"leapfrog_steps = " << leapfrog_steps << std::endl;
435 std::cout <<
"max_treedepth = " << max_treedepth << std::endl;;
436 std::cout <<
"epsilon = " << epsilon << std::endl;;
437 std::cout <<
"epsilon_pm = " << epsilon_pm << std::endl;;
438 std::cout <<
"delta = " << delta << std::endl;
439 std::cout <<
"gamma = " << gamma << std::endl;
441 if (command.
has_flag(
"test_grad")) {
442 std::cout << std::endl <<
"TEST GRADIENT MODE" << std::endl;
443 return model.test_gradients(params_r,params_i);
446 std::fstream sample_stream(sample_file.c_str(),
447 samples_append_mode);
472 if (leapfrog_steps < 0 && !equal_step_sizes) {
475 max_treedepth, epsilon,
476 epsilon_pm, epsilon_adapt,
482 if (!append_samples) {
483 sample_stream <<
"lp__,";
485 model.write_csv_header(sample_stream);
491 num_iterations,num_warmup,num_thin,save_warmup,
492 sample_stream,params_r,params_i,
495 }
else if (leapfrog_steps < 0 && equal_step_sizes) {
499 max_treedepth, epsilon,
500 epsilon_pm, epsilon_adapt,
508 if (!append_samples) {
509 sample_stream <<
"lp__,";
511 model.write_csv_header(sample_stream);
515 num_iterations,num_warmup,num_thin,save_warmup,
516 sample_stream,params_r,params_i,
524 epsilon, epsilon_pm, epsilon_adapt,
532 if (!append_samples) {
533 sample_stream <<
"lp__,";
535 model.write_csv_header(sample_stream);
539 num_iterations,num_warmup,num_thin,save_warmup,
540 sample_stream,params_r,params_i,
544 sample_stream.close();
545 std::cout << std::endl << std::endl;