MUQ  0.4.3
GMHKernel.cpp
Go to the documentation of this file.
2 
3 #include <Eigen/Eigenvalues>
4 
5 #if MUQ_HAS_PARCER
6 #include <cereal/types/tuple.hpp>
7 #endif
8 
11 
12 namespace pt = boost::property_tree;
13 using namespace muq::Utilities;
14 using namespace muq::SamplingAlgorithms;
15 
17 
18 #if MUQ_HAS_PARCER
19 
20 // first: current step, second: the current state, third: do we want to propose a new state or not?
21 typedef std::tuple<unsigned int, std::shared_ptr<SamplingState>, bool> CurrentState;
22 
23 class ProposeState {
24 public:
25  inline ProposeState() {}
26  //inline ProposeState(std::shared_ptr<MCMCProposal> const& proposal, std::shared_ptr<AbstractSamplingProblem> const& problem) : proposal(proposal), problem(problem) {}
27 
28  virtual ~ProposeState() = default;
29 
30  /*//inline std::shared_ptr<SamplingState> Evaluate(CurrentState state) { return nullptr; }
31  inline std::shared_ptr<SamplingState> Evaluate(CurrentState state) {
32  std::shared_ptr<SamplingState> proposed = std::get<2>(state) ? proposal->Sample(std::get<1>(state)) : std::get<1>(state);
33  proposed->meta["LogTarget"] = problem->LogDensity(std::get<0>(state), proposed, std::get<2>(state) ? AbstractSamplingProblem::SampleType::Proposed : AbstractSamplingProblem::SampleType::Accepted);
34  // TODO: Fill in gradient information if needed by proposal
35  return proposed;
36  }
37 
38  std::shared_ptr<MCMCProposal> proposal;
39  std::shared_ptr<AbstractSamplingProblem> problem;*/
40 };
41 
42 //typedef parcer::Queue<CurrentState, std::shared_ptr<SamplingState>, ProposeState> ProposalQueue;
43 #endif
44 
45 GMHKernel::GMHKernel(pt::ptree const& pt, std::shared_ptr<AbstractSamplingProblem> problem) : MHKernel(pt, problem),
46  N(pt.get<unsigned int>("NumProposals")),
47  Np1(N+1),
48  M(pt.get<unsigned int>("NumAccepted", N)) {}
49 
50 GMHKernel::GMHKernel(pt::ptree const& pt, std::shared_ptr<AbstractSamplingProblem> problem, std::shared_ptr<MCMCProposal> proposalIn) :
51  MHKernel(pt, problem, proposalIn),
52  N(pt.get<unsigned int>("NumProposals")),
53  Np1(N+1),
54  M(pt.get<unsigned int>("NumAccepted", N)) {}
55 
56 GMHKernel::~GMHKernel() {}
57 
58 void GMHKernel::SerialProposal(unsigned int const t, std::shared_ptr<SamplingState> state) {
59 
60  // If the current state does not have LogTarget information, add it
61  if(! state->HasMeta("LogTarget"))
62  state->meta["LogTarget"] = problem->LogDensity(state);
63 
64  // propose the points
65  proposedStates.resize(Np1, nullptr);
66  proposedStates[0] = state;
67 
68  for(auto it = proposedStates.begin()+1; it!=proposedStates.end(); ++it ) {
69  *it = proposal->Sample(state);
70  (*it)->meta["LogTarget"] = problem->LogDensity(*it);
71  }
72 
73  // evaluate the target density
74  Eigen::VectorXd R = Eigen::VectorXd::Zero(Np1);
75  for( unsigned int i=0; i<Np1; ++i )
76  R(i) = AnyCast(proposedStates[i]->meta["LogTarget"]);
77 
78  // compute stationary transition probability
80 }
81 
82 #if MUQ_HAS_PARCER
83 
84 void GMHKernel::ParallelProposal(unsigned int const t, std::shared_ptr<SamplingState> state) {
85  // if we only have one processor, just propose in serial
86  if( comm->GetSize()==1 ) { return SerialProposal(t, state); }
87 
88  // create a queue to propose and evaluate the log-target
89  auto helper = std::make_shared<ProposeState>();
90  assert(helper);
91  //auto helper = std::make_shared<ProposeState>(proposal, problem);
92  //auto proposalQueue = std::make_shared<ProposalQueue>(helper, comm);
93 
94  if( comm->GetRank()==0 ) {
95  /*std::cout << "ONE RANK IS HERE" << std::endl;
96  assert(state);
97 
98  // submit the work
99  std::vector<int> proposalIDs(Np1);
100 
101  // If the current state doesn't have the logtarget evaluation, submit it to the queue for evaluation
102  if(!state->HasMeta("LogTarget")){
103  proposalIDs[0] = proposalQueue->SubmitWork(CurrentState(t, state, false)); // evaluate the current state
104  }else{
105  proposalIDs[0] = -1;
106  }
107 
108  std::cout << "NOW IT IS HERE" << std::endl;
109 
110  // Submit a bunch of proposal requests to the queue
111  for( auto id=proposalIDs.begin()+1; id!=proposalIDs.end(); ++id )
112  *id = proposalQueue->SubmitWork(CurrentState(t, state, true));
113 
114  std::cout << "OKAY THEN" << std::endl;
115 
116  // retrieve the work
117  proposedStates.resize(Np1, nullptr);
118  Eigen::VectorXd R = Eigen::VectorXd::Zero(Np1);
119 
120  if(proposalIDs[0]<0){
121  proposedStates[0] = state;
122  }else{
123  proposedStates[0] = proposalQueue->GetResult(proposalIDs[0]);
124  }
125  R(0) = AnyCast(proposedStates[0]->meta["LogTarget"]);
126 
127  for( unsigned int i=1; i<Np1; ++i ) {
128  proposedStates[i] = proposalQueue->GetResult(proposalIDs[i]);
129  R(i) = AnyCast(proposedStates[i]->meta["LogTarget"]);
130  }
131 
132  std::cout << "THIS FAR" << std::endl;
133 
134  // compute stationary transition probability
135  AcceptanceDensity(R);*/
136  }
137 }
138 #endif
139 
140 void GMHKernel::AcceptanceDensity(Eigen::VectorXd& R) {
141 
142  // update log-target with proposal density
143  for( unsigned int i=0; i<Np1; ++i ) {
144  for( auto k : proposedStates ) {
145  if( k==proposedStates[i] ) { continue; }
146  R(i) += proposal->LogDensity(proposedStates[i], k);
147  }
148  }
149 
150  // compute the cumlative acceptance density
152 }
153 
154 Eigen::MatrixXd GMHKernel::AcceptanceMatrix(Eigen::VectorXd const& R) const {
155  // compute stationary acceptance transition probability
156  Eigen::MatrixXd A = Eigen::MatrixXd::Ones(Np1,Np1);
157  for( unsigned int i=0; i<Np1; ++i ) {
158  for( unsigned int j=0; j<Np1; ++j ) {
159  if( j==i ) { continue; }
160  A(i,j) = std::fmin(1.0, std::exp(R(j)-R(i)))/(double)(Np1);
161  A(i,i) -= A(i,j);
162  }
163  }
164 
165  return A;
166 }
167 
168 void GMHKernel::ComputeStationaryAcceptance(Eigen::VectorXd const& R) {
169  const Eigen::MatrixXd& A = AcceptanceMatrix(R);
170 
171  stationaryAcceptance = Eigen::VectorXd::Ones(A.cols()).normalized();
172 
173  Eigen::MatrixXd mat(Np1+1, Np1);
174  mat.block(0,0,Np1,Np1) = A.transpose()-Eigen::MatrixXd::Identity(Np1,Np1);
175  mat.row(Np1) = Eigen::RowVectorXd::Ones(Np1);
176 
177  Eigen::VectorXd rhs = Eigen::VectorXd::Zero(Np1+1);
178  rhs(Np1) = 1.0;
179 
180  stationaryAcceptance = mat.colPivHouseholderQr().solve(rhs);
181 }
182 
183 void GMHKernel::PreStep(unsigned int const t, std::shared_ptr<SamplingState> state) {
184  // propose N steps
185 #if MUQ_HAS_PARCER
186  if( comm ) {
187  if( comm->GetRank()==0 ) { assert(state); }
188  ParallelProposal(t, state);
189  }else{
190  SerialProposal(t, state);
191  }
192 #else
193  SerialProposal(t, state);
194 #endif
195 }
196 
197 std::vector<std::shared_ptr<SamplingState> > GMHKernel::SampleStationary() const {
198  std::vector<std::shared_ptr<SamplingState> > newStates(M, nullptr);
199 
200  // get the indices of the proposed states that are accepted
201  Eigen::VectorXi indices = RandomGenerator::GetDiscrete(stationaryAcceptance, M);
202  assert(indices.size()==M);
203 
204  // store the accepted states
205  for( unsigned int i=0; i<M; ++i ) { newStates[i] = proposedStates[indices[i]]; }
206 
207  return newStates;
208 }
209 
210 std::vector<std::shared_ptr<SamplingState> > GMHKernel::Step(unsigned int const t, std::shared_ptr<SamplingState> state) {
211 
212 #if MUQ_HAS_PARCER
213  if( !comm ) { return SampleStationary(); }
214  return comm->GetRank()==0 ? SampleStationary() : std::vector<std::shared_ptr<SamplingState> >(M, nullptr);
215 #else
216  return SampleStationary();
217 #endif
218 }
219 
220 Eigen::VectorXd GMHKernel::StationaryAcceptance() const {
221  // make sure this object has been populated
222  assert(stationaryAcceptance.size()==Np1);
223 
224  return stationaryAcceptance;
225 }
226 
227 #if MUQ_HAS_PARCER
228 std::shared_ptr<parcer::Communicator> GMHKernel::GetCommunicator() const { return comm; }
229 #endif
REGISTER_TRANSITION_KERNEL(DRKernel) DRKernel
Definition: DRKernel.cpp:15
A kernel for the generalized Metropolis-Hastings kernel.
Definition: GMHKernel.h:19
void SerialProposal(unsigned int const t, std::shared_ptr< SamplingState > state)
Propose points in serial and evaluate the log target.
Definition: GMHKernel.cpp:58
Eigen::MatrixXd AcceptanceMatrix(Eigen::VectorXd const &R) const
Definition: GMHKernel.cpp:154
const unsigned int Np1
Number of proposals plus one.
Definition: GMHKernel.h:109
void ParallelProposal(unsigned int const t, std::shared_ptr< SamplingState > state)
Propose points in parallel and evaluate the log target.
Definition: GMHKernel.cpp:84
Eigen::VectorXd stationaryAcceptance
The cumulative stationary accepatnce probability.
Definition: GMHKernel.h:115
std::shared_ptr< parcer::Communicator > GetCommunicator() const
Definition: GMHKernel.cpp:228
std::vector< std::shared_ptr< SamplingState > > SampleStationary() const
Sample the stationary distribution.
Definition: GMHKernel.cpp:197
Eigen::VectorXd StationaryAcceptance() const
Get the cumulative stationary acceptance probability.
Definition: GMHKernel.cpp:220
void ComputeStationaryAcceptance(Eigen::VectorXd const &R)
Compute the cumulative acceptance density.
Definition: GMHKernel.cpp:168
virtual std::vector< std::shared_ptr< SamplingState > > Step(unsigned int const t, std::shared_ptr< SamplingState > state) override
Definition: GMHKernel.cpp:210
std::vector< std::shared_ptr< SamplingState > > proposedStates
Proposed states.
Definition: GMHKernel.h:118
void AcceptanceDensity(Eigen::VectorXd &R)
Compute the stationary transition density.
Definition: GMHKernel.cpp:140
virtual void PreStep(unsigned int const t, std::shared_ptr< SamplingState > state) override
Definition: GMHKernel.cpp:183
const unsigned int M
Number of accepted points (number of points added to the chain)
Definition: GMHKernel.h:112
An implementation of the standard Metropolis-Hastings transition kernel.
Definition: MHKernel.h:22
std::shared_ptr< MCMCProposal > proposal
Definition: MHKernel.h:45
std::shared_ptr< parcer::Communicator > comm
std::shared_ptr< AbstractSamplingProblem > problem
The sampling problem that evaluates/samples the target distribution.
Class for easily casting boost::any's in assignment operations.
Definition: AnyHelpers.h:34
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.h:3956