1 #ifndef __STAN__GM__COMMAND_HPP__
2 #define __STAN__GM__COMMAND_HPP__
7 #include <boost/date_time/posix_time/posix_time_types.hpp>
13 #include <boost/random/additive_combine.hpp>
16 #include <boost/random/uniform_real_distribution.hpp>
38 std::cout << std::endl;
39 std::cout <<
"Compiled Stan Graphical Model Command" << std::endl;
40 std::cout << std::endl;
42 std::cout <<
"USAGE: " << cmd <<
" [options]" << std::endl;
43 std::cout << std::endl;
45 std::cout <<
"OPTIONS:" << std::endl;
46 std::cout << std::endl;
50 "Display this information");
54 "Read data from specified dump-format file",
55 "required if model declares data");
59 "Use initial values from specified file or zero values if <file>=0",
60 "default is random initialization");
64 "File into which samples are written",
65 "default = samples.csv");
69 "Append samples to existing file if it exists",
70 "does not write header in append mode");
74 "Random number generation seed",
75 "default = randomly generated from time");
79 "Markov chain identifier",
84 "Total number of iterations, including warmup",
89 "Discard the specified number of initial samples",
90 "default = iter / 2");
94 "Period between saved samples after warm up",
95 "default = max(1, floor(iter - warmup) / 1000)");
99 "Period between samples updating progress report print (0 for no printing)",
100 "default = max(1,iter/200))");
103 "leapfrog_steps",
"int",
104 "Number of leapfrog steps; -1 for no-U-turn adaptation",
108 "max_treedepth",
"int",
109 "Limit NUTS leapfrog steps to 2^max_tree_depth; -1 for no limit",
114 "Initial value for step size, or -1 to set automatically",
118 "epsilon_pm",
"[0,1]",
119 "Sample epsilon +/- epsilon * epsilon_pm",
123 "equal_step_sizes",
"",
124 "Use same step size for every parameter with NUTS",
125 "default is to estimate varying step sizes during warmup");
129 "Accuracy target for step-size adaptation (higher means smaller step sizes)",
134 "Gamma parameter for dual averaging step-size adaptation",
139 "Save the warmup samples");
143 "Test gradient calculations using finite differences");
147 "Fit point estimate of hidden parameters by maximizing log joint probability");
149 std::cout << std::endl;
155 || ((n + 1) % refresh == 0) );
158 template <
class Sampler,
class Model>
166 std::ostream& sample_file_stream,
167 std::vector<double>& params_r,
168 std::vector<int>& params_i,
171 sampler.set_params(params_r,params_i);
174 std::cout << std::endl;
178 for (
int m = 0; m < num_iterations; ++m) {
180 std::cout <<
"Iteration: ";
181 std::cout << std::setw(it_print_width) << (m + 1)
182 <<
" / " << num_iterations;
183 std::cout <<
" [" << std::setw(3)
184 <<
static_cast<int>((100.0 * (m + 1))/num_iterations)
186 std::cout << ((m < num_warmup) ?
" (Adapting)" :
" (Sampling)");
187 std::cout << std::endl;
190 if (m < num_warmup) {
191 if (save_warmup && (m % num_thin) == 0) {
195 sample_file_stream <<
sample.log_prob() <<
',';
196 sampler.write_sampler_params(sample_file_stream);
197 sample.params_r(params_r);
198 sample.params_i(params_i);
199 model.write_csv(params_r,params_i,sample_file_stream);
204 if (epsilon_adapt && sampler.adapting()) {
206 sampler.write_adaptation_params(sample_file_stream);
208 if (((m - num_warmup) % num_thin) != 0) {
215 sample_file_stream <<
sample.log_prob() <<
',';
216 sampler.write_sampler_params(sample_file_stream);
217 sample.params_r(params_r);
218 sample.params_i(params_i);
219 model.write_csv(params_r,params_i,sample_file_stream);
226 o <<
"#" << std::endl;
228 template <
typename M>
231 o <<
"# " << msg << std::endl;
233 template <
typename K,
typename V>
237 o <<
"# " << key <<
"=" << val << std::endl;
240 template <
class Model>
250 std::string data_file;
251 command.
val(
"data",data_file);
252 std::fstream data_stream(data_file.c_str(),
257 Model model(data_var_context, &std::cout);
259 bool point_estimate = command.
has_flag(
"point_estimate");
261 std::string sample_file =
"samples.csv";
262 command.
val(
"samples",sample_file);
264 unsigned int num_iterations = 2000U;
265 command.
val(
"iter",num_iterations);
267 unsigned int num_warmup = num_iterations / 2;
268 command.
val(
"warmup",num_warmup);
270 unsigned int calculated_thin = (num_iterations - num_warmup) / 1000U;
271 unsigned int num_thin = (calculated_thin > 1) ? calculated_thin : 1U;
272 command.
val(
"thin",num_thin);
274 bool user_supplied_thin = command.
has_key(
"thin");
276 int leapfrog_steps = -1;
277 command.
val(
"leapfrog_steps",leapfrog_steps);
282 int max_treedepth = 10;
283 command.
val(
"max_treedepth",max_treedepth);
285 double epsilon_pm = 0.0;
286 command.
val(
"epsilon_pm",epsilon_pm);
288 bool epsilon_adapt =
epsilon <= 0.0;
290 bool equal_step_sizes = command.
has_flag(
"equal_step_sizes");
293 command.
val(
"delta", delta);
296 command.
val(
"gamma", gamma);
298 int refresh = num_iterations / 200;
299 refresh = refresh <= 0 ? 1 : refresh;
300 command.
val(
"refresh",refresh);
302 unsigned int random_seed = 0;
304 bool well_formed = command.
val(
"seed",random_seed);
306 std::string seed_val;
307 command.
val(
"seed",seed_val);
308 std::cerr <<
"value for seed must be integer"
309 <<
"; found value=" << seed_val << std::endl;
314 = (boost::posix_time::microsec_clock::universal_time() -
315 boost::posix_time::ptime(boost::posix_time::min_date_time))
316 .total_milliseconds();
320 if (command.
has_key(
"chain_id")) {
321 bool well_formed = command.
val(
"chain_id",chain_id);
322 if (!well_formed || chain_id < 0) {
323 std::string chain_id_val;
324 command.
val(
"chain_id",chain_id_val);
325 std::cerr <<
"value for chain_id must be positive integer"
326 <<
"; found chain_id=" << chain_id_val
336 typedef boost::ecuyer1988 rng_t;
337 rng_t base_rng(random_seed);
339 static boost::uintmax_t DISCARD_STRIDE =
static_cast<boost::uintmax_t
>(1) << 50;
341 base_rng.discard(DISCARD_STRIDE * (chain_id - 1));
343 std::vector<int> params_i;
344 std::vector<double> params_r;
346 std::string init_val;
348 int num_init_tries = 1;
351 command.
val(
"init",init_val);
352 if (init_val ==
"0") {
353 params_i = std::vector<int>(model.num_params_i(),0);
354 params_r = std::vector<double>(model.num_params_r(),0.0);
357 std::fstream init_stream(init_val.c_str(),std::fstream::in);
358 if (init_stream.fail()) {
359 std::string msg(
"ERROR: specified init file does not exist: ");
361 throw std::invalid_argument(msg);
365 model.transform_inits(init_var_context,params_i,params_r);
366 }
catch (
const std::exception&
e) {
367 std::cerr <<
"Error during user-specified initialization:"
375 init_val =
"random initialization";
377 boost::random::uniform_real_distribution<double>
378 init_range_distribution(-2.0,2.0);
379 boost::variate_generator<rng_t&,
380 boost::random::uniform_real_distribution<double> >
381 init_rng(base_rng,init_range_distribution);
383 params_i = std::vector<int>(model.num_params_i(),0);
384 params_r = std::vector<double>(model.num_params_r());
387 std::vector<double> init_grad;
388 static int MAX_INIT_TRIES = 100;
389 for (num_init_tries = 1; num_init_tries <= MAX_INIT_TRIES; ++num_init_tries) {
390 for (
size_t i = 0; i < params_r.size(); ++i)
391 params_r[i] = init_rng();
393 double init_log_prob = model.grad_log_prob(params_r,params_i,init_grad,&std::cout);
396 for (
size_t i = 0; i < init_grad.size(); ++i)
401 if (num_init_tries > MAX_INIT_TRIES) {
402 std::cout <<
"Initialization failed after " << MAX_INIT_TRIES
404 <<
" Try specifying initial values,"
405 <<
" reducing ranges of constrained values,"
406 <<
" or reparameterizing the model."
412 bool save_warmup = command.
has_flag(
"save_warmup");
414 bool append_samples = command.
has_flag(
"append_samples");
415 std::ios_base::openmode samples_append_mode
417 ? (std::fstream::out | std::fstream::app)
420 if (command.
has_flag(
"test_grad")) {
421 std::cout << std::endl <<
"TEST GRADIENT MODE" << std::endl;
422 return model.test_gradients(params_r,params_i);
425 if (point_estimate) {
426 std::cout <<
"STAN OPTIMIZATION COMMAND" << std::endl;
428 std::cout <<
"data = (specified model requires no data)" << std::endl;
430 std::cout <<
"data = " << data_file << std::endl;
432 std::cout <<
"init = " << init_val << std::endl;
433 if (num_init_tries > 0)
434 std::cout <<
"init tries = " << num_init_tries << std::endl;
436 std::cout <<
"output = " << sample_file << std::endl;
437 std::cout <<
"save_warmup = " << save_warmup<< std::endl;
439 std::cout <<
"seed = " << random_seed
440 <<
" (" << (command.
has_key(
"seed")
442 :
"randomly generated") <<
")"
445 std::fstream sample_stream(sample_file.c_str(),
446 samples_append_mode);
448 write_comment(sample_stream,
"Point Estimate Generated by Stan");
459 sample_stream <<
"lp__,";
460 model.write_csv_header(sample_stream);
462 std::vector<double> gradient;
463 double lp = model.grad_log_prob(params_r, params_i, gradient);
465 double lastlp = lp - 1;
466 std::cout <<
"initial log joint probability = " << lp << std::endl;
468 while ((lp - lastlp) /
fabs(lp) > 1
e-8) {
471 std::cout <<
"Iteration ";
472 std::cout << std::setw(2) << (m + 1) <<
". ";
473 std::cout <<
"Log joint probability = " << std::setw(10) << lp;
474 std::cout <<
". Improved by " << (lp - lastlp) <<
".";
475 std::cout << std::endl;
482 sample_stream << lp <<
',';
483 model.write_csv(params_r,params_i,sample_stream);
487 sample_stream << lp <<
',';
488 model.write_csv(params_r,params_i,sample_stream);
493 std::cout <<
"STAN SAMPLING COMMAND" << std::endl;
495 std::cout <<
"data = (specified model requires no data)" << std::endl;
497 std::cout <<
"data = " << data_file << std::endl;
499 std::cout <<
"init = " << init_val << std::endl;
500 if (num_init_tries > 0)
501 std::cout <<
"init tries = " << num_init_tries << std::endl;
503 std::cout <<
"samples = " << sample_file << std::endl;
504 std::cout <<
"append_samples = " << append_samples << std::endl;
505 std::cout <<
"save_warmup = " << save_warmup<< std::endl;
507 std::cout <<
"seed = " << random_seed
508 <<
" (" << (command.
has_key(
"seed")
510 :
"randomly generated") <<
")"
512 std::cout <<
"chain_id = " << chain_id
513 <<
" (" << (command.
has_key(
"chain_id")
518 std::cout <<
"iter = " << num_iterations << std::endl;
519 std::cout <<
"warmup = " << num_warmup << std::endl;
520 std::cout <<
"thin = " << num_thin
521 << (user_supplied_thin ?
" (user supplied)" :
" (default)")
524 std::cout <<
"equal_step_sizes = " << equal_step_sizes << std::endl;
525 std::cout <<
"leapfrog_steps = " << leapfrog_steps << std::endl;
526 std::cout <<
"max_treedepth = " << max_treedepth << std::endl;;
527 std::cout <<
"epsilon = " <<
epsilon << std::endl;;
528 std::cout <<
"epsilon_pm = " << epsilon_pm << std::endl;;
529 std::cout <<
"delta = " << delta << std::endl;
530 std::cout <<
"gamma = " << gamma << std::endl;
532 std::fstream sample_stream(sample_file.c_str(),
533 samples_append_mode);
558 if (leapfrog_steps < 0 && !equal_step_sizes) {
562 epsilon_pm, epsilon_adapt,
568 if (!append_samples) {
569 sample_stream <<
"lp__,";
571 model.write_csv_header(sample_stream);
577 num_iterations,num_warmup,num_thin,save_warmup,
578 sample_stream,params_r,params_i,
581 }
else if (leapfrog_steps < 0 && equal_step_sizes) {
586 epsilon_pm, epsilon_adapt,
594 if (!append_samples) {
595 sample_stream <<
"lp__,";
597 model.write_csv_header(sample_stream);
601 num_iterations,num_warmup,num_thin,save_warmup,
602 sample_stream,params_r,params_i,
610 epsilon, epsilon_pm, epsilon_adapt,
618 if (!append_samples) {
619 sample_stream <<
"lp__,";
621 model.write_csv_header(sample_stream);
625 num_iterations,num_warmup,num_thin,save_warmup,
626 sample_stream,params_r,params_i,
630 sample_stream.close();
631 std::cout << std::endl << std::endl;
Parses and stores command-line arguments.
bool has_key(const std::string &key) const
Return true if the specified key is defined.
bool has_flag(const std::string &flag) const
Return true if the specified flag is defined.
bool val(const std::string &key, T &x) const
Returns the value for the key provided.
Represents named arrays with dimensions.
Adaptive Hamiltonian Monte Carlo (HMC) sampler.
virtual void write_sampler_param_names(std::ostream &o)
Write out any sampler-specific parameter names for output.
void set_output_stream(std::ostream &output_msgs)
Set the stream into which output will be written as the sampler runs.
void set_error_stream(std::ostream &error_msgs)
Set the stream into which errors will be written as the sampler runs.
No-U-Turn Sampler (NUTS) with varying step sizes.
virtual void write_sampler_param_names(std::ostream &o)
Write out any sampler-specific parameter names for output.
No-U-Turn Sampler (NUTS).
virtual void write_sampler_param_names(std::ostream &o)
Write out any sampler-specific parameter names for output.
Representation of a MCMC sample.
bool isfinite(const stan::agrad::var v)
Checks if the given number has finite value.
var fabs(const var &a)
Return the absolute value of the variable (cmath).
var ceil(const var &a)
Return the ceiling of the specified variable (cmath).
var log10(const var &a)
Return the base 10 log of the specified variable (cmath).
bool do_print(int n, int refresh)
void print_nuts_help(std::string cmd)
void write_comment_property(std::ostream &o, const K &key, const V &val)
int nuts_command(int argc, const char *argv[])
void sample_from(Sampler &sampler, bool epsilon_adapt, int refresh, int num_iterations, int num_warmup, int num_thin, bool save_warmup, std::ostream &sample_file_stream, std::vector< double > ¶ms_r, std::vector< int > ¶ms_i, Model &model)
void write_comment(std::ostream &o)
void print_help_option(std::ostream *o, const std::string &key, const std::string &value_type, const std::string &msg, const std::string ¬e="")
Prints single print option to output ptr if non-null.
double epsilon()
Return minimum positive number representable.
double e()
Return the base of the natural logarithm.
double newton_step(stan::model::prob_grad &model, std::vector< double > ¶ms_r, std::vector< int > ¶ms_i, std::ostream *output_stream=0)
Probability, optimization and sampling library.
const std::string MAJOR_VERSION
Major version number for Stan package.
const std::string MINOR_VERSION
Minor version number for Stan package.
const std::string PATCH_VERSION
Patch version for Stan package.