hops
AdaptiveMetropolisProposal.hpp
Go to the documentation of this file.
1 #ifndef HOPS_ADAPTIVEMETROPOLISPROPOSAL_HPP
2 #define HOPS_ADAPTIVEMETROPOLISPROPOSAL_HPP
3 
4 #include "../IsSetStepSizeAvailable.hpp"
5 #include "../../RandomNumberGenerator/RandomNumberGenerator.hpp"
6 #include "../../FileWriter/CsvWriter.hpp"
7 #include "../../Polytope/MaximumVolumeEllipsoid.hpp"
8 #include <random>
9 
10 namespace hops {
11  template<typename MatrixType, typename VectorType>
13  public:
15 
28  VectorType b,
29  StateType currentState,
30  typename MatrixType::Scalar stepSize = 1,
31  typename MatrixType::Scalar eps = 1.e-3,
32  unsigned long warmUp = 100);
33 
34  void propose(RandomNumberGenerator &randomNumberGenerator);
35 
36  void acceptProposal();
37 
38  StateType getState() const;
39 
40  StateType getProposal() const;
41 
42  void setState(StateType newState);
43 
44  void setStepSize(typename MatrixType::Scalar stepSize);
45 
46  typename MatrixType::Scalar getStepSize() const;
47 
48  [[nodiscard]] typename MatrixType::Scalar computeLogAcceptanceProbability();
49 
51 
52  private:
53  MatrixType A;
54  VectorType b;
55  StateType state;
56  StateType m_proposal;
57 
58  StateType stateMean;
59 
60  MatrixType stateCovariance;
61  MatrixType proposalCovariance;
62  MatrixType maximumVolumeEllipsoid;
63 
64  MatrixType stateCholeskyOfCovariance;
65  MatrixType proposalCholeskyOfCovariance;
66  MatrixType choleskyOfMaximumVolumeEllipsoid;
67 
68  typename MatrixType::Scalar stateLogSqrtDeterminant;
69  typename MatrixType::Scalar proposalLogSqrtDeterminant;
70 
71  unsigned long t;
72  unsigned long warmUp;
73 
74  typename MatrixType::Scalar eps;
75  typename MatrixType::Scalar stepSize;
76  constexpr static typename MatrixType::Scalar boundaryCushion = 1e-10;
77 
78  std::normal_distribution<typename MatrixType::Scalar> normal;
79 
80  MatrixType updateCovariance(const MatrixType& covariance, const StateType& mean, const StateType& newState) {
81  assert(t > 0 && "cannot update covariance without samples having been drawn");
82 
83  // recursive mean
84  StateType newMean = (t * mean + newState) / (t + 1);
85  MatrixType newCovariance = ((t - 1) * covariance
86  + t * (mean * mean.transpose())
87  - (t + 1) * (newMean * newMean.transpose())
88  + newState * newState.transpose()
89  + eps * maximumVolumeEllipsoid) / t;
90  return newCovariance;
91  }
92  };
93 
94  template<typename MatrixType, typename VectorType>
96  VectorType b_,
97  VectorType currentState_,
98  typename MatrixType::Scalar stepSize_,
99  typename MatrixType::Scalar eps_,
100  unsigned long warmUp_) :
101  A(std::move(A_)),
102  b(std::move(b_)),
103  state(std::move(currentState_)),
104  m_proposal(this->state),
105  t(0),
106  warmUp(warmUp_),
107  stepSize(stepSize_) {
108  normal = std::normal_distribution<typename MatrixType::Scalar>(0, stepSize);
109 
110  // scale down with larger dimensions according to Roberts & Rosenthal, 2001.
111  eps = eps_ / A.cols();
112 
113  stateMean = state; // actual content is irrelevant as long as dimensions match
114 
115  maximumVolumeEllipsoid = MaximumVolumeEllipsoid<double>::construct(A, b, 10000).getEllipsoid();
116  Eigen::LLT<Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>> solverMaximumVolumeEllipsoid(maximumVolumeEllipsoid);
117  choleskyOfMaximumVolumeEllipsoid = solverMaximumVolumeEllipsoid.matrixL();
118 
119  stateCovariance = maximumVolumeEllipsoid;
120  Eigen::LLT<Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>> solverStateCovariance(stateCovariance);
121  stateCholeskyOfCovariance = solverStateCovariance.matrixL();
122 
123  stateLogSqrtDeterminant = stateCholeskyOfCovariance.diagonal().array().log().sum();
124  }
125 
126  template<typename MatrixType, typename VectorType>
128  RandomNumberGenerator &randomNumberGenerator) {
129  stateMean = (t * stateMean + state) / (t + 1);
130 
131  for (long i = 0; i < m_proposal.rows(); ++i) {
132  m_proposal(i) = normal(randomNumberGenerator);
133  }
134 
135  if (t > warmUp) {
136  m_proposal = state + stateCholeskyOfCovariance * m_proposal;
137  } else {
138  m_proposal = state + eps * choleskyOfMaximumVolumeEllipsoid.template triangularView<Eigen::Lower>().solve(m_proposal);
139  }
140 ;
141  ++t; // increment time
142  }
143 
144  template<typename MatrixType, typename VectorType>
145  void
147  state.swap(m_proposal);
148  stateCovariance = proposalCovariance;
149  stateCholeskyOfCovariance = proposalCholeskyOfCovariance;
150  stateLogSqrtDeterminant = proposalLogSqrtDeterminant;
151  }
152 
153  template<typename MatrixType, typename VectorType>
154  typename MatrixType::Scalar
156  bool isProposalInteriorPoint = ((A * m_proposal - b).array() < -boundaryCushion).all();
157  if (!isProposalInteriorPoint) {
158  return -std::numeric_limits<typename MatrixType::Scalar>::infinity();
159  }
160 
161  proposalCovariance = updateCovariance(stateCovariance, stateMean, m_proposal);
162  Eigen::LLT<Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>> solver(proposalCovariance);
163  if (solver.info() != Eigen::Success) {
164  return -std::numeric_limits<typename MatrixType::Scalar>::infinity();
165  }
166  proposalCholeskyOfCovariance = solver.matrixL();
167 
168  proposalLogSqrtDeterminant = proposalCholeskyOfCovariance.diagonal().array().log().sum();
169  StateType stateDifference = m_proposal - state;
170 
171  double alpha = 0;
172 
173  // before warm up we have a symmetrical m_proposal distribution
174  if (t > warmUp) {
175  alpha = stateLogSqrtDeterminant
176  - proposalLogSqrtDeterminant
177  - 0.5 * (
178  proposalCholeskyOfCovariance.template triangularView<Eigen::Lower>().solve(stateDifference).squaredNorm()
179  - stateCholeskyOfCovariance.template triangularView<Eigen::Lower>().solve(stateDifference).squaredNorm()
180  );
181  }
182 
183  return alpha;
184  }
185 
186  template<typename MatrixType, typename VectorType>
189  return state;
190  }
191 
192  template<typename MatrixType, typename VectorType>
195  return m_proposal;
196  }
197 
198  template<typename MatrixType, typename VectorType>
200  AdaptiveMetropolisProposal::state = std::move(newState);
201  }
202 
203  template<typename MatrixType, typename VectorType>
205  typename MatrixType::Scalar newStepSize) {
206  stepSize = newStepSize;
207  normal = std::normal_distribution<typename MatrixType::Scalar>(0, stepSize);
208  }
209 
210  template<typename MatrixType, typename VectorType>
211  typename MatrixType::Scalar
213  return stepSize;
214  }
215 
216  template<typename MatrixType, typename VectorType>
218  return "AdaptiveMetropolis";
219  }
220 }
221 
222 #endif //HOPS_ADAPTIVEMETROPOLISPROPOSAL_HPP
hops::AdaptiveMetropolisProposal::getProposal
StateType getProposal() const
Definition: AdaptiveMetropolisProposal.hpp:194
hops::AdaptiveMetropolisProposal::getState
StateType getState() const
Definition: AdaptiveMetropolisProposal.hpp:188
hops::AdaptiveMetropolisProposal::StateType
VectorType StateType
Definition: AdaptiveMetropolisProposal.hpp:14
hops::MatrixType
Eigen::MatrixXd MatrixType
Definition: MatrixType.hpp:7
hops::AdaptiveMetropolisProposal::AdaptiveMetropolisProposal
AdaptiveMetropolisProposal(MatrixType A, VectorType b, StateType currentState, typename MatrixType::Scalar stepSize=1, typename MatrixType::Scalar eps=1.e-3, unsigned long warmUp=100)
Constructs the Adaptive Metropolis m_proposal mechanism (Haario et al. 2001) on polytope defined as Ax<...
Definition: AdaptiveMetropolisProposal.hpp:95
pcg_detail::engine
Definition: pcg_random.hpp:364
hops::AdaptiveMetropolisProposal::getName
std::string getName()
Definition: AdaptiveMetropolisProposal.hpp:217
hops::MaximumVolumeEllipsoid::construct
static MaximumVolumeEllipsoid construct(const Eigen::Matrix< RealType, Eigen::Dynamic, Eigen::Dynamic > &A, const Eigen::Matrix< RealType, Eigen::Dynamic, 1 > &b, size_t maximumNumberOfIterationsToRun, const Eigen::Matrix< RealType, Eigen::Dynamic, 1 > &startingPoint, RealType tolerance=1e-6)
Definition: MaximumVolumeEllipsoid.cpp:84
hops::MaximumVolumeEllipsoid::getEllipsoid
Eigen::Matrix< RealType, Eigen::Dynamic, Eigen::Dynamic > getEllipsoid() const
Definition: MaximumVolumeEllipsoid.cpp:58
hops::AdaptiveMetropolisProposal::getStepSize
MatrixType::Scalar getStepSize() const
Definition: AdaptiveMetropolisProposal.hpp:212
hops
Definition: CsvReader.hpp:8
hops::AdaptiveMetropolisProposal::setStepSize
void setStepSize(typename MatrixType::Scalar stepSize)
Definition: AdaptiveMetropolisProposal.hpp:204
hops::AdaptiveMetropolisProposal::propose
void propose(RandomNumberGenerator &randomNumberGenerator)
Definition: AdaptiveMetropolisProposal.hpp:127
string
NAME string(REPLACE ".cpp" "_bin" example_name ${example_filename}) if($
Definition: hops/Third-party/HighFive/src/examples/CMakeLists.txt:6
hops::VectorType
Eigen::VectorXd VectorType
Definition: VectorType.hpp:7
hops::AdaptiveMetropolisProposal
Definition: AdaptiveMetropolisProposal.hpp:12
hops::AdaptiveMetropolisProposal::setState
void setState(StateType newState)
Definition: AdaptiveMetropolisProposal.hpp:199
hops::AdaptiveMetropolisProposal::acceptProposal
void acceptProposal()
Definition: AdaptiveMetropolisProposal.hpp:146
hops::AdaptiveMetropolisProposal::computeLogAcceptanceProbability
MatrixType::Scalar computeLogAcceptanceProbability()
Definition: AdaptiveMetropolisProposal.hpp:155