tristanz / ScytheMCMC (http://bytebucket.org/tristanz/scythemcmc/wiki/html/index.html)
A Scythe Markov Chain Monte Carlo C++ Framework
Clone this repository (size: 1.0 MB): HTTPS / SSH
$ hg clone http://bitbucket.org/tristanz/scythemcmc
| commit 12: | fd1ece924824 |
| parent 11: | 6ceff113f5e0 |
| branch: | default |
Autoformatting
Changed (Δ155 bytes):
raw changeset »
src/mcmc.h (193 lines added, 184 lines removed)
15 |
15 |
code needed to write custom MCMC routines. It also provides common MCMC step types, including Gibbs, Metropolis-Hastings, |
16 |
16 |
and Slice sampling. Users can experiment with which sampling steps provide the best results and implement their own sampling |
17 |
17 |
steps as desired. |
18 |
||
18 |
||
19 |
19 |
Scythe MCMC was motivated with the need to combine simpler samplers, such as univariate slice sampling, with more specialized |
20 |
20 |
samplers for particular problems. Future versions of Scythe MCMC will include common samplers for nonparametric Bayesian models, |
21 |
21 |
including a Collapsed Gibbs sampler for the Dirichlet Process, and Slice samplers for the Dirichlet Process and Indian Buffet Process. |
22 |
||
22 |
||
23 |
23 |
There are many choices for writing MCMC samplers. Scythe MCMC is similar to, and heavily inspired by, |
24 |
24 |
<a href="http://darwin.eeb.uconn.edu/mcmc++/mcmc++.html">MCMC++</a>, but is based |
25 |
on the Scythe, which provides convenient matrix types, random number generators, |
|
26 |
and probability distributions. Scythe MCMC is different in focus from |
|
25 |
on the Scythe, which provides convenient matrix types, random number generators, |
|
26 |
and probability distributions. Scythe MCMC is different in focus from |
|
27 |
27 |
<a href="http://mcmcpack.wustl.edu/wiki/index.php/Main_Page">MCMCPack</a>, which |
28 |
28 |
is also based on Scythe and interfaces with R. Users wishing to distribute a specific model to R users |
29 |
29 |
should consider contributing to MCMCPack directly. Unlike MCMCPack, Scythe MCMC makes no attempt to interface with R |
32 |
32 |
development of samplers for many models. |
33 |
33 |
|
34 |
34 |
Even though implementing models in ScytheMCMC requires more work than |
35 |
implementing comparable models in <a href="http://mathstat.helsinki.fi/openbugs/">Bugs</a> |
|
35 |
implementing comparable models in <a href="http://mathstat.helsinki.fi/openbugs/">Bugs</a> |
|
36 |
36 |
or <a href="http://www-ice.iarc.fr/~martyn/software/jags/">JAGS</a>, Scythe MCMC generally |
37 |
37 |
leads to faster samplers that can exploit the particular structure of a given problem. It also |
38 |
38 |
allows development of models that cannot be sampled effectively using either Bugs or Jags, such |
52 |
52 |
- Collapsed gibbs samplers for Dirichlet Process, |
53 |
53 |
- Slice sampler for Dirichlet Process and Indian Buffet Process. |
54 |
54 |
- MIT License. |
55 |
||
55 |
||
56 |
56 |
\section gettingstarted GETTING STARTED |
57 |
||
57 |
||
58 |
58 |
|
59 |
59 |
\section license MIT LICENSE |
60 |
60 |
|
| … | … | @@ -108,9 +108,9 @@ using namespace scythe; |
108 |
108 |
using namespace std; |
109 |
109 |
|
110 |
110 |
/// Scythe column-oriented double matrix typedef. |
111 |
typedef Matrix<double, |
|
111 |
typedef Matrix<double, Col> matrix; |
|
112 |
112 |
/// Scythe column-oriented integer matrix typedef. |
113 |
typedef Matrix<int, |
|
113 |
typedef Matrix<int, Col> imatrix; |
|
114 |
114 |
/// Pair typedef for integers. Used to store (x, y) coordinates of a matrix location. |
115 |
115 |
typedef pair<int, int> ipair; |
116 |
116 |
|
| … | … | @@ -119,7 +119,7 @@ double dInf = std::numeric_limits<double |
119 |
119 |
double iInf = std::numeric_limits<int>::infinity(); |
120 |
120 |
|
121 |
121 |
/// Global Mersenne-Twister random number generator. |
122 |
mersenne myrng; |
|
122 |
mersenne myrng; |
|
123 |
123 |
|
124 |
124 |
|
125 |
125 |
/*! \brief Basic MCMC options. |
| … | … | @@ -129,7 +129,7 @@ mersenne myrng; |
129 |
129 |
*/ |
130 |
130 |
struct MCMCOptions { |
131 |
131 |
/// Sample size. (iterations - burnin)/(thin + 1). |
132 |
int sample_size; |
|
132 |
int sample_size; |
|
133 |
133 |
/// Thinning interval |
134 |
134 |
int thin; |
135 |
135 |
/// Burn in period. |
| … | … | @@ -159,8 +159,8 @@ bool FileExists(string strFilename) { |
159 |
159 |
int intStat; |
160 |
160 |
|
161 |
161 |
// Attempt to get the file attributes |
162 |
intStat = stat(strFilename.c_str(),&stFileInfo); |
|
163 |
if(intStat == 0) { |
|
162 |
intStat = stat(strFilename.c_str(), &stFileInfo); |
|
163 |
if (intStat == 0) { |
|
164 |
164 |
// We were able to get the file attributes |
165 |
165 |
// so the file obviously exists. |
166 |
166 |
blnReturn = true; |
| … | … | @@ -173,7 +173,7 @@ bool FileExists(string strFilename) { |
173 |
173 |
// more details on why stat failed. |
174 |
174 |
blnReturn = false; |
175 |
175 |
} |
176 |
||
176 |
||
177 |
177 |
return(blnReturn); |
178 |
178 |
} |
179 |
179 |
|
| … | … | @@ -181,12 +181,11 @@ bool FileExists(string strFilename) { |
181 |
181 |
* |
182 |
182 |
*/ |
183 |
183 |
template <class T> |
184 |
inline string to_csv (const T& t) |
|
185 |
{ |
|
184 |
inline string to_csv (const T& t) { |
|
186 |
185 |
std::stringstream ss; |
187 |
186 |
ss << t; |
188 |
187 |
string s = ss.str(); |
189 |
replace(s.begin(), |
|
188 |
replace(s.begin(), s.end(), ' ', ','); |
|
190 |
189 |
return s; |
191 |
190 |
} |
192 |
191 |
|
| … | … | @@ -209,7 +208,7 @@ inline string to_csv (const T& t) |
209 |
208 |
Example: ./base_model --config-file=base_model.cfg --out-file=out.txt --chains=1 --sample-size=1000 |
210 |
209 |
--burnin=0 --thin=1 --random-seed=12345 |
211 |
210 |
</pre> |
212 |
*/ |
|
211 |
*/ |
|
213 |
212 |
void ShowUsage() { |
214 |
213 |
cout << " Usage:" << endl |
215 |
214 |
<< " --help \t\t\t displays help message" << endl |
| … | … | @@ -220,7 +219,7 @@ void ShowUsage() { |
220 |
219 |
<< " --burnin=arg \t\t burn in period" << endl |
221 |
220 |
<< " --thin=arg \t\t\t thinning iterval (0 = no thinning)" << endl |
222 |
221 |
<< " --random-seed=arg \t\t random number seed" << endl << endl; |
223 |
||
222 |
||
224 |
223 |
cout << " Example: ./base_model --config-file=base_model.cfg --out-file=out.txt --chains=1 --sample-size=1000" << endl |
225 |
224 |
<< "\t --burnin=0 --thin=1 --random-seed=12345" << endl << endl; |
226 |
225 |
} |
| … | … | @@ -235,7 +234,7 @@ void ShowUsage() { |
235 |
234 |
*/ |
236 |
235 |
void DefaultStartUp(int argc, char* argv[]) { |
237 |
236 |
cout << "ScytheMCMC v. " << SCYTHE_MCMC_VERSION << endl << endl; |
238 |
||
237 |
||
239 |
238 |
// Config parser is based on SimpleOpt Library. |
240 |
239 |
// See: http://code.jellycan.com/simpleopt/ |
241 |
240 |
enum { OPT_SAMPLE_SIZE, OPT_THIN, OPT_BURNIN, OPT_CHAINS, OPT_RANDOM_SEED, OPT_CONFIG_FILE, OPT_OUT_FILE, OPT_HELP }; |
| … | … | @@ -255,71 +254,70 @@ void DefaultStartUp(int argc, char* argv |
255 |
254 |
int setflags = 0; |
256 |
255 |
while (args.Next()) { |
257 |
256 |
if (args.LastError() == SO_SUCCESS) { |
258 |
switch(args.OptionId()) { |
|
259 |
case OPT_HELP: |
|
260 |
ShowUsage(); |
|
261 |
exit(0); |
|
262 |
break; |
|
263 |
case OPT_CONFIG_FILE: |
|
264 |
setflags++; |
|
265 |
mcmc_options.config_file = args.OptionArg(); |
|
266 |
break; |
|
267 |
case OPT_OUT_FILE: |
|
268 |
setflags++; |
|
269 |
mcmc_options.out_file = args.OptionArg(); |
|
270 |
break; |
|
271 |
case OPT_CHAINS: |
|
272 |
setflags++; |
|
273 |
mcmc_options.chains = atoi(args.OptionArg()); |
|
274 |
break; |
|
275 |
case OPT_SAMPLE_SIZE: |
|
276 |
setflags++; |
|
277 |
mcmc_options.sample_size = atoi(args.OptionArg()); |
|
278 |
break; |
|
279 |
case OPT_BURNIN: |
|
280 |
setflags++; |
|
281 |
mcmc_options.burnin = atoi(args.OptionArg()); |
|
282 |
break; |
|
283 |
case OPT_THIN: |
|
284 |
setflags++; |
|
285 |
mcmc_options.thin = atoi(args.OptionArg()); |
|
286 |
break; |
|
287 |
case OPT_RANDOM_SEED: |
|
288 |
setflags++; |
|
289 |
mcmc_options.random_seed = atoi(args.OptionArg()); |
|
290 |
|
|
257 |
switch (args.OptionId()) { |
|
258 |
case OPT_HELP: |
|
259 |
ShowUsage(); |
|
260 |
exit(0); |
|
261 |
break; |
|
262 |
case OPT_CONFIG_FILE: |
|
263 |
setflags++; |
|
264 |
mcmc_options.config_file = args.OptionArg(); |
|
265 |
break; |
|
266 |
case OPT_OUT_FILE: |
|
267 |
setflags++; |
|
268 |
mcmc_options.out_file = args.OptionArg(); |
|
269 |
break; |
|
270 |
case OPT_CHAINS: |
|
271 |
setflags++; |
|
272 |
mcmc_options.chains = atoi(args.OptionArg()); |
|
273 |
break; |
|
274 |
case OPT_SAMPLE_SIZE: |
|
275 |
setflags++; |
|
276 |
mcmc_options.sample_size = atoi(args.OptionArg()); |
|
277 |
break; |
|
278 |
case OPT_BURNIN: |
|
279 |
setflags++; |
|
280 |
mcmc_options.burnin = atoi(args.OptionArg()); |
|
281 |
break; |
|
282 |
case OPT_THIN: |
|
283 |
setflags++; |
|
284 |
mcmc_options.thin = atoi(args.OptionArg()); |
|
285 |
break; |
|
286 |
case OPT_RANDOM_SEED: |
|
287 |
setflags++; |
|
288 |
mcmc_options.random_seed = atoi(args.OptionArg()); |
|
289 |
break; |
|
291 |
290 |
} |
292 |
} |
|
293 |
else { |
|
291 |
} else { |
|
294 |
292 |
cout << "Invalid argument: " << args.OptionText() << endl; |
295 |
293 |
exit(1); |
296 |
294 |
} |
297 |
295 |
} |
298 |
||
296 |
||
299 |
297 |
// Check that all required flags are set. |
300 |
if |
|
298 |
if (setflags != 7) { |
|
301 |
299 |
ShowUsage(); |
302 |
300 |
exit(1); |
303 |
301 |
} |
304 |
302 |
|
305 |
303 |
// Check argument values. |
306 |
if |
|
304 |
if (mcmc_options.sample_size <= 0) { |
|
307 |
305 |
cout << "Sample size must be positive.\n"; |
308 |
306 |
exit(1); |
309 |
307 |
} |
310 |
if |
|
308 |
if (mcmc_options.burnin < 0) { |
|
311 |
309 |
cout << "Burn in cannot be negative.\n"; |
312 |
310 |
exit(1); |
313 |
311 |
} |
314 |
if |
|
312 |
if (mcmc_options.thin < 0) { |
|
315 |
313 |
cout << "Thinning interval cannot be negative.\n"; |
316 |
314 |
exit(1); |
317 |
315 |
} |
318 |
if |
|
316 |
if (!FileExists(mcmc_options.config_file)) { |
|
319 |
317 |
cout << "Config file does not exist.\n"; |
320 |
318 |
exit(1); |
321 |
319 |
} |
322 |
||
320 |
||
323 |
321 |
// Seed random number generator. |
324 |
322 |
myrng.initialize(mcmc_options.random_seed); |
325 |
323 |
|
| … | … | @@ -334,7 +332,7 @@ void DefaultStartUp(int argc, char* argv |
334 |
332 |
} |
335 |
333 |
|
336 |
334 |
|
337 |
/*! \brief Main parameter class. |
|
335 |
/*! \brief Main parameter class. |
|
338 |
336 |
* |
339 |
337 |
* The model is defined as many instances of parameter subclasses. Different Step types require different methods |
340 |
338 |
* to be implemented in each Parameter subclass. |
| … | … | @@ -348,7 +346,7 @@ void DefaultStartUp(int argc, char* argv |
348 |
346 |
* GibbsStep: |
349 |
347 |
* - Parameter::StartingValue |
350 |
348 |
* - Parameter::RandomPosterior |
351 |
* |
|
349 |
* |
|
352 |
350 |
* Metropolis-Hastings: |
353 |
351 |
* - Parameter::StartingValue |
354 |
352 |
* - Parameter::LogDensity |
| … | … | @@ -363,25 +361,25 @@ void DefaultStartUp(int argc, char* argv |
363 |
361 |
* \section examples Examples: |
364 |
362 |
* |
365 |
363 |
* \subsection example1 Normal mean parameter with normal prior, known standard deviation: |
366 |
* |
|
364 |
* |
|
367 |
365 |
\code |
368 |
366 |
// Priors |
369 |
367 |
double mean_mu = 0; |
370 |
368 |
double mean_sigma = 2; |
371 |
||
369 |
||
372 |
370 |
// Parameters |
373 |
371 |
double mean = 0; // free parameter |
374 |
372 |
double sd = 1; // known |
375 |
||
373 |
||
376 |
374 |
// Data |
377 |
375 |
matrix X('X.txt'); |
378 |
||
376 |
||
379 |
377 |
// Define the mean parameter, implementing methods required for GibbsStep. |
380 |
class MeanParameter : public Parameter |
|
378 |
class MeanParameter : public Parameter<double> { |
|
381 |
379 |
public: |
382 |
380 |
/// Default constructors that call base constructors. (REQUIRED) |
383 |
MeanParameter() : Parameter() {} |
|
384 |
MeanParameter(bool track, string name) : Parameter(track, name) {} |
|
381 |
MeanParameter() : Parameter<double>() {} |
|
382 |
MeanParameter(bool track, string name) : Parameter<double>(track, name) {} |
|
385 |
383 |
|
386 |
384 |
/// Draw a random value from analytical posterior for GibbsStep. |
387 |
385 |
double RandomPosterior() { |
| … | … | @@ -422,39 +420,49 @@ public: |
422 |
420 |
* \param label Label of parameter for tracking purposes. |
423 |
421 |
*/ |
424 |
422 |
Parameter(bool track, string label) : track_(track), label_(label) {} |
425 |
||
423 |
||
426 |
424 |
/// Function for deterministic nodes. |
427 |
425 |
/// \return Function value. |
428 |
virtual ParameterStorageType Function() { return 0.0; }; |
|
429 |
||
426 |
virtual ParameterStorageType Function() { |
|
427 |
return 0.0; |
|
428 |
}; |
|
429 |
||
430 |
430 |
/// Starting value. |
431 |
431 |
/// \return Starting value. |
432 |
virtual ParameterStorageType StartingValue() { return 0.0; }; |
|
433 |
||
432 |
virtual ParameterStorageType StartingValue() { |
|
433 |
return 0.0; |
|
434 |
}; |
|
435 |
||
434 |
436 |
/// Log of the probability density (plus constant) |
435 |
437 |
/// \param value Value of parameter to evaluate density at. |
436 |
438 |
/// \return Log of probability density (plus constant) |
437 |
virtual double LogDensity(double value) { |
|
439 |
virtual double LogDensity(double value) { |
|
440 |
return 0.0; |
|
441 |
} |
|
438 |
442 |
|
439 |
443 |
/// Return a random draw from the posterior. |
440 |
444 |
/// Random draw from posterior is called by GibbsStep. |
441 |
445 |
/// \return Random draw from posterior. |
442 |
virtual ParameterStorageType RandomPosterior() { return 0.0; } |
|
443 |
||
446 |
virtual ParameterStorageType RandomPosterior() { |
|
447 |
return 0.0; |
|
448 |
} |
|
449 |
||
444 |
450 |
/// Value of parameter. |
445 |
451 |
/// \return Parameter value |
446 |
virtual ParameterStorageType Value() { |
|
452 |
virtual ParameterStorageType Value() { |
|
453 |
return 0.0; |
|
454 |
}; |
|
447 |
455 |
|
448 |
456 |
/// Save a new value of the parameter. |
449 |
457 |
/// \param new_value New value to save. |
450 |
458 |
virtual void Save(double new_value) {}; |
451 |
||
459 |
||
452 |
460 |
/// Parameter is tracked / saved. |
453 |
461 |
/// \return True if parameter is tracked. |
454 |
462 |
bool Track() { |
455 |
463 |
return track_; |
456 |
464 |
} |
457 |
||
465 |
||
458 |
466 |
/// String label of parameter. |
459 |
467 |
/// \return Label of parameter, for purposes of saving output. |
460 |
468 |
string Label() { |
| … | … | @@ -480,7 +488,7 @@ private: |
480 |
488 |
* |
481 |
489 |
* \ingroup steps |
482 |
490 |
* |
483 |
* The step (Gibbs, Metropolis-Hastings, Slice, etc) describes how the sampler |
|
491 |
* The step (Gibbs, Metropolis-Hastings, Slice, etc) describes how the sampler |
|
484 |
492 |
* calculates the next value of each parameter. The key function is Step::DoStep, which is |
485 |
493 |
* equivalent to the Execute function in a <a href="http://en.wikipedia.org/wiki/Command_pattern">Command Pattern</a>. |
486 |
494 |
* Samplers consists of a many of steps. |
| … | … | @@ -496,34 +504,40 @@ public: |
496 |
504 |
/*! \brief Take step. |
497 |
505 |
* |
498 |
506 |
* Executes the main step function, such as taking a MH step or deterministic step. |
499 |
*/ |
|
507 |
*/ |
|
500 |
508 |
virtual void DoStep() {} |
501 |
509 |
/*! \brief Set starting value. |
502 |
510 |
* |
503 |
511 |
* Calls the parameter's Parameter::Starting function and then saves the result using Parameter::Save. |
504 |
512 |
*/ |
505 |
513 |
virtual void Start() {} |
506 |
||
514 |
||
507 |
515 |
/*! \brief Return parameter value |
508 |
516 |
* |
509 |
517 |
* \return String representation of parameter value for csv output. |
510 |
518 |
* \see Parameter::Value |
511 |
519 |
*/ |
512 |
virtual string ParameterValue() { return ""; } |
|
513 |
||
520 |
virtual string ParameterValue() { |
|
521 |
return ""; |
|
522 |
} |
|
523 |
||
514 |
524 |
/*! \brief Return parameter label |
515 |
525 |
* |
516 |
526 |
* \return The label of the parameter associated with the step instance. |
517 |
527 |
* \see Parameter::Label |
518 |
528 |
*/ |
519 |
virtual string ParameterLabel() { |
|
529 |
virtual string ParameterLabel() { |
|
530 |
return ""; |
|
531 |
} |
|
520 |
532 |
|
521 |
533 |
/*! Return the tracking status |
522 |
534 |
* |
523 |
535 |
* \return The tracking status of the parameter associated with the step instance. |
524 |
536 |
* \see Parameter::Track |
525 |
537 |
*/ |
526 |
virtual bool ParameterTrack() { |
|
538 |
virtual bool ParameterTrack() { |
|
539 |
return true; |
|
540 |
} |
|
527 |
541 |
}; |
528 |
542 |
|
529 |
543 |
/*! \brief Gibbs step. |
| … | … | @@ -531,7 +545,7 @@ public: |
531 |
545 |
* \ingroup steps |
532 |
546 |
* |
533 |
547 |
* A univariate Gibbs step draws from the Parameter::RandomPosterior function of a Parameter and then saves the result |
534 |
* using Parameter:Save. |
|
548 |
* using Parameter:Save. |
|
535 |
549 |
*/ |
536 |
550 |
template <typename ParameterType, typename ParameterStorageType> |
537 |
551 |
class GibbsStep: public Step { |
| … | … | @@ -556,25 +570,25 @@ public: |
556 |
570 |
} |
557 |
571 |
|
558 |
572 |
string ParameterLabel() { |
559 |
|
|
573 |
return parameter_.Label(); |
|
560 |
574 |
} |
561 |
575 |
|
562 |
576 |
string ParameterValue() { |
563 |
|
|
577 |
return to_csv<ParameterStorageType>(parameter_.Value()); |
|
564 |
578 |
} |
565 |
579 |
|
566 |
580 |
bool ParameterTrack() { |
567 |
|
|
581 |
return parameter_.Track(); |
|
568 |
582 |
} |
569 |
583 |
private: |
570 |
584 |
/// Parameter associated with step instance. |
571 |
ParameterType parameter_; |
|
585 |
ParameterType parameter_; |
|
572 |
586 |
}; |
573 |
587 |
|
574 |
588 |
/*! \brief Deterministic function step. |
575 |
589 |
* |
576 |
590 |
* \ingroup steps |
577 |
* |
|
591 |
* |
|
578 |
592 |
* Deterministic nodes can be helpful to track summary statistics or to reduce computations through intermediate use |
579 |
593 |
* of sufficient statistics across multiple parameters. FunctionStep calls the parameters Parameter::Function method |
580 |
594 |
* and saves the result using Parameter::Save. |
| … | … | @@ -609,32 +623,32 @@ public: |
609 |
623 |
} |
610 |
624 |
|
611 |
625 |
string ParameterLabel() { |
612 |
|
|
626 |
return parameter_.Label(); |
|
613 |
627 |
} |
614 |
628 |
|
615 |
629 |
string ParameterValue() { |
616 |
|
|
630 |
return to_csv<ParameterStorageType>(parameter_.Value()); |
|
617 |
631 |
} |
618 |
632 |
|
619 |
633 |
bool ParameterTrack() { |
620 |
|
|
634 |
return parameter_.Track(); |
|
621 |
635 |
} |
622 |
636 |
private: |
623 |
637 |
/// Parameter associated with step instance. |
624 |
ParameterType parameter_; |
|
638 |
ParameterType parameter_; |
|
625 |
639 |
}; |
626 |
640 |
|
627 |
641 |
/*! \defgroup proposals Metropolis-Hastings Proposals |
628 |
* |
|
642 |
* |
|
629 |
643 |
* The MetropStep Metropolis-Hastings class requires both a Parameter instance |
630 |
644 |
* and a Proposal instance. Proposal instances define a Draw and LogDensity method. |
631 |
645 |
* The constructor should set a tuning parameter. |
632 |
646 |
* |
633 |
647 |
* MetroStep::DoStep uses the Draw method to draw new proposed values for the parameter |
634 |
* and the LogDensity to calculate the proposal terms in the acceptance \f$\alpha\f$. For |
|
648 |
* and the LogDensity to calculate the proposal terms in the acceptance \f$\alpha\f$. For |
|
635 |
649 |
* symmetric proposal distributions returning 0.0 is enough. |
636 |
650 |
*/ |
637 |
||
651 |
||
638 |
652 |
/*! \brief Normal proposal for Metropolis-Hastings. |
639 |
653 |
* |
640 |
654 |
* \ingroup proposals |
| … | … | @@ -649,7 +663,7 @@ public: |
649 |
663 |
* \param standard_deviation Tuning parameter for normal proposal. |
650 |
664 |
*/ |
651 |
665 |
NormalProposal(double standard_deviation) : standard_deviation_(standard_deviation) {} |
652 |
||
666 |
||
653 |
667 |
/*! \brief Draw from normal proposal |
654 |
668 |
* |
655 |
669 |
* \param starting_value Starting value. |
| … | … | @@ -657,7 +671,7 @@ public: |
657 |
671 |
double Draw(double starting_value) { |
658 |
672 |
return myrng.rnorm(starting_value, standard_deviation_); |
659 |
673 |
} |
660 |
||
674 |
||
661 |
675 |
/*! \brief Log probability of proposal new value, given starting value. |
662 |
676 |
* |
663 |
677 |
* \note Needs to be implemented but can be 0.0 if proposal is symmetric, which it is. |
| … | … | @@ -667,14 +681,14 @@ public: |
667 |
681 |
double LogDensity(double new_value, double starting_value) { |
668 |
682 |
return 0.0; // Symmetric, doesn't matter. |
669 |
683 |
} |
670 |
||
684 |
||
671 |
685 |
private: |
672 |
686 |
double standard_deviation_; |
673 |
687 |
}; |
674 |
688 |
|
675 |
689 |
|
676 |
690 |
/*! \brief Beta proposal for Metropolis-Hastings. |
677 |
* |
|
691 |
* |
|
678 |
692 |
* \ingroup proposals |
679 |
693 |
* |
680 |
694 |
* Useful proposal type for parameters with support between 0 and 1. |
| … | … | @@ -704,9 +718,9 @@ public: |
704 |
718 |
* \param idenominator Tuning parameter equal to the inverse denominator \f$1/d\f$ of a Beta distribution. |
705 |
719 |
*/ |
706 |
720 |
BetaProposal(double idenominator) { |
707 |
denom_ = 1 |
|
721 |
denom_ = 1 / idenominator; |
|
708 |
722 |
} |
709 |
||
723 |
||
710 |
724 |
/*! \brief Draw from Beta proposal |
711 |
725 |
* |
712 |
726 |
* \param starting_value Starting value (mean of Beta distribution). |
| … | … | @@ -716,9 +730,9 @@ public: |
716 |
730 |
double beta = alpha - denom_; |
717 |
731 |
return myrng.rbeta(alpha, beta); |
718 |
732 |
} |
719 |
||
733 |
||
720 |
734 |
/*! \brief Log probability of proposal new value, given starting value. |
721 |
* |
|
735 |
* |
|
722 |
736 |
* \param starting_value Starting value. |
723 |
737 |
* \param new_value Proposed new value. |
724 |
738 |
*/ |
| … | … | @@ -727,19 +741,19 @@ public: |
727 |
741 |
double beta = alpha - denom_; |
728 |
742 |
return dbeta(new_value, alpha, beta); |
729 |
743 |
} |
730 |
||
744 |
||
731 |
745 |
private: |
732 |
746 |
double denom_; |
733 |
747 |
}; |
734 |
748 |
|
735 |
749 |
|
736 |
750 |
/*! \brief Log normal proposal for Metropolis-Hastings. |
737 |
* |
|
751 |
* |
|
738 |
752 |
* \ingroup proposals |
739 |
753 |
* |
740 |
754 |
* Useful proposal type for parameters with support between 0 and positive infinity. |
741 |
755 |
* |
742 |
* For convenience, the log normal proposal is parameterized using the unlogged mean (starting value) |
|
756 |
* For convenience, the log normal proposal is parameterized using the unlogged mean (starting value) |
|
743 |
757 |
* and the (positive) log standard deviation. This differs from how scythe::dlnorm is parameterized. |
744 |
758 |
* |
745 |
759 |
*/ |
| … | … | @@ -754,7 +768,7 @@ public: |
754 |
768 |
* \param logsd Tuning parameter equal to the log standard deviation. |
755 |
769 |
*/ |
756 |
770 |
LogNormalProposal(double logsd) : logsd_(logsd) {} |
757 |
||
771 |
||
758 |
772 |
/*! \brief Draw from log normal proposal |
759 |
773 |
* |
760 |
774 |
* \param starting_value Starting value (unlogged mean of log normal). |
| … | … | @@ -763,9 +777,9 @@ public: |
763 |
777 |
double logmean = log(starting_value); |
764 |
778 |
return myrng.rlnorm(logmean, logsd_); |
765 |
779 |
} |
766 |
||
780 |
||
767 |
781 |
/*! \brief Log probability of proposal new value, given starting value. |
768 |
* |
|
782 |
* |
|
769 |
783 |
* \param starting_value Starting value. |
770 |
784 |
* \param new_value Proposed new value. |
771 |
785 |
*/ |
| … | … | @@ -773,7 +787,7 @@ public: |
773 |
787 |
double logmean = log(starting_value); |
774 |
788 |
return dlnorm(new_value, logmean, logsd_); |
775 |
789 |
} |
776 |
||
790 |
||
777 |
791 |
private: |
778 |
792 |
double logsd_; |
779 |
793 |
}; |
| … | … | @@ -781,7 +795,7 @@ private: |
781 |
795 |
/*! \brief Metropolis Hastings step |
782 |
796 |
* |
783 |
797 |
* \ingroup steps |
784 |
* |
|
798 |
* |
|
785 |
799 |
* Basic univariate Metropolis-Hastings step. Requires both a Parameter and Proposal instance. |
786 |
800 |
*/ |
787 |
801 |
template <typename ParameterType, typename ProposalType> |
| … | … | @@ -796,7 +810,7 @@ public: |
796 |
810 |
* \param proposal A Proposal instance that implements Proposal::LogDensity and Proposal::Draw. |
797 |
811 |
*/ |
798 |
812 |
MetropStep(ParameterType parameter, ProposalType proposal) : parameter_(parameter), proposal_(proposal) {} |
799 |
||
813 |
||
800 |
814 |
/*! \brief Take a function step for the parameter. |
801 |
815 |
* |
802 |
816 |
* Calculates the value of Parameter::Function and then saves the result using Parameter::Save. |
| … | … | @@ -807,26 +821,26 @@ public: |
807 |
821 |
double old_value = parameter_.Value(); |
808 |
822 |
// MH accept/reject criteria |
809 |
823 |
double alpha = parameter_.LogDensity(new_value) - parameter_.LogDensity(old_value) |
810 |
+ proposal_.LogDensity(old_value, new_value) - proposal_.LogDensity(new_value, old_value); |
|
811 |
if(myrng.runif() < min(exp(alpha), 1.0)) { |
|
824 |
+ proposal_.LogDensity(old_value, new_value) - proposal_.LogDensity(new_value, old_value); |
|
825 |
if (myrng.runif() < min(exp(alpha), 1.0)) { |
|
812 |
826 |
parameter_.Save(new_value); |
813 |
827 |
} |
814 |
828 |
} |
815 |
||
829 |
||
816 |
830 |
void Start() { |
817 |
831 |
parameter_.Save(parameter_.StartingValue()); |
818 |
832 |
} |
819 |
833 |
|
820 |
834 |
string ParameterLabel() { |
821 |
|
|
835 |
return parameter_.Label(); |
|
822 |
836 |
} |
823 |
837 |
|
824 |
838 |
string ParameterValue() { |
825 |
|
|
839 |
return to_csv<double>(parameter_.Value()); |
|
826 |
840 |
} |
827 |
841 |
|
828 |
842 |
bool ParameterTrack() { |
829 |
|
|
843 |
return parameter_.Track(); |
|
830 |
844 |
} |
831 |
845 |
private: |
832 |
846 |
/// Parameter associated with step instance. |
| … | … | @@ -840,7 +854,7 @@ private: |
840 |
854 |
* |
841 |
855 |
* Basic univariate slice sampling step with stepping out and shrinkage. Performs a slice sampling update from an initial |
842 |
856 |
* point to a new point that leaves invariant the distribution with the specifified log density functions. |
843 |
* |
|
857 |
* |
|
844 |
858 |
* The log desnity function may return -Inf for points outside the support of the distribution. |
845 |
859 |
* If a lower and/or upper bound is specified for the support, the log density function will not be called outside |
846 |
860 |
* such limits. |
| … | … | @@ -864,9 +878,9 @@ public: |
864 |
878 |
* \param lower Lower bound on the support of the distribution (default = -Infinity) |
865 |
879 |
* \param upper Upper bound on the support of the distribution (default = Infinity) |
866 |
880 |
*/ |
867 |
SliceStep(ParameterType parameter, double w = 1.0, double lower=-dInf, double upper=dInf) : |
|
868 |
parameter_(parameter), w_(w), lower_(lower), upper_(upper) {} |
|
869 |
||
881 |
SliceStep(ParameterType parameter, double w = 1.0, double lower = -dInf, double upper = dInf) : |
|
882 |
parameter_(parameter), w_(w), lower_(lower), upper_(upper) {} |
|
883 |
||
870 |
884 |
/*! \brief Take a slice sampling step for the parameter. |
871 |
885 |
* |
872 |
886 |
*/ |
| … | … | @@ -874,83 +888,82 @@ public: |
874 |
888 |
// Find the log density at the initial point. |
875 |
889 |
double x0 = parameter_.Value(); |
876 |
890 |
double gx0 = parameter_.LogDensity(x0); |
877 |
||
891 |
||
878 |
892 |
// Determine slice level, in log terms |
879 |
893 |
double logy = gx0 - myrng.rexp(1); |
880 |
||
894 |
||
881 |
895 |
//Find the initial interval to sample from. |
882 |
896 |
double u = myrng.runif() * w_; |
883 |
897 |
double L = x0 - u; |
884 |
898 |
double R = x0 + (w_ - u); |
885 |
||
899 |
||
886 |
900 |
// Expand the interval until its ends are outside the slice, or |
887 |
901 |
// until the limit on steps is reached. |
888 |
||
902 |
||
889 |
903 |
// allow infinite steps... could hang! |
890 |
904 |
// FIXME: Add check for too many iterations and exit with error message. |
891 |
while(true) { |
|
892 |
if(L <= lower_) { |
|
905 |
while (true) { |
|
906 |
if (L <= lower_) { |
|
893 |
907 |
break; |
894 |
908 |
} |
895 |
if |
|
909 |
if (parameter_.LogDensity(L) <= logy) { |
|
896 |
910 |
break; |
897 |
911 |
} |
898 |
912 |
L = L - w_; |
899 |
913 |
} |
900 |
||
901 |
while(true) { |
|
902 |
if(R >= upper_) { |
|
914 |
||
915 |
while (true) { |
|
916 |
if (R >= upper_) { |
|
903 |
917 |
break; |
904 |
918 |
} |
905 |
if |
|
919 |
if (parameter_.LogDensity(R) <= logy) { |
|
906 |
920 |
break; |
907 |
921 |
} |
908 |
922 |
R = R + w_; |
909 |
923 |
} |
910 |
||
924 |
||
911 |
925 |
// Shrink interval to lower and upper bounds. |
912 |
if |
|
926 |
if (L < lower_) { |
|
913 |
927 |
L = lower_; |
914 |
928 |
} |
915 |
if |
|
929 |
if (R > upper_) { |
|
916 |
930 |
R = upper_; |
917 |
931 |
} |
918 |
||
932 |
||
919 |
933 |
// Sample from the interval, shrinking it on each rejection |
920 |
934 |
double x1, gx1; |
921 |
while |
|
935 |
while (true) { |
|
922 |
936 |
x1 = myrng.runif() * (R - L) + L; // Sample between L and R, uniformly. |
923 |
937 |
gx1 = parameter_.LogDensity(x1); |
924 |
if |
|
938 |
if (gx1 >= logy) { |
|
925 |
939 |
break; |
926 |
940 |
} |
927 |
||
928 |
if(x1 > x0) { |
|
941 |
||
942 |
if (x1 > x0) { |
|
929 |
943 |
R = x1; |
930 |
} |
|
931 |
else { |
|
944 |
} else { |
|
932 |
945 |
L = x1; |
933 |
946 |
} |
934 |
947 |
} |
935 |
||
948 |
||
936 |
949 |
// Save the point sampled |
937 |
950 |
parameter_.Save(x1); |
938 |
951 |
} |
939 |
||
952 |
||
940 |
953 |
void Start() { |
941 |
954 |
parameter_.Save(parameter_.StartingValue()); |
942 |
955 |
} |
943 |
956 |
|
944 |
957 |
string ParameterLabel() { |
945 |
|
|
958 |
return parameter_.Label(); |
|
946 |
959 |
} |
947 |
960 |
|
948 |
961 |
string ParameterValue() { |
949 |
|
|
962 |
return to_csv<double>(parameter_.Value()); |
|
950 |
963 |
} |
951 |
964 |
|
952 |
965 |
bool ParameterTrack() { |
953 |
|
|
966 |
return parameter_.Track(); |
|
954 |
967 |
} |
955 |
968 |
private: |
956 |
969 |
/// Parameter associated with step instance. |
| … | … | @@ -993,7 +1006,7 @@ public: |
993 |
1006 |
// Add step to step stack. |
994 |
1007 |
steps_.push_back(step); |
995 |
1008 |
// Add index to tracking stack, if necessary tracked. |
996 |
if |
|
1009 |
if (steps_.back().ParameterTrack()) { |
|
997 |
1010 |
tracks_.push_back(steps_.size() - 1); |
998 |
1011 |
} |
999 |
1012 |
} |
| … | … | @@ -1003,18 +1016,17 @@ public: |
1003 |
1016 |
* \param progress Display a progress bar. |
1004 |
1017 |
*/ |
1005 |
1018 |
void Iterate(int number_of_iterations, bool progress = false) { |
1006 |
if |
|
1019 |
if (progress) { |
|
1007 |
1020 |
boost::progress_display show_progress(number_of_iterations); |
1008 |
for(int iter = 0; iter < number_of_iterations; ++iter) { |
|
1009 |
for(int i = 0; i < steps_.size(); ++i) { |
|
1021 |
for (int iter = 0; iter < number_of_iterations; ++iter) { |
|
1022 |
for (int i = 0; i < steps_.size(); ++i) { |
|
1010 |
1023 |
steps_[i].DoStep(); |
1011 |
1024 |
} |
1012 |
1025 |
++show_progress; |
1013 |
1026 |
} |
1014 |
} |
|
1015 |
else { |
|
1016 |
for(int iter = 0; iter < number_of_iterations; ++iter) { |
|
1017 |
for(int i = 0; i < steps_.size(); ++i) { |
|
1027 |
} else { |
|
1028 |
for (int iter = 0; iter < number_of_iterations; ++iter) { |
|
1029 |
for (int i = 0; i < steps_.size(); ++i) { |
|
1018 |
1030 |
steps_[i].DoStep(); |
1019 |
1031 |
} |
1020 |
1032 |
} |
| … | … | @@ -1028,32 +1040,31 @@ public: |
1028 |
1040 |
void Run() { |
1029 |
1041 |
// Timer |
1030 |
1042 |
boost::timer timer; |
1031 |
||
1043 |
||
1032 |
1044 |
// Status of sampler... |
1033 |
1045 |
cout << "Running sampler..." << endl; |
1034 |
1046 |
cout << "Number of steps added: " << NumberOfSteps() << endl; |
1035 |
1047 |
cout << "Number of tracked steps added: " << NumberOfTrackedSteps() << endl; |
1036 |
||
1048 |
||
1037 |
1049 |
// Opening output file |
1038 |
1050 |
cout << "Opening output file: " << out_file_ << endl; |
1039 |
1051 |
ofstream outfile(out_file_.c_str()); |
1040 |
if |
|
1052 |
if (!outfile.is_open()) { |
|
1041 |
1053 |
cerr << "ERROR: Cannot open file!"; |
1042 |
1054 |
exit(1); |
1043 |
1055 |
} |
1044 |
||
1045 |
for(int k = 0; k < tracks_.size(); ++k) { |
|
1046 |
if(k == tracks_.size() - 1) { |
|
1056 |
||
1057 |
for (int k = 0; k < tracks_.size(); ++k) { |
|
1058 |
if (k == tracks_.size() - 1) { |
|
1047 |
1059 |
outfile << steps_[tracks_[k]].ParameterLabel() << endl; |
1048 |
} |
|
1049 |
else { |
|
1060 |
} else { |
|
1050 |
1061 |
outfile << steps_[tracks_[k]].ParameterLabel() << ","; |
1051 |
1062 |
} |
1052 |
1063 |
} |
1053 |
1064 |
|
1054 |
1065 |
// Setting starting value: |
1055 |
1066 |
cout << "Setting starting values..." << endl; |
1056 |
for |
|
1067 |
for (int i = 0; i < steps_.size(); ++i) { |
|
1057 |
1068 |
steps_[i].Start(); |
1058 |
1069 |
} |
1059 |
1070 |
|
| … | … | @@ -1063,23 +1074,22 @@ public: |
1063 |
1074 |
|
1064 |
1075 |
cout << endl << "Sampling..." << endl; |
1065 |
1076 |
boost::progress_display show_progress(sample_size_); |
1066 |
for |
|
1077 |
for (int i = 0; i < sample_size_; ++i) { |
|
1067 |
1078 |
Iterate(thin_ + 1); |
1068 |
1079 |
// Save data |
1069 |
for(int k = 0; k < tracks_.size(); ++k) { |
|
1070 |
if(k == tracks_.size() - 1) { |
|
1080 |
for (int k = 0; k < tracks_.size(); ++k) { |
|
1081 |
if (k == tracks_.size() - 1) { |
|
1071 |
1082 |
outfile << steps_[tracks_[k]].ParameterValue() << endl; |
1072 |
} |
|
1073 |
else { |
|
1083 |
} else { |
|
1074 |
1084 |
outfile << steps_[tracks_[k]].ParameterValue() << ","; |
1075 |
1085 |
} |
1076 |
1086 |
} |
1077 |
1087 |
//Show progress |
1078 |
1088 |
++show_progress; |
1079 |
1089 |
} |
1080 |
||
1090 |
||
1081 |
1091 |
outfile.close(); |
1082 |
||
1092 |
||
1083 |
1093 |
cout << "Total elapsed time: " << timer.elapsed() << " seconds" << endl; |
1084 |
1094 |
} |
1085 |
1095 |
/*! \brief Number of steps in one sampler iteration. |
| … | … | @@ -1111,16 +1121,15 @@ private: |
1111 |
1121 |
* Useful if === is too strict. |
1112 |
1122 |
*/ |
1113 |
1123 |
bool approx_equal(double a, double b) { |
1114 |
return abs(a |
|
1124 |
return abs(a - b) <= numeric_limits<double>::epsilon() ? true : false; |
|
1115 |
1125 |
} |
1116 |
1126 |
|
1117 |
1127 |
/// Fast sum of log of dnorms |
1118 |
1128 |
template <typename T, matrix_order PO, matrix_style PS> |
1119 |
double sum_fast_log_dnorm(const Matrix<T,PO,PS> &A, const double mean, const double sd) |
|
1120 |
{ |
|
1129 |
double sum_fast_log_dnorm(const Matrix<T, PO, PS> &A, const double mean, const double sd) { |
|
1121 |
1130 |
double result = 0; |
1122 |
1131 |
|
1123 |
for |
|
1132 |
for (int i = 0; i < A.size(); ++i) { |
|
1124 |
1133 |
// Slower part here is A[i], can this be speed up using an iterator? |
1125 |
1134 |
result += fast_log_dnorm(A[i], mean, sd); |
1126 |
1135 |
} |
| … | … | @@ -1129,7 +1138,7 @@ double sum_fast_log_dnorm(const Matrix<T |
1129 |
1138 |
|
1130 |
1139 |
/// Fast log of dnorm for mean parameter |
1131 |
1140 |
double fast_log_dnorm(const double x, const double mean, const double sd) { |
1132 |
return -pow((x - mean), |
|
1141 |
return -pow((x - mean), 2) / (2*pow(sd, 2)); |
|
1133 |
1142 |
} |
1134 |
1143 |
|
1135 |
1144 |
