Stan  2.5.0
probability, sampling & optimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
command.hpp
Go to the documentation of this file.
1 #ifndef STAN__COMMON__COMMAND_HPP
2 #define STAN__COMMON__COMMAND_HPP
3 
4 #include <fstream>
5 #include <stdexcept>
6 
7 #include <boost/date_time/posix_time/posix_time_types.hpp>
8 #include <boost/math/special_functions/fpclassify.hpp>
9 #include <boost/random/additive_combine.hpp> // L'Ecuyer RNG
10 #include <boost/random/uniform_real_distribution.hpp>
11 
12 #include <stan/version.hpp>
13 #include <stan/io/cmd_line.hpp>
14 #include <stan/io/dump.hpp>
15 #include <stan/io/json.hpp>
16 #include <stan/io/mcmc_writer.hpp>
17 
24 
32 
33 #include <stan/model/util.hpp>
34 
37 
43 #include <stan/common/do_print.hpp>
47 #include <stan/common/warmup.hpp>
48 #include <stan/common/sample.hpp>
57 
58 namespace stan {
59 
60  namespace common {
61 
62  struct NoOpFunctor {
63  void operator()() { }
64  };
65 
66  template <class Model>
67  int command(int argc, const char* argv[]) {
68 
69  std::vector<stan::gm::argument*> valid_arguments;
70  valid_arguments.push_back(new stan::gm::arg_id());
71  valid_arguments.push_back(new stan::gm::arg_data());
72  valid_arguments.push_back(new stan::gm::arg_init());
73  valid_arguments.push_back(new stan::gm::arg_random());
74  valid_arguments.push_back(new stan::gm::arg_output());
75 
76  stan::gm::argument_parser parser(valid_arguments);
77  int err_code = parser.parse_args(argc, argv, &std::cout, &std::cout);
78 
79  if (err_code != 0) {
80  std::cout << "Failed to parse arguments, terminating Stan" << std::endl;
81  return err_code;
82  }
83 
84  if (parser.help_printed())
85  return err_code;
86 
87  // Identification
88  unsigned int id = dynamic_cast<stan::gm::int_argument*>(parser.arg("id"))->value();
89 
91  // Random number generator //
93 
94  unsigned int random_seed = 0;
95  stan::gm::u_int_argument* random_arg
96  = dynamic_cast<stan::gm::u_int_argument*>(parser.arg("random")->arg("seed"));
97 
98  if (random_arg->is_default()) {
99  random_seed = (boost::posix_time::microsec_clock::universal_time() -
100  boost::posix_time::ptime(boost::posix_time::min_date_time))
101  .total_milliseconds();
102 
103  random_arg->set_value(random_seed);
104 
105  } else {
106  random_seed = random_arg->value();
107  }
108 
109  typedef boost::ecuyer1988 rng_t; // (2**50 = 1T samples, 1000 chains)
110  rng_t base_rng(random_seed);
111 
112  // Advance generator to avoid process conflicts
113  static boost::uintmax_t DISCARD_STRIDE = static_cast<boost::uintmax_t>(1) << 50;
114  base_rng.discard(DISCARD_STRIDE * (id - 1));
115 
117  // Input/Output //
119 
120  // Data input
121  std::string data_file
122  = dynamic_cast<stan::gm::string_argument*>(parser.arg("data")->arg("file"))->value();
123 
124  std::fstream data_stream(data_file.c_str(),
125  std::fstream::in);
126  stan::io::dump data_var_context(data_stream);
127  data_stream.close();
128 
129  // Sample output
130  std::string output_file = dynamic_cast<stan::gm::string_argument*>(
131  parser.arg("output")->arg("file"))->value();
132  std::fstream* output_stream = 0;
133  if (output_file != "") {
134  output_stream = new std::fstream(output_file.c_str(),
135  std::fstream::out);
136  }
137 
138  // Diagnostic output
139  std::string diagnostic_file = dynamic_cast<stan::gm::string_argument*>(
140  parser.arg("output")->arg("diagnostic_file"))->value();
141 
142  std::fstream* diagnostic_stream = 0;
143  if (diagnostic_file != "") {
144  diagnostic_stream = new std::fstream(diagnostic_file.c_str(),
145  std::fstream::out);
146  }
147 
148  // Refresh rate
149  int refresh = dynamic_cast<stan::gm::int_argument*>(
150  parser.arg("output")->arg("refresh"))->value();
151 
153  // Initialize Model //
155 
156  Model model(data_var_context, &std::cout);
157 
158  Eigen::VectorXd cont_params = Eigen::VectorXd::Zero(model.num_params_r());
159 
160  parser.print(&std::cout);
161  std::cout << std::endl;
162 
163  if (output_stream) {
164  write_stan(output_stream, "#");
165  write_model(output_stream, model.model_name(), "#");
166  parser.print(output_stream, "#");
167  }
168 
169  if (diagnostic_stream) {
170  write_stan(diagnostic_stream, "#");
171  write_model(diagnostic_stream, model.model_name(), "#");
172  parser.print(diagnostic_stream, "#");
173  }
174 
175  std::string init = dynamic_cast<stan::gm::string_argument*>(
176  parser.arg("init"))->value();
177 
179  if (!initialize_state<dump_factory>
180  (init, cont_params, model, base_rng, &std::cout,
181  var_context_factory))
183 
185  // Model Diagnostics //
187 
188  if (parser.arg("method")->arg("diagnose")) {
189 
190  std::vector<double> cont_vector(cont_params.size());
191  for (int i = 0; i < cont_params.size(); ++i)
192  cont_vector.at(i) = cont_params(i);
193  std::vector<int> disc_vector;
194 
195  stan::gm::list_argument* test = dynamic_cast<stan::gm::list_argument*>
196  (parser.arg("method")->arg("diagnose")->arg("test"));
197 
198  if (test->value() == "gradient") {
199  std::cout << std::endl << "TEST GRADIENT MODE" << std::endl;
200 
201  double epsilon = dynamic_cast<stan::gm::real_argument*>
202  (test->arg("gradient")->arg("epsilon"))->value();
203 
204  double error = dynamic_cast<stan::gm::real_argument*>
205  (test->arg("gradient")->arg("error"))->value();
206 
207  int num_failed
208  = stan::model::test_gradients<true,true>(model,cont_vector, disc_vector,
209  epsilon, error, std::cout);
210 
211  if (output_stream) {
212  num_failed
213  = stan::model::test_gradients<true,true>(model,cont_vector, disc_vector,
214  epsilon, error, *output_stream);
215  }
216 
217  if (diagnostic_stream) {
218  num_failed
219  = stan::model::test_gradients<true,true>(model,cont_vector, disc_vector,
220  epsilon, error, *diagnostic_stream);
221  }
222 
223  (void) num_failed; // FIXME: do something with the number failed
224 
226  }
227 
228  }
229 
231  // Optimization Algorithms //
233 
234  if (parser.arg("method")->arg("optimize")) {
235  std::vector<double> cont_vector(cont_params.size());
236  for (int i = 0; i < cont_params.size(); ++i)
237  cont_vector.at(i) = cont_params(i);
238  std::vector<int> disc_vector;
239 
240  stan::gm::list_argument* algo = dynamic_cast<stan::gm::list_argument*>
241  (parser.arg("method")->arg("optimize")->arg("algorithm"));
242 
243  int num_iterations = dynamic_cast<stan::gm::int_argument*>(
244  parser.arg("method")->arg("optimize")->arg("iter"))->value();
245 
246  bool save_iterations
247  = dynamic_cast<stan::gm::bool_argument*>(parser.arg("method")
248  ->arg("optimize")
249  ->arg("save_iterations"))->value();
250  if (output_stream) {
251  std::vector<std::string> names;
252  names.push_back("lp__");
253  model.constrained_param_names(names,true,true);
254 
255  (*output_stream) << names.at(0);
256  for (size_t i = 1; i < names.size(); ++i) {
257  (*output_stream) << "," << names.at(i);
258  }
259  (*output_stream) << std::endl;
260  }
261 
262  double lp(0);
263  int return_code = stan::gm::error_codes::CONFIG;
264  if (algo->value() == "newton") {
265  std::vector<double> gradient;
266  try {
267  lp = model.template log_prob<false, false>(cont_vector, disc_vector, &std::cout);
268  } catch (const std::exception& e) {
269  write_error_msg(&std::cout, e);
270  lp = -std::numeric_limits<double>::infinity();
271  }
272 
273  std::cout << "initial log joint probability = " << lp << std::endl;
274  if (output_stream && save_iterations) {
275  write_iteration(*output_stream, model, base_rng,
276  lp, cont_vector, disc_vector);
277  }
278 
279  double lastlp = lp * 1.1;
280  int m = 0;
281  std::cout << "(lp - lastlp) / lp > 1e-8: " << ((lp - lastlp) / fabs(lp)) << std::endl;
282  while ((lp - lastlp) / fabs(lp) > 1e-8) {
283 
284  lastlp = lp;
285  lp = stan::optimization::newton_step(model, cont_vector, disc_vector);
286  std::cout << "Iteration ";
287  std::cout << std::setw(2) << (m + 1) << ". ";
288  std::cout << "Log joint probability = " << std::setw(10) << lp;
289  std::cout << ". Improved by " << (lp - lastlp) << ".";
290  std::cout << std::endl;
291  std::cout.flush();
292  m++;
293 
294  if (output_stream && save_iterations) {
295  write_iteration(*output_stream, model, base_rng,
296  lp, cont_vector, disc_vector);
297  }
298 
299  }
300  return_code = stan::gm::error_codes::OK;
301  } else if (algo->value() == "bfgs") {
302  NoOpFunctor callback;
304  Optimizer bfgs(model, cont_vector, disc_vector, &std::cout);
305 
306  bfgs._ls_opts.alpha0 = dynamic_cast<stan::gm::real_argument*>(
307  algo->arg("bfgs")->arg("init_alpha"))->value();
308  bfgs._conv_opts.tolAbsF = dynamic_cast<stan::gm::real_argument*>(
309  algo->arg("bfgs")->arg("tol_obj"))->value();
310  bfgs._conv_opts.tolRelF = dynamic_cast<stan::gm::real_argument*>(
311  algo->arg("bfgs")->arg("tol_rel_obj"))->value();
312  bfgs._conv_opts.tolAbsGrad = dynamic_cast<stan::gm::real_argument*>(
313  algo->arg("bfgs")->arg("tol_grad"))->value();
314  bfgs._conv_opts.tolRelGrad = dynamic_cast<stan::gm::real_argument*>(
315  algo->arg("bfgs")->arg("tol_rel_grad"))->value();
316  bfgs._conv_opts.tolAbsX = dynamic_cast<stan::gm::real_argument*>(
317  algo->arg("bfgs")->arg("tol_param"))->value();
318  bfgs._conv_opts.maxIts = num_iterations;
319 
320  return_code = do_bfgs_optimize(model,bfgs, base_rng,
321  lp, cont_vector, disc_vector,
322  output_stream, &std::cout,
323  save_iterations, refresh,
324  callback);
325  } else if (algo->value() == "lbfgs") {
326  NoOpFunctor callback;
328  Optimizer bfgs(model, cont_vector, disc_vector, &std::cout);
329 
330  bfgs.get_qnupdate().set_history_size(dynamic_cast<gm::int_argument*>(
331  algo->arg("lbfgs")->arg("history_size"))->value());
332  bfgs._ls_opts.alpha0 = dynamic_cast<gm::real_argument*>(
333  algo->arg("lbfgs")->arg("init_alpha"))->value();
334  bfgs._conv_opts.tolAbsF = dynamic_cast<gm::real_argument*>(
335  algo->arg("lbfgs")->arg("tol_obj"))->value();
336  bfgs._conv_opts.tolRelF = dynamic_cast<gm::real_argument*>(
337  algo->arg("lbfgs")->arg("tol_rel_obj"))->value();
338  bfgs._conv_opts.tolAbsGrad = dynamic_cast<gm::real_argument*>(
339  algo->arg("lbfgs")->arg("tol_grad"))->value();
340  bfgs._conv_opts.tolRelGrad = dynamic_cast<gm::real_argument*>(
341  algo->arg("lbfgs")->arg("tol_rel_grad"))->value();
342  bfgs._conv_opts.tolAbsX = dynamic_cast<gm::real_argument*>(
343  algo->arg("lbfgs")->arg("tol_param"))->value();
344  bfgs._conv_opts.maxIts = num_iterations;
345 
346  return_code = do_bfgs_optimize(model,bfgs, base_rng,
347  lp, cont_vector, disc_vector,
348  output_stream, &std::cout,
349  save_iterations, refresh,
350  callback);
351  } else {
352  return_code = stan::gm::error_codes::CONFIG;
353  }
354 
355  if (output_stream) {
356  write_iteration(*output_stream, model, base_rng,
357  lp, cont_vector, disc_vector);
358  output_stream->close();
359  delete output_stream;
360  }
361  return return_code;
362  }
363 
365  // Sampling Algorithms //
367 
368  if (parser.arg("method")->arg("sample")) {
369 
370  // Check timing
371  clock_t start_check = clock();
372 
373  double init_log_prob;
374  Eigen::VectorXd init_grad = Eigen::VectorXd::Zero(model.num_params_r());
375 
376  stan::model::gradient(model, cont_params, init_log_prob, init_grad, &std::cout);
377 
378  clock_t end_check = clock();
379  double deltaT = (double)(end_check - start_check) / CLOCKS_PER_SEC;
380 
381  std::cout << std::endl;
382  std::cout << "Gradient evaluation took " << deltaT << " seconds" << std::endl;
383  std::cout << "1000 transitions using 10 leapfrog steps per transition would take "
384  << 1e4 * deltaT << " seconds." << std::endl;
385  std::cout << "Adjust your expectations accordingly!" << std::endl << std::endl;
386  std::cout << std::endl;
387 
388  stan::common::recorder::csv sample_recorder(output_stream, "# ");
389  stan::common::recorder::csv diagnostic_recorder(diagnostic_stream, "# ");
390  stan::common::recorder::messages message_recorder(&std::cout, "# ");
391 
392  stan::io::mcmc_writer<Model,
393  stan::common::recorder::csv, stan::common::recorder::csv,
395  writer(sample_recorder, diagnostic_recorder, message_recorder, &std::cout);
396 
397  // Sampling parameters
398  int num_warmup = dynamic_cast<stan::gm::int_argument*>(
399  parser.arg("method")->arg("sample")->arg("num_warmup"))->value();
400 
401  int num_samples = dynamic_cast<stan::gm::int_argument*>(
402  parser.arg("method")->arg("sample")->arg("num_samples"))->value();
403 
404  int num_thin = dynamic_cast<stan::gm::int_argument*>(
405  parser.arg("method")->arg("sample")->arg("thin"))->value();
406 
407  bool save_warmup = dynamic_cast<stan::gm::bool_argument*>(
408  parser.arg("method")->arg("sample")->arg("save_warmup"))->value();
409 
410  stan::mcmc::sample s(cont_params, 0, 0);
411 
412  double warmDeltaT;
413  double sampleDeltaT;
414 
415  // Sampler
416  stan::mcmc::base_mcmc* sampler_ptr = 0;
417 
418  stan::gm::list_argument* algo = dynamic_cast<stan::gm::list_argument*>
419  (parser.arg("method")->arg("sample")->arg("algorithm"));
420 
422  parser.arg("method")->arg("sample")->arg("adapt"));
423  bool adapt_engaged = dynamic_cast<stan::gm::bool_argument*>(adapt->arg("engaged"))->value();
424 
425  if (model.num_params_r() == 0 && algo->value() != "fixed_param") {
426  std::cout
427  << "Must use algorithm=fixed_param for model that has no parameters."
428  << std::endl;
429  return -1;
430  }
431 
432  if (algo->value() == "fixed_param") {
433 
434  sampler_ptr = new stan::mcmc::fixed_param_sampler();
435 
436  adapt_engaged = false;
437 
438  if (num_warmup != 0) {
439  std::cout << "Warning: warmup will be skipped for the fixed parameter sampler!" << std::endl;
440  num_warmup = 0;
441  }
442 
443  } else if (algo->value() == "rwm") {
444 
445  std::cout << algo->arg("rwm")->description() << std::endl;
446  return 0;
447 
448  } else if (algo->value() == "hmc") {
449 
450  int engine_index = 0;
451  stan::gm::list_argument* engine
452  = dynamic_cast<stan::gm::list_argument*>(algo->arg("hmc")->arg("engine"));
453  if (engine->value() == "static") {
454  engine_index = 0;
455  } else if (engine->value() == "nuts") {
456  engine_index = 1;
457  }
458 
459  int metric_index = 0;
460  stan::gm::list_argument* metric
461  = dynamic_cast<stan::gm::list_argument*>(algo->arg("hmc")->arg("metric"));
462  if (metric->value() == "unit_e") {
463  metric_index = 0;
464  } else if (metric->value() == "diag_e") {
465  metric_index = 1;
466  } else if (metric->value() == "dense_e") {
467  metric_index = 2;
468  }
469 
470  int sampler_select = engine_index
471  + 10 * metric_index
472  + 100 * static_cast<int>(adapt_engaged);
473 
474  switch (sampler_select) {
475 
476  case 0: {
478  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
479  if (!init_static_hmc<sampler>(sampler_ptr, algo)) return 0;
480  break;
481  }
482 
483  case 1: {
485  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
486  if (!init_nuts<sampler>(sampler_ptr, algo)) return 0;
487  break;
488  }
489 
490  case 10: {
492  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
493  if (!init_static_hmc<sampler>(sampler_ptr, algo)) return 0;
494  break;
495  }
496 
497  case 11: {
499  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
500  if (!init_nuts<sampler>(sampler_ptr, algo)) return 0;
501  break;
502  }
503 
504  case 20: {
506  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
507  if (!init_static_hmc<sampler>(sampler_ptr, algo)) return 0;
508  break;
509  }
510 
511  case 21: {
513  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
514  if (!init_nuts<sampler>(sampler_ptr, algo)) return 0;
515  break;
516  }
517 
518  case 100: {
520  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
521  if (!init_static_hmc<sampler>(sampler_ptr, algo)) return 0;
522  if (!init_adapt<sampler>(sampler_ptr, adapt, cont_params)) return 0;
523  break;
524  }
525 
526  case 101: {
528  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
529  if (!init_nuts<sampler>(sampler_ptr, algo)) return 0;
530  if (!init_adapt<sampler>(sampler_ptr, adapt, cont_params)) return 0;
531  break;
532  }
533 
534  case 110: {
536  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
537  if (!init_static_hmc<sampler>(sampler_ptr, algo)) return 0;
538  if (!init_windowed_adapt<sampler>(sampler_ptr, adapt, num_warmup, cont_params))
539  return 0;
540  break;
541  }
542 
543  case 111: {
545  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
546  if (!init_nuts<sampler>(sampler_ptr, algo)) return 0;
547  if (!init_windowed_adapt<sampler>(sampler_ptr, adapt, num_warmup, cont_params))
548  return 0;
549  break;
550  }
551 
552  case 120: {
554  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
555  if (!init_static_hmc<sampler>(sampler_ptr, algo)) return 0;
556  if (!init_windowed_adapt<sampler>(sampler_ptr, adapt, num_warmup, cont_params))
557  return 0;
558  break;
559  }
560 
561  case 121: {
563  sampler_ptr = new sampler(model, base_rng, &std::cout, &std::cout);
564  if (!init_nuts<sampler>(sampler_ptr, algo)) return 0;
565  if (!init_windowed_adapt<sampler>(sampler_ptr, adapt, num_warmup, cont_params))
566  return 0;
567  break;
568  }
569 
570  default:
571  std::cout << "No sampler matching HMC specification!" << std::endl;
572  return 0;
573  }
574 
575  }
576 
577  // Headers
578  writer.write_sample_names(s, sampler_ptr, model);
579  writer.write_diagnostic_names(s, sampler_ptr, model);
580 
581  std::string prefix = "";
582  std::string suffix = "\n";
583  NoOpFunctor startTransitionCallback;
584 
585  // Warm-Up
586  clock_t start = clock();
587 
588  warmup<Model, rng_t>(sampler_ptr, num_warmup, num_samples, num_thin,
589  refresh, save_warmup,
590  writer,
591  s, model, base_rng,
592  prefix, suffix, std::cout,
593  startTransitionCallback);
594 
595  clock_t end = clock();
596  warmDeltaT = (double)(end - start) / CLOCKS_PER_SEC;
597 
598  if (adapt_engaged) {
599  dynamic_cast<mcmc::base_adapter*>(sampler_ptr)->disengage_adaptation();
600  writer.write_adapt_finish(sampler_ptr);
601  }
602 
603  // Sampling
604  start = clock();
605 
606  stan::common::sample<Model, rng_t>(sampler_ptr, num_warmup, num_samples, num_thin,
607  refresh, true,
608  writer,
609  s, model, base_rng,
610  prefix, suffix, std::cout,
611  startTransitionCallback);
612 
613  end = clock();
614  sampleDeltaT = (double)(end - start) / CLOCKS_PER_SEC;
615 
616  writer.write_timing(warmDeltaT, sampleDeltaT);
617 
618  if (sampler_ptr) delete sampler_ptr;
619 
620  }
621 
622  if (output_stream) {
623  output_stream->close();
624  delete output_stream;
625  }
626 
627  if (diagnostic_stream) {
628  diagnostic_stream->close();
629  delete diagnostic_stream;
630  }
631 
632  for (size_t i = 0; i < valid_arguments.size(); ++i)
633  delete valid_arguments.at(i);
634 
635  return 0;
636 
637  }
638 
639  } // namespace common
640 
641 } // namespace stan
642 
643 #endif
int parse_args(int argc, const char *argv[], std::ostream *out=0, std::ostream *err=0)
void gradient(const F &f, const Eigen::Matrix< double, Eigen::Dynamic, 1 > &x, double &fx, Eigen::Matrix< double, Eigen::Dynamic, 1 > &grad_fx)
Calculate the value and the gradient of the specified function at the specified argument.
Definition: autodiff.hpp:93
fvar< T > fabs(const fvar< T > &x)
Definition: fabs.hpp:18
void write_stan(std::ostream *s, const std::string prefix="")
Definition: write_stan.hpp:12
argument * arg(std::string name)
std::string description() const
Definition: argument.hpp:30
double newton_step(M &model, std::vector< double > &params_r, std::vector< int > &params_i, std::ostream *output_stream=0)
Definition: newton.hpp:34
argument * arg(const std::string name)
Writes out a vector as string.
Definition: csv.hpp:19
void gradient(const M &model, const Eigen::Matrix< double, Eigen::Dynamic, 1 > &x, double &f, Eigen::Matrix< double, Eigen::Dynamic, 1 > &grad_f, std::ostream *msgs=0)
Definition: util.hpp:405
argument * arg(std::string name)
void write_error_msg(std::ostream *error_stream, const std::exception &e)
void write_iteration(std::ostream &output_stream, Model &model, RNG &base_rng, double lp, std::vector< double > &cont_vector, std::vector< int > &disc_vector)
int do_bfgs_optimize(ModelT &model, BFGSOptimizerT &bfgs, RNGT &base_rng, double &lp, std::vector< double > &cont_vector, std::vector< int > &disc_vector, std::fstream *output_stream, std::ostream *notice_stream, bool save_iterations, int refresh, StartIterationCallback &callback)
void write_model(std::ostream *s, const std::string model_name, const std::string prefix="")
Definition: write_model.hpp:11
double e()
Return the base of the natural logarithm.
Definition: constants.hpp:86
mcmc_writer writes out headers and samples
Definition: mcmc_writer.hpp:29
int command(int argc, const char *argv[])
Definition: command.hpp:67
virtual argument * arg(const std::string name)
Definition: argument.hpp:67
Represents named arrays with dimensions.
Definition: dump.hpp:902
void print(std::ostream *s, const std::string prefix="")

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