CMP++: Uncertainty Quantification & Bayesian Calibration
Loading...
Searching...
No Matches
cmp::mcmc::HamiltonianMarkovChain Class Reference

Implements the Hamiltonian Monte Carlo (HMC) algorithm with the No-U-Turn Sampler (NUTS) and Dual Averaging. More...

#include <hmc.h>

Classes

struct  TreeState
 

Public Member Functions

 HamiltonianMarkovChain (Eigen::VectorXd initialState, std::default_random_engine &rng, double epsilon)
 
void step (const score_t &getScore, const gradient_t &getGradient, bool adapt=false)
 Perform a single MCMC step using the NUTS algorithm.
 
void reset ()
 
Eigen::VectorXd getCurrent () const
 
size_t getSteps () const
 
double getAcceptanceRatio () const
 
double getStepSize () const
 
Eigen::VectorXd getMean () const
 
Eigen::MatrixXd getCovariance () const
 
void info () const
 

Private Member Functions

void leapfrog (Eigen::VectorXd &q, Eigen::VectorXd &p, Eigen::VectorXd &grad, double epsilon, const gradient_t &getGradient) const
 Perform a single leapfrog step.
 
TreeState build_tree (const Eigen::VectorXd &q, const Eigen::VectorXd &p, const Eigen::VectorXd &grad, double log_u, int v, int j, double epsilon, const score_t &getScore, const gradient_t &getGradient)
 Build a binary tree for the NUTS algorithm.
 
void update ()
 

Private Attributes

std::default_random_engine & rng_
 Reference to the random number generator.
 
Eigen::VectorXd currentPosition_
 The current position (parameter state).
 
Eigen::VectorXd currentMomentum_
 The current momentum auxiliary variable.
 
double currentScore_
 The current log-posterior score value.
 
size_t dim_
 Dimension of the parameter space.
 
Eigen::VectorXd mean_
 Running mean of the parameter samples.
 
Eigen::MatrixXd cov_
 Running covariance of the parameter samples.
 
double epsilon_
 Step size for the leapfrog integrator.
 
size_t nSteps_ = 0
 Number of steps taken in the Markov chain.
 
double sumAcceptanceProb_ = 0.0
 Sum of acceptance probabilities for step size adaptation.
 
double mu_
 Target value for log step size.
 
double gamma_ = 0.05
 Adaptation shrinkage parameter.
 
double t0_ = 10.0
 Adaptation stabilization parameter.
 
double kappa_ = 0.75
 Adaptation exponential decay parameter.
 
double H_bar_ = 0.0
 Running average of difference between target and accept probability.
 
double log_epsilon_bar_ = 0.0
 Log of the adapted step size.
 
double target_accept_ = 0.80
 Target acceptance probability.
 
std::normal_distribution< double > distN_ {0.0, 1.0}
 Normal generator helper for momentum initialization.
 
std::uniform_real_distribution< double > distU_ {0.0, 1.0}
 Uniform generator helper for transition accept checks.
 

Detailed Description

Implements the Hamiltonian Monte Carlo (HMC) algorithm with the No-U-Turn Sampler (NUTS) and Dual Averaging.

Mathematical Foundations

Hamiltonian Monte Carlo (HMC) maps the target probability density \(p(\mathbf{q})\) to the potential energy of a physical system: \(U(\mathbf{q}) = -\log p(\mathbf{q})\). We introduce auxiliary momentum variables \(\mathbf{p} \sim \mathcal{N}(\mathbf{0}, \mathbf{M})\) with kinetic energy \(K(\mathbf{p}) = \frac{1}{2} \mathbf{p}^T \mathbf{M}^{-1} \mathbf{p}\).

The total energy is given by the Hamiltonian:

\[ H(\mathbf{q}, \mathbf{p}) = U(\mathbf{q}) + K(\mathbf{p}) \]

The joint system evolves according to Hamilton's equations:

\[ \frac{d\mathbf{q}}{dt} = \frac{\partial H}{\partial \mathbf{p}} = \mathbf{M}^{-1} \mathbf{p}, \quad \frac{d\mathbf{p}}{dt} = -\frac{\partial H}{\partial \mathbf{q}} = -\nabla U(\mathbf{q}) \]

Implementation Algorithms

  1. Leapfrog Integrator: To integrate the system numerically with step size \(\epsilon\), we use the symplectic Leapfrog scheme:

    \[ \mathbf{p}\left(t + \frac{\epsilon}{2}\right) = \mathbf{p}(t) - \frac{\epsilon}{2} \nabla U(\mathbf{q}(t)) \]

    \[ \mathbf{q}(t + \epsilon) = \mathbf{q}(t) + \epsilon \mathbf{M}^{-1} \mathbf{p}\left(t + \frac{\epsilon}{2}\right) \]

    \[ \mathbf{p}(t + \epsilon) = \mathbf{p}\left(t + \frac{\epsilon}{2}\right) - \frac{\epsilon}{2} \nabla U(\mathbf{q}(t + \epsilon)) \]

  2. No-U-Turn Sampler (NUTS): Avoids manual tuning of the number of integration steps \(L\). It recursively builds a binary tree of leapfrog steps forward and backward in time. The tree stops growing when the trajectory starts to turn back on itself:

    \[ (\mathbf{q}_{\text{plus}} - \mathbf{q}_{\text{minus}})^T \mathbf{p}_{\text{minus}} < 0 \quad \text{or} \quad (\mathbf{q}_{\text{plus}} - \mathbf{q}_{\text{minus}})^T \mathbf{p}_{\text{plus}} < 0 \]

  3. Dual Averaging Step Size Adaptation: Uses Nesterov's dual averaging scheme to adaptively tune the step size \(\epsilon\) to match a target acceptance probability \(\delta\) (default 0.8):

    \[ H_t = \delta - \alpha_t, \quad \bar{H}_t = \left(1 - \frac{1}{t + t_0}\right) \bar{H}_{t-1} + \frac{1}{t + t_0} H_t \]

    \[ \log \epsilon_t = \mu - \frac{\sqrt{t}}{\gamma} \bar{H}_t, \quad \log \bar{\epsilon}_t = t^{-\kappa} \log \epsilon_t + (1 - t^{-\kappa}) \log \bar{\epsilon}_{t-1} \]

Constraints & Invariants

  • Symplectic Flow: The Leapfrog scheme must preserve volume in phase space and hold total energy approximately constant.
  • U-turn Condition: Tree growth is terminated immediately if a U-turn is detected to ensure detailed balance is maintained.

Constructor & Destructor Documentation

◆ HamiltonianMarkovChain()

cmp::mcmc::HamiltonianMarkovChain::HamiltonianMarkovChain ( Eigen::VectorXd  initialState,
std::default_random_engine &  rng,
double  epsilon 
)

Member Function Documentation

◆ build_tree()

cmp::mcmc::HamiltonianMarkovChain::TreeState cmp::mcmc::HamiltonianMarkovChain::build_tree ( const Eigen::VectorXd &  q,
const Eigen::VectorXd &  p,
const Eigen::VectorXd &  grad,
double  log_u,
int  v,
int  j,
double  epsilon,
const score_t getScore,
const gradient_t getGradient 
)
private

Build a binary tree for the NUTS algorithm.

Parameters
qThe current position (parameters)
pThe current momentum (auxiliary variable)
gradThe gradient of the score function at the current position
log_uThe log of the slice variable
vThe direction of tree expansion (-1 for backward, +1 for forward)
jThe depth of the tree
epsilonThe step size for the leapfrog integrator
getScoreThe score function (log-posterior)
getGradientThe gradient function of the score function
Returns
The state of the tree after expansion
Note
This function is called recursively to build the tree. It returns the state of the tree after expansion, which includes the new position, momentum, gradient, and acceptance probabilities. The function also checks for U-turns and updates the stop flag accordingly. The acceptance probabilities are accumulated to compute the overall acceptance ratio for the NUTS algorithm. The gradient is passed by reference and will be updated to the new gradient after the leapfrog step. This is important for efficiency, as it avoids redundant gradient calculations during the tree expansion. The log of the slice variable is used to determine whether the proposed states are within the slice defined by the current Hamiltonian level. This is crucial for the correctness of the NUTS algorithm, as it ensures that the samples are drawn from the correct distribution. The direction of tree expansion (v) determines whether the tree is built forward (v=+1) or backward (v=-1) in time. This allows the NUTS algorithm to explore the parameter space more effectively and adaptively determine the number of leapfrog

◆ getAcceptanceRatio()

double cmp::mcmc::HamiltonianMarkovChain::getAcceptanceRatio ( ) const

◆ getCovariance()

Eigen::MatrixXd cmp::mcmc::HamiltonianMarkovChain::getCovariance ( ) const
inline

◆ getCurrent()

Eigen::VectorXd cmp::mcmc::HamiltonianMarkovChain::getCurrent ( ) const

◆ getMean()

Eigen::VectorXd cmp::mcmc::HamiltonianMarkovChain::getMean ( ) const
inline

◆ getSteps()

size_t cmp::mcmc::HamiltonianMarkovChain::getSteps ( ) const

◆ getStepSize()

double cmp::mcmc::HamiltonianMarkovChain::getStepSize ( ) const
inline

◆ info()

void cmp::mcmc::HamiltonianMarkovChain::info ( ) const

Print the current state of the Markov chain, including the current position, step size, number of steps, and acceptance ratio.

◆ leapfrog()

void cmp::mcmc::HamiltonianMarkovChain::leapfrog ( Eigen::VectorXd &  q,
Eigen::VectorXd &  p,
Eigen::VectorXd &  grad,
double  epsilon,
const gradient_t getGradient 
) const
private

Perform a single leapfrog step.

Parameters
qThe current position (parameters)
pThe current momentum (auxiliary variable)
gradThe gradient of the score function at the current position
epsilonThe step size for the leapfrog integrator
getGradientThe gradient function of the score function
Note
The gradient is passed by reference and will be updated to the new gradient after the leapfrog step.

◆ reset()

void cmp::mcmc::HamiltonianMarkovChain::reset ( )

◆ step()

void cmp::mcmc::HamiltonianMarkovChain::step ( const score_t getScore,
const gradient_t getGradient,
bool  adapt = false 
)

Perform a single MCMC step using the NUTS algorithm.

Parameters
getScoreThe score function (log-posterior)
getGradientThe gradient function of the score function
adaptWhether to adapt the step size using dual averaging (default is false)
Note
If adapt is true, the step size will be adapted using dual averaging to achieve the target acceptance ratio. If adapt is false, the step size will remain fixed.

◆ update()

void cmp::mcmc::HamiltonianMarkovChain::update ( )
private

Updates the mean and covariance of the samples based on the current position.

Member Data Documentation

◆ cov_

Eigen::MatrixXd cmp::mcmc::HamiltonianMarkovChain::cov_
private

Running covariance of the parameter samples.

◆ currentMomentum_

Eigen::VectorXd cmp::mcmc::HamiltonianMarkovChain::currentMomentum_
private

The current momentum auxiliary variable.

◆ currentPosition_

Eigen::VectorXd cmp::mcmc::HamiltonianMarkovChain::currentPosition_
private

The current position (parameter state).

◆ currentScore_

double cmp::mcmc::HamiltonianMarkovChain::currentScore_
private

The current log-posterior score value.

◆ dim_

size_t cmp::mcmc::HamiltonianMarkovChain::dim_
private

Dimension of the parameter space.

◆ distN_

std::normal_distribution<double> cmp::mcmc::HamiltonianMarkovChain::distN_ {0.0, 1.0}
private

Normal generator helper for momentum initialization.

◆ distU_

std::uniform_real_distribution<double> cmp::mcmc::HamiltonianMarkovChain::distU_ {0.0, 1.0}
private

Uniform generator helper for transition accept checks.

◆ epsilon_

double cmp::mcmc::HamiltonianMarkovChain::epsilon_
private

Step size for the leapfrog integrator.

◆ gamma_

double cmp::mcmc::HamiltonianMarkovChain::gamma_ = 0.05
private

Adaptation shrinkage parameter.

◆ H_bar_

double cmp::mcmc::HamiltonianMarkovChain::H_bar_ = 0.0
private

Running average of difference between target and accept probability.

◆ kappa_

double cmp::mcmc::HamiltonianMarkovChain::kappa_ = 0.75
private

Adaptation exponential decay parameter.

◆ log_epsilon_bar_

double cmp::mcmc::HamiltonianMarkovChain::log_epsilon_bar_ = 0.0
private

Log of the adapted step size.

◆ mean_

Eigen::VectorXd cmp::mcmc::HamiltonianMarkovChain::mean_
private

Running mean of the parameter samples.

◆ mu_

double cmp::mcmc::HamiltonianMarkovChain::mu_
private

Target value for log step size.

◆ nSteps_

size_t cmp::mcmc::HamiltonianMarkovChain::nSteps_ = 0
private

Number of steps taken in the Markov chain.

◆ rng_

std::default_random_engine& cmp::mcmc::HamiltonianMarkovChain::rng_
private

Reference to the random number generator.

◆ sumAcceptanceProb_

double cmp::mcmc::HamiltonianMarkovChain::sumAcceptanceProb_ = 0.0
private

Sum of acceptance probabilities for step size adaptation.

◆ t0_

double cmp::mcmc::HamiltonianMarkovChain::t0_ = 10.0
private

Adaptation stabilization parameter.

◆ target_accept_

double cmp::mcmc::HamiltonianMarkovChain::target_accept_ = 0.80
private

Target acceptance probability.


The documentation for this class was generated from the following files: