MUQ  0.4.3
ParallelMIMCMCBox.h
Go to the documentation of this file.
1 #ifndef PARALLELMIMCMCBOX_H_
2 #define PARALLELMIMCMCBOX_H_
3 
4 #include "MUQ/config.h"
5 
6 
7 #if MUQ_HAS_MPI
8 
9 #if !MUQ_HAS_PARCER
10 #error
11 #endif
12 
13 #include <parcer/Communicator.h>
14 #include <boost/property_tree/ptree.hpp>
15 
22 
24 
25 namespace pt = boost::property_tree;
26 using namespace muq::Utilities;
27 
28 namespace muq {
29  namespace SamplingAlgorithms {
30 
41  public:
42 
43  ParallelMIMCMCBox(boost::property_tree::ptree const& pt, std::shared_ptr<MIComponentFactory> componentFactory, std::shared_ptr<MultiIndex> boxHighestIndex, std::shared_ptr<parcer::Communicator> global_comm, std::shared_ptr<PhonebookClient> phonebookClient, std::shared_ptr<muq::Utilities::OTF2TracerBase> tracer)
44  : QOIDiff(std::make_shared<MarkovChain>()),
45  componentFactory(componentFactory),
46  boxHighestIndex(boxHighestIndex)
47  {
48  pt::ptree ptChains;
49  ptChains.put("NumSamples", 0); // number of MCMC steps expected, so we'll pass it in
50  ptChains.put("BurnIn", 0);
51  ptChains.put("PrintLevel", 0);
52  ptChains.put("BlockIndex",0);
53  pt::ptree ptBlockID;
54  ptBlockID.put("BlockIndex",0);
55 
56 
57  boxLowestIndex = MultiIndex::Copy(boxHighestIndex);
58  --(*boxLowestIndex);
59 
60  std::shared_ptr<MultiIndex> boxSize = std::make_shared<MultiIndex>(*boxHighestIndex - *boxLowestIndex);
61 
62  // Set up Multiindex box
63  boxIndices = MultiIndexFactory::CreateFullTensor(boxSize->GetVector());
64  boxChains.resize(boxIndices->Size());
65 
66  std::shared_ptr<SingleChainMCMC> coarse_chain = nullptr;
67  std::shared_ptr<AbstractSamplingProblem> coarse_problem = nullptr;
68 
69  for (uint i = 0; i < boxIndices->Size(); i++) {
70  std::shared_ptr<MultiIndex> boxIndex = (*boxIndices)[i];
71 
72  if (boxIndex->Max() == 0) { // We're the root node of the MI box
73  if (boxLowestIndex->Max() == 0) { // and also the absolute root node, so run the globally coarsest chain by ourselves
74  coarse_problem = componentFactory->SamplingProblem(boxLowestIndex);
75  auto proposal_coarse = componentFactory->Proposal(boxLowestIndex, coarse_problem);
76 
77  std::vector<std::shared_ptr<TransitionKernel>> coarse_kernels(1);
78  if (componentFactory->IsInverseProblem())
79  coarse_kernels[0] = std::make_shared<MHKernel>(ptBlockID,coarse_problem,proposal_coarse);
80  else
81  coarse_kernels[0] = std::make_shared<DummyKernel>(ptBlockID, coarse_problem, proposal_coarse);
82 
83  Eigen::VectorXd startPtCoarse = componentFactory->StartingPoint(boxLowestIndex);
84 
85  pt::ptree ptCoarsestChain;
86  ptCoarsestChain.put("PrintLevel", 0);
87  ptCoarsestChain.put("NumSamples", 0); // number of MCMC steps expected, so we'll pass it in
88  ptCoarsestChain.put("BurnIn", pt.get<int>("MCMC.BurnIn")); // Pass BurnIn length into coarsest chain of box
89 
90  coarse_chain = std::make_shared<SingleChainMCMC>(ptCoarsestChain,coarse_kernels);
91  coarse_chain->SetState(startPtCoarse);
92  boxChains[boxIndices->MultiToIndex(boxIndex)] = coarse_chain;
93 
94  tracer->enterRegion(TracerRegions::BurnIn);
95  spdlog::debug("Rank {} burning in", global_comm->GetRank());
96  coarse_chain->AddNumSamps(pt.get<int>("MCMC.BurnIn"));
97  coarse_chain->Run();
98  spdlog::debug("Rank {} burned in", global_comm->GetRank());
99  tracer->leaveRegion(TracerRegions::BurnIn);
100 
101  } else { // or we have to request proposals from the next coarser chain
102  std::shared_ptr<MultiIndex> remoteIndex = MultiIndex::Copy(boxLowestIndex);
103  int maxCoeffId;
104  int maxEntry = remoteIndex->GetVector().maxCoeff(&maxCoeffId);
105  assert (maxEntry > 0);
106 
107  remoteIndex->SetValue(maxCoeffId, maxEntry - 1);
108 
109  auto remote_problem = componentFactory->SamplingProblem(remoteIndex); // TODO: Try to avoid this
110 
111  auto coarse_proposal = std::make_shared<RemoteMIProposal>(ptBlockID, remote_problem, global_comm, remoteIndex, boxHighestIndex, phonebookClient);
112  auto startingPoint = componentFactory->StartingPoint(boxLowestIndex);
113  auto problem = componentFactory->SamplingProblem(boxLowestIndex);
114  auto proposal = componentFactory->Proposal(boxLowestIndex, problem);
115  auto proposalInterpolation = componentFactory->Interpolation(boxLowestIndex);
116 
117  std::vector<std::shared_ptr<TransitionKernel>> kernels(1);
118  if (componentFactory->IsInverseProblem())
119  kernels[0] = std::make_shared<MIKernel>(ptBlockID,problem,remote_problem,proposal,coarse_proposal,proposalInterpolation,nullptr);
120  else
121  kernels[0] = std::make_shared<MIDummyKernel>(ptBlockID, problem, proposal, coarse_proposal, proposalInterpolation, coarse_chain);
122 
123  auto startingState = std::make_shared<SamplingState>(startingPoint);
124  startingState->meta["coarseSample"] = std::make_shared<SamplingState>(componentFactory->StartingPoint(remoteIndex));
125 
126  coarse_chain = std::make_shared<SingleChainMCMC>(ptChains,kernels);
127  coarse_chain->SetState(startingState);
128 
129  boxChains[boxIndices->MultiToIndex(boxIndex)] = coarse_chain;
130  coarse_problem = problem;
131  }
132  } else { // All in all, you're just another node in the MI box (We don't need no communication... We don't need no remote control...) - Pink Floyd
133 
134  std::shared_ptr<MultiIndex> index = std::make_shared<MultiIndex>(*boxLowestIndex + *boxIndex);
135 
136  auto problem = componentFactory->SamplingProblem(index);
137  auto proposal = componentFactory->Proposal(index, problem);
138  auto coarse_proposal = componentFactory->CoarseProposal(index, boxLowestIndex, coarse_problem, coarse_chain);
139  auto proposalInterpolation = componentFactory->Interpolation(index);
140  auto startingPoint = componentFactory->StartingPoint(index);
141 
142  std::vector<std::shared_ptr<TransitionKernel>> kernels(1);
143  if (componentFactory->IsInverseProblem())
144  kernels[0] = std::make_shared<MIKernel>(ptBlockID,problem,coarse_problem,proposal,coarse_proposal,proposalInterpolation,coarse_chain);
145  else
146  kernels[0] = std::make_shared<MIDummyKernel>(ptBlockID, problem, proposal, coarse_proposal, proposalInterpolation, coarse_chain);
147 
148  auto chain = std::make_shared<SingleChainMCMC>(ptChains,kernels);
149  chain->SetState(startingPoint);
150 
151  boxChains[boxIndices->MultiToIndex(boxIndex)] = chain;
152 
153  if (*boxIndex == *boxSize)
154  finestProblem = problem;
155  }
156 
157  }
158  if (boxHighestIndex->Max() == 0)
159  finestProblem = coarse_problem;
160  }
161 
162  std::shared_ptr<AbstractSamplingProblem> GetFinestProblem() {
163  return finestProblem;
164  }
165 
166  std::shared_ptr<SingleChainMCMC> FinestChain() {
167  std::shared_ptr<MultiIndex> boxSize = std::make_shared<MultiIndex>(*boxHighestIndex - *boxLowestIndex);
168  return boxChains[boxIndices->MultiToIndex(boxSize)];
169  }
170 
171  std::shared_ptr<SingleChainMCMC> GetChain(int index) {
172  return boxChains[index];
173  }
174 
175  int NumChains() {
176  return boxIndices->Size();
177  }
178 
179  void Sample() {
180  // Set up valid sample vector with arbitrary number of components in order to store contribution to telescoping sum
181  const int num_components = GetFinestProblem()->blockSizesQOI.size();
182  std::vector<Eigen::VectorXd> sampDiff(num_components);
183  for (int component = 0; component < num_components; component++) {
184  sampDiff[component] = Eigen::VectorXd::Zero(GetFinestProblem()->blockSizesQOI[component]);
185  }
186 
187  /*
188  auto chain = boxChains[boxIndices->MultiToIndex(boxHighestIndex)];
189  chain->AddNumSamps(1);
190  chain->Run();*/
191 
192  // Advance chains
193  for (unsigned int i = 0; i < boxIndices->Size(); i++) {
194  std::shared_ptr<MultiIndex> boxIndex = (*boxIndices)[i];
195  auto chain = boxChains[boxIndices->MultiToIndex(boxIndex)];
196  chain->AddNumSamps(1);
197  chain->Run();
198  }
199 
200  for (unsigned int i = 0; i < boxIndices->Size(); i++) {
201  std::shared_ptr<MultiIndex> boxIndex = (*boxIndices)[i];
202  auto chain = boxChains[boxIndices->MultiToIndex(boxIndex)];
203 
204  // Add new sample to difference according to chain's position in telescoping sum
205  if (chain->GetQOIs()->size() > 0) {
206  auto new_state = chain->GetQOIs()->back();
207 
208  std::shared_ptr<MultiIndex> index = std::make_shared<MultiIndex>(*boxLowestIndex + *boxIndex);
209  auto indexDiffFromTop = std::make_shared<MultiIndex>(*boxHighestIndex - *index);
210 
211  if (indexDiffFromTop->Sum() % 2 == 0) {
212  for (int component = 0; component < num_components; component++) {
213  sampDiff[component] += new_state->state[component];
214  }
215  } else {
216  for (int component = 0; component < num_components; component++) {
217  sampDiff[component] -= new_state->state[component];
218  }
219  }
220  }
221  }
222  if (boxChains[0]->GetQOIs()->size() > 0)
223  QOIDiff->Add(std::make_shared<SamplingState>(sampDiff));
224 
225  }
226 
227  Eigen::VectorXd MeanQOI() {
228  Eigen::VectorXd sampMean = Eigen::VectorXd::Zero(GetFinestProblem()->blockSizesQOI.sum());
229 
230  for (uint i = 0; i < boxIndices->Size(); i++) {
231  std::shared_ptr<MultiIndex> boxIndex = (*boxIndices)[i];
232  auto chain = boxChains[boxIndices->MultiToIndex(boxIndex)];
233  auto samps = chain->GetQOIs();
234 
235  std::shared_ptr<MultiIndex> index = std::make_shared<MultiIndex>(*boxLowestIndex + *boxIndex);
236  auto indexDiffFromTop = std::make_shared<MultiIndex>(*boxHighestIndex - *index);
237 
238  if (indexDiffFromTop->Sum() % 2 == 0) {
239  sampMean += samps->Mean();
240  } else {
241  sampMean -= samps->Mean();
242  }
243  }
244  return sampMean;
245  }
246 
247  std::shared_ptr<SampleCollection> GetQOIDiff() {
248  return QOIDiff;
249  }
250 
251  private:
252 
253  std::shared_ptr<SampleCollection> QOIDiff;
254 
255  std::shared_ptr<MIComponentFactory> componentFactory;
256  std::shared_ptr<MultiIndex> boxHighestIndex;
257  std::shared_ptr<MultiIndex> boxLowestIndex;
258  std::shared_ptr<MultiIndexSet> boxIndices;
259  std::vector<std::shared_ptr<SingleChainMCMC>> boxChains;
260  std::vector<std::shared_ptr<SingleChainMCMC>> tailChains;
261  std::shared_ptr<AbstractSamplingProblem> finestProblem = nullptr;
262  };
263 
264  }
265 }
266 
267 #endif
268 
269 #endif
A class for storing and working with the results of Markov chain Monte Carlo algorithms.
Definition: MarkovChain.h:20
Parallel equivalent to the MIMCMCBox, holds chains representing telescoping sum component.
std::shared_ptr< SingleChainMCMC > FinestChain()
std::shared_ptr< AbstractSamplingProblem > GetFinestProblem()
std::shared_ptr< MultiIndex > boxLowestIndex
std::vector< std::shared_ptr< SingleChainMCMC > > boxChains
std::shared_ptr< MultiIndexSet > boxIndices
std::shared_ptr< MIComponentFactory > componentFactory
std::shared_ptr< SampleCollection > GetQOIDiff()
std::shared_ptr< SampleCollection > QOIDiff
std::shared_ptr< MultiIndex > boxHighestIndex
std::vector< std::shared_ptr< SingleChainMCMC > > tailChains
ParallelMIMCMCBox(boost::property_tree::ptree const &pt, std::shared_ptr< MIComponentFactory > componentFactory, std::shared_ptr< MultiIndex > boxHighestIndex, std::shared_ptr< parcer::Communicator > global_comm, std::shared_ptr< PhonebookClient > phonebookClient, std::shared_ptr< muq::Utilities::OTF2TracerBase > tracer)
std::shared_ptr< SingleChainMCMC > GetChain(int index)
static std::shared_ptr< MultiIndexSet > CreateFullTensor(unsigned int const length, unsigned int const order, std::shared_ptr< MultiIndexLimiter > limiter=std::make_shared< NoLimiter >())
Construct a full tensor product multiindex set.