Hamiltonian Monte Carlo

montecarlo.cpp
Go to the documentation of this file.
1 //
2 // Created by Lars Gebraad on 7/11/17.
3 //
4 
5 #include <ctime>
6 #include <utility>
7 #include <vector>
8 #include <cmath>
9 #include "auxiliary.hpp"
10 #include "montecarlo.hpp"
11 #include <cstdlib>
12 #include "randomnumbers.hpp"
13 #include "linearalgebra.hpp"
14 #include <cstdio>
15 #include <iostream>
16 
17 montecarlo::montecarlo(prior &in_prior, data &in_data, forwardModel in_model, int in_nt, double in_dt, int in_iterations,
18  bool useGeneralisedMomentumPropose, bool useGeneralisedMomentumKinetic, bool normalizeMomentum, bool
19  evaluateHamiltonianBeforeLeap) {
20  _prior = in_prior;
21  _data = in_data;
22  _model = std::move(in_model);
23  _nt = in_nt;
24  _dt = in_dt;
25  _iterations = in_iterations;
26  _useGeneralisedMomentumKinetic = useGeneralisedMomentumKinetic;
27  _useGeneralisedMomentumPropose = useGeneralisedMomentumPropose;
28  _normalizeMomentum = normalizeMomentum;
29  _evaluateHamiltonianBeforeLeap = evaluateHamiltonianBeforeLeap;
30 
31  /* Initialise random number generator. ----------------------------------------*/
32  srand((unsigned int) time(nullptr));
33 
34  // Pre-compute mass matrix and other associated quantities
38 
39  // This is where the magic happens
41  std::vector<std::vector<double>> InverseCholeskyLowerMassMatrix = InvertLowerTriangular(_CholeskyLowerMassMatrix);
42  _inverseMassMatrix = TransposeMatrix(InverseCholeskyLowerMassMatrix) * InverseCholeskyLowerMassMatrix;
43 
51 
52  _A = _massMatrix;
57 };
58 
59 //montecarlo::montecarlo(prior &in_prior, data &in_data, posterior &in_posterior, forwardModel &in_model, int in_nt,
60 // double in_dt, int in_iterations, bool useGeneralisedMomentumPropose,
61 // bool useGeneralisedMomentumKinetic, bool normalizeMomentum) :
62 // montecarlo::montecarlo(in_prior, in_data, std::move(in_model), in_nt, in_dt, in_iterations,
63 // useGeneralisedMomentumPropose, useGeneralisedMomentumKinetic, normalizeMomentum) {
64 // _posterior = in_posterior;
65 //}
66 
67 montecarlo::~montecarlo() = default;
68 
70  for (int i = 0; i < _prior._numberParameters; i++)
72 }
73 
74 void montecarlo::propose_hamilton(int &uturns) {
75  /* Draw random prior momenta. */
76  double normalizationFactor = sqrt(_proposedMomentum * _proposedMomentum);
77  _proposedMomentum = _useGeneralisedMomentumPropose ?
80  _proposedMomentum = _normalizeMomentum ? normalizationFactor * NormalizeVector(_proposedMomentum) : _proposedMomentum;
81 }
82 
84  return 0.5 * _proposedModel * (_A * _proposedModel) - _bT * _proposedModel + _c;
85 }
86 
91 }
92 
93 std::vector<double> montecarlo::precomp_misfitGrad() {
94  // Should actually be left multiply, but matrix is symmetric, so skipped that bit.
95  return _A * _proposedModel - _bT;
96 }
97 
98 double montecarlo::chi() {
99 // return _posterior.misfit(_proposedModel, _prior, _data, _model);
100  return precomp_misfit();
101 }
102 
104  double H = chi();
105  H += kineticEnergy();
106  return H;
107 }
108 
109 void montecarlo::sample(bool hamilton) {
110  double x = hamilton ? energy() : chi();
111  double x_new;
112  int accepted = 1;
113  int uturns = 0;
114 
115  std::ofstream samplesfile;
116  samplesfile.open("OUTPUT/samples.txt");
117  samplesfile << _prior._numberParameters << " " << _iterations << std::endl;
118 
119  write_sample(samplesfile, x);
120  for (int it = 1; it < _iterations; it++) {
121 
122  if (hamilton) {
123  propose_hamilton(uturns);
125  leap_frog(uturns, it == _iterations - 1);
126  }
127  } else {
129  }
130 
131  x_new = (hamilton ? energy() : chi());
132 
133  double result;
134  result = x - x_new;
135  double result_exponent;
136  result_exponent = exp(result);
137 
138 // if (true) {
139  if ((x_new < x) || (result_exponent > randf(0.0, 1.0))) {
140 // double Hamiltonian = energy();
141 // std::cout<< Hamiltonian;
143  leap_frog(uturns, it == _iterations - 1);
144  }
145 // Hamiltonian = energy();
146 // std::cout<< Hamiltonian;
147  accepted++;
148  x = x_new;
150  write_sample(samplesfile, x);
151  }
152  }
153  samplesfile << accepted << std::endl;
154  samplesfile.close();
155 
156  std::cout << "Number of accepted models: " << accepted << std::endl;
157  std::cout << "Number of U-Turn terminations in propagation: " << uturns;
158 }
159 
160 /* Leap-frog integration of Hamilton's equations. ---------------------------------*/
161 void montecarlo::leap_frog(int &uturns, bool writeTrajectory) {
162 
163  // start proposal at current momentum
165  // Acts as starting momentum
167 
168  std::vector<double> misfitGrad;
169  double angle1, angle2;
170 
171  std::ofstream trajectoryfile;
172  if (writeTrajectory) {
173  trajectoryfile.open("OUTPUT/trajectory.txt");
174  trajectoryfile << _prior._numberParameters << " " << _nt << std::endl;
175  }
176 
177  for (int it = 0; it < _nt; it++) {
178  misfitGrad = precomp_misfitGrad();
179  _proposedMomentum = _proposedMomentum - 0.5 * _dt * misfitGrad;
180  misfitGrad.clear();
181 
182  if (writeTrajectory) write_sample(trajectoryfile, chi());
183  // Full step in position. Linear algebra does not allow for dividing by diagonal of matrix, hence the loop.
186  // Second branch produces unnecessary overhead (lot of zeros).
187 
188  misfitGrad = precomp_misfitGrad();
189  _proposedMomentum = _proposedMomentum - 0.5 * _dt * misfitGrad;
190  misfitGrad.clear();
191 
192  /* Check no-U-turn criterion. */
195 
196  if (angle1 > 0.0 && angle2 > 0.0) {
197  uturns++;
198  break;
199  }
200  }
201  if (writeTrajectory) trajectoryfile.close();
202 }
203 
204 void montecarlo::write_sample(std::ofstream &outfile, double misfit) {
205  for (double j : _proposedModel) {
206  outfile << j << " ";
207  }
208  outfile << misfit;
209  outfile << std::endl;
210 
211 }
212 
213 std::vector<double> montecarlo::precomp_misfitGrad(std::vector<double> parameters) {
214  // Should actually be left multiply, but matrix is symmetric, so skipped that bit.
215  return _A * std::move(parameters) - _bT;
216 }
std::vector< std::vector< double > > InvertLowerTriangular(std::vector< std::vector< double >> L)
Invert a lower triangular matrix by use of solving the system per column of using SolveLowerTriang...
std::vector< double > _mean
Definition: auxiliary.hpp:24
int _iterations
Definition: montecarlo.hpp:72
std::vector< std::vector< double > > _inverseCovarianceMatrix
Definition: auxiliary.hpp:26
std::vector< std::vector< double > > _inverseMassMatrix
Definition: montecarlo.hpp:85
std::vector< double > MatrixTrace(std::vector< std::vector< double >> M)
Function to the trace of a square matrix .
double _dt
Definition: montecarlo.hpp:71
double chi()
Definition: montecarlo.cpp:98
double precomp_misfit()
Definition: montecarlo.cpp:83
std::vector< std::vector< double > > VectorToDiagonal(std::vector< double > A)
Function which takes a std::vector of double to make a diagonal matrix of it, such that ...
montecarlo(prior &in_prior, data &in_data, forwardModel in_model, int in_nt, double in_dt, int in_iterations, bool useGeneralisedMomentumPropose, bool useGeneralisedMomentumKinetic, bool normalizeMomentum, bool evaluateHamiltonianBeforeLeap)
Definition: montecarlo.cpp:17
std::vector< double > _std
Definition: auxiliary.hpp:25
std::vector< double > precomp_misfitGrad()
Definition: montecarlo.cpp:93
bool _normalizeMomentum
Definition: montecarlo.hpp:75
forwardModel _model
Definition: montecarlo.hpp:68
prior _prior
Definition: montecarlo.hpp:66
std::vector< std::vector< double > > _inverseMassMatrixDiagonal
Definition: montecarlo.hpp:86
std::vector< std::vector< double > > _inverseCD
Definition: auxiliary.hpp:61
double randf(double min, double max)
Draw uniformly distributed samples between two numbers.
bool _useGeneralisedMomentumPropose
Definition: montecarlo.hpp:74
void write_sample(std::ofstream &outfile, double misfit)
Definition: montecarlo.cpp:204
Set of functions to draw from (multivariate, correlated) normal distributions.
std::vector< std::vector< double > > TransposeMatrix(std::vector< std::vector< double > > M)
std::vector< double > _currentMomentum
Definition: montecarlo.hpp:80
double kineticEnergy()
Definition: montecarlo.cpp:87
void sample(bool hamilton)
Definition: montecarlo.cpp:109
std::vector< std::vector< double > > InvertMatrixElements(std::vector< std::vector< double >> M)
Function to take the inverse of the individual matrix elements.
double energy()
Definition: montecarlo.cpp:103
std::vector< std::vector< double > > _CholeskyLowerMassMatrix
Definition: montecarlo.hpp:84
bool _evaluateHamiltonianBeforeLeap
Definition: montecarlo.hpp:76
std::vector< double > randn_Cholesky(std::vector< double > mean, std::vector< std::vector< double >> CholeskyLower_CovarianceMatrix)
Drawing non-zero mean samples from an dimensional correlated Gaussian. Invokes randn_Cholesky(std::v...
double randn(double mean, double stdv)
Draws from Gaussian (mean, standard deviation) using Box-Müller transform.
std::vector< double > _bT
Definition: montecarlo.hpp:90
std::vector< double > _currentModel
Definition: montecarlo.hpp:78
std::vector< double > _proposedMomentum
Definition: montecarlo.hpp:81
std::vector< double > NormalizeVector(std::vector< double > A)
Normalizes a vector to unit length.
std::vector< std::vector< double > > _massMatrix
Definition: montecarlo.hpp:83
std::vector< double > _proposedModel
Definition: montecarlo.hpp:79
Linear algebra functions operating on standard library containers.
void propose_metropolis()
Definition: montecarlo.cpp:69
double _c
Definition: montecarlo.hpp:91
bool _useGeneralisedMomentumKinetic
Definition: montecarlo.hpp:73
void leap_frog(int &uturns, bool writeTrajectory)
Definition: montecarlo.cpp:161
std::vector< double > _observedData
Definition: auxiliary.hpp:60
std::vector< std::vector< double > > _A
Definition: montecarlo.hpp:89
Prior information in parameter space.
Definition: auxiliary.hpp:20
unsigned long _numberParameters
Definition: auxiliary.hpp:23
std::vector< std::vector< double > > _designMatrix
Definition: auxiliary.hpp:98
std::vector< std::vector< double > > CholeskyDecompose(std::vector< std::vector< double >> A)
Cholesky-decomposition of a positive definite Hermitian matrix .
void propose_hamilton(int &uturns)
Definition: montecarlo.cpp:74