27 return (a < 1.0) ? std::log1p(-a) : -std::numeric_limits<double>::infinity();
74template <
typename ProposalType>
87 std::uniform_real_distribution<double>
distU_{0.0, 1.0};
88 std::default_random_engine
rng_;
102 std::default_random_engine &rng,
103 const double &targetAcceptanceRatio = 0.234)
106 score_(-std::numeric_limits<double>::infinity()),
107 dim_(proposal.get().size()),
130 bool accept(
const Eigen::Ref<const Eigen::VectorXd> &par,
double score) {
150 double score_prev =
getScore(cand_prev);
153 double log_alpha_1_fwd = std::min(0.0, score_prev -
score_);
154 double alpha_1_fwd = std::exp(log_alpha_1_fwd);
156 bool accepted =
accept(cand_prev, score_prev);
159 double rm_gamma = 1.0 / std::sqrt(
static_cast<double>(
nSteps_));
165 if(!accepted && delayedRejection) {
169 double score_new =
getScore(cand_new);
172 double log_alpha_1_bwd = std::min(0.0, score_prev - score_new);
173 double alpha_1_bwd = std::exp(log_alpha_1_bwd);
175 double log_rej_fwd =
log1m(alpha_1_fwd);
176 double log_rej_bwd =
log1m(alpha_1_bwd);
179 Eigen::VectorXd jump_fwd = cand_prev -
getCurrent();
180 Eigen::VectorXd jump_bwd = cand_prev - cand_new;
182 double log_q1_fwd = -0.5 *
proposal_.squaredMahalanobis(jump_fwd);
183 double log_q1_bwd = -0.5 *
proposal_.squaredMahalanobis(jump_bwd);
186 double log_ratio_stage2 = (score_new -
score_) +
187 (log_q1_bwd - log_q1_fwd) +
188 (log_rej_bwd - log_rej_fwd);
190 double alpha_2 = std::exp(std::min(0.0, log_ratio_stage2));
193 if(std::log(
distU_(
rng_)) < std::log(alpha_2)) {
214 Eigen::VectorXd delta_old = par -
mean_;
216 Eigen::VectorXd delta_new = par -
mean_;
218 cov_ += delta_old * delta_new.transpose();
226 double epsilon = 1e-6;
227 Eigen::MatrixXd identity = Eigen::MatrixXd::Identity(
dim_,
dim_);
296 return Eigen::MatrixXd::Zero(
dim_,
dim_);
298 return cov_ / (
static_cast<double>(
nSteps_) - 1.0);
305 std::cout <<
"run " <<
nSteps_ <<
" steps\n"
306 <<
"acceptance ratio: " << std::fixed << std::setprecision(3) <<
getAcceptanceRatio() <<
"\n"
308 <<
"Data mean: \n" <<
getMean() << std::endl;
337template <
typename ProposalType>
339 if(chains.empty())
return 0.0;
341 size_t dim_chain = chains[0].getDim();
342 size_t num_chains = chains.size();
344 Eigen::VectorXd chainwise_mean = Eigen::VectorXd::Zero(dim_chain);
345 Eigen::VectorXd chainwise_cov = Eigen::VectorXd::Zero(dim_chain);
346 Eigen::VectorXd chainwise_mean_cov = Eigen::VectorXd::Zero(dim_chain);
348 for(
const auto &chain : chains) {
349 Eigen::VectorXd current_mean = chain.getMean();
350 Eigen::MatrixXd current_cov = chain.getCovariance();
352 chainwise_mean += current_mean;
353 chainwise_cov += current_cov.diagonal();
354 chainwise_mean_cov += current_mean.cwiseProduct(current_mean);
357 chainwise_mean /=
static_cast<double>(num_chains);
358 chainwise_cov /=
static_cast<double>(num_chains);
360 chainwise_mean_cov = chainwise_mean_cov /
static_cast<double>(num_chains) - chainwise_mean.cwiseProduct(chainwise_mean);
363 chainwise_mean_cov *=
static_cast<double>(num_chains) /
static_cast<double>(num_chains - 1);
366 Eigen::VectorXd var_chain = chainwise_cov + chainwise_mean_cov;
369 Eigen::VectorXd r_hat = Eigen::VectorXd::Zero(dim_chain);
370 for(
size_t i = 0; i < dim_chain; ++i) {
371 if(chainwise_cov(i) > 0.0) {
372 r_hat(i) = std::sqrt(var_chain(i) / chainwise_cov(i));
378 return r_hat.maxCoeff();
412 std::uniform_real_distribution<double>
distU_{0, 1};
413 std::normal_distribution<double>
distN_{0, 1};
427 EvolutionaryMarkovChain(std::vector<Eigen::VectorXd> initialSamples, std::vector<double> initialScores,
double nugget = 1e-6);
435 void step(
const score_t &getScore, std::default_random_engine &rng,
double gamma = 0.2);
Implements an Evolutionary Markov Chain Monte Carlo sampler.
Definition mcmc.h:401
std::uniform_real_distribution< double > distU_
Uniform distribution helper.
Definition mcmc.h:412
size_t dim_
Dimension of the parameter space.
Definition mcmc.h:404
EvolutionaryMarkovChain()=default
std::vector< double > getScores() const
Gets the current log probability scores of all chains.
Definition mcmc.h:449
std::uniform_int_distribution< size_t > distChain_
Discrete uniform distribution helper to pick random chain.
Definition mcmc.h:409
std::vector< Eigen::VectorXd > getCurrent() const
Gets the current states of all chains.
Definition mcmc.h:441
size_t nChains_
Number of active parallel chains.
Definition mcmc.h:403
double nugget_
Crossover mutation noise scaling.
Definition mcmc.h:415
std::vector< Eigen::VectorXd > chainSamples_
Current parameter samples for each chain.
Definition mcmc.h:405
std::normal_distribution< double > distN_
Normal distribution helper.
Definition mcmc.h:413
void step(const score_t &getScore, std::default_random_engine &rng, double gamma=0.2)
Performs one crossover and mutation step for all chains.
Definition mcmc.cpp:30
std::vector< double > chainScores_
Current score (log probability) for each chain.
Definition mcmc.h:406
Represents a single Markov Chain utilizing Delayed Rejection Adaptive Metropolis (DRAM) for sampling.
Definition mcmc.h:75
std::default_random_engine rng_
Random engine.
Definition mcmc.h:88
Eigen::MatrixXd cov_
Parameter sample running covariance matrix.
Definition mcmc.h:83
size_t nSteps_
Number of steps taken.
Definition mcmc.h:79
ProposalType proposal_
Proposal distribution model (copied by value).
Definition mcmc.h:85
size_t getSteps() const
Gets the total number of steps run in this chain.
Definition mcmc.h:270
MarkovChain(const ProposalType &proposal, std::default_random_engine &rng, const double &targetAcceptanceRatio=0.234)
Construct a new mcmc chain object.
Definition mcmc.h:101
void increaseSteps()
Increase the number of steps.
Definition mcmc.h:120
double getScore() const
Gets the current log probability score of the chain.
Definition mcmc.h:254
Eigen::VectorXd getMean() const
Gets the running mean of the parameter samples.
Definition mcmc.h:286
void step(const score_t &getScore, const bool &delayedRejection=false, const double &gamma=0.1)
Perform a single MCMC step.
Definition mcmc.h:143
double targetAcceptanceRatio_
Target acceptance ratio for adaptive tuning.
Definition mcmc.h:91
size_t getDim() const
Gets the dimensionality of the parameter space.
Definition mcmc.h:262
double getAcceptanceRatio() const
Gets the current acceptance ratio of proposals.
Definition mcmc.h:278
Eigen::MatrixXd getCovariance() const
Gets the running covariance of the parameter samples.
Definition mcmc.h:294
void update()
Updates the value of the mean and covariance matrix.
Definition mcmc.h:206
size_t nAccepts_
Number of accepted proposals.
Definition mcmc.h:80
double score_
Current log probability score value.
Definition mcmc.h:77
size_t dim_
Dimension of parameter space.
Definition mcmc.h:78
Eigen::VectorXd mean_
Parameter sample running mean vector.
Definition mcmc.h:82
double scale_
Proposal covariance scale parameter.
Definition mcmc.h:90
bool accept(const Eigen::Ref< const Eigen::VectorXd > &par, double score)
Accept or reject a candidate.
Definition mcmc.h:130
void reset()
Definition mcmc.h:234
void info() const
Definition mcmc.h:304
Eigen::VectorXd getCurrent() const
Gets the current parameters of the chain.
Definition mcmc.h:246
std::uniform_real_distribution< double > distU_
Uniform distribution helper.
Definition mcmc.h:87
Eigen::MatrixXd getAdaptedCovariance() const
Get a covariance matrix adapted to the samples.
Definition mcmc.h:225
Definition cmp_defines.h:19
double log1m(double a)
Definition mcmc.h:26
double multiChainDiagnosis(const std::vector< MarkovChain< ProposalType > > &chains)
Computes the Gelman-Rubin convergence diagnostic metric (R-hat).
Definition mcmc.h:338
std::function< double(const Eigen::VectorXd &)> score_t
The score_t type A function that takes a const reference to an Eigen::VectorXd and returns a double A...
Definition cmp_defines.h:82