MUQ  0.4.3
SingleChainMCMC.cpp
Go to the documentation of this file.
2 
3 #include <chrono>
4 
7 
9 
10 namespace pt = boost::property_tree;
11 using namespace muq::Utilities;
12 using namespace muq::SamplingAlgorithms;
13 
14 SingleChainMCMC::SingleChainMCMC(pt::ptree pt,
15  std::shared_ptr<AbstractSamplingProblem> const& problem) :
16  samples(std::make_shared<MarkovChain>()),
17  QOIs(std::make_shared<MarkovChain>()),
18  printLevel(pt.get("PrintLevel",3))
19 {
20  Setup(pt, problem);
21 }
22 
23 SingleChainMCMC::SingleChainMCMC(boost::property_tree::ptree pt,
24  std::vector<std::shared_ptr<TransitionKernel> > const& kernelsIn) :
25  samples(std::make_shared<MarkovChain>()),
26  QOIs(std::make_shared<MarkovChain>()),
27  printLevel(pt.get("PrintLevel",3))
28 {
29  Setup(pt,kernelsIn);
30 }
31 
32 #if MUQ_HAS_PARCER
34  std::shared_ptr<AbstractSamplingProblem> const& problem,
35  std::shared_ptr<parcer::Communicator> const& comm) :
36  samples(std::make_shared<MarkovChain>()),
37  QOIs(std::make_shared<MarkovChain>()),
38  printLevel(pt.get("PrintLevel",3)),
39  comm(comm)
40 {
41  Setup(pt, problem);
42 }
43 
45  std::shared_ptr<parcer::Communicator> const& comm,
46  std::vector<std::shared_ptr<TransitionKernel> > const& kernelsIn) :
47  samples(std::make_shared<MarkovChain>()),
48  QOIs(std::make_shared<MarkovChain>()),
49  printLevel(pt.get("PrintLevel",3)),
50  comm(comm)
51 {
52  Setup(pt, kernelsIn);
53 }
54 
55 #endif
56 
57 
58 
59 void SingleChainMCMC::Setup(pt::ptree pt,
60  std::vector<std::shared_ptr<TransitionKernel>> const& kernelsIn) {
61 
62  assert(kernelsIn.size()>0);
63 
64  numSamps = pt.get<unsigned int>("NumSamples");
65  burnIn = pt.get("BurnIn",0);
66 
67  kernels = kernelsIn;
68 
69  scheduler = std::make_shared<ThinScheduler>(pt);
70  schedulerQOI = std::make_shared<ThinScheduler>(pt);
71  assert(scheduler);
72  assert(schedulerQOI);
73 
74 #if MUQ_HAS_PARCER
75 
76  for(int i=0; i<kernels.size(); ++i)
77  kernels.at(i)->SetCommunicator(comm);
78 
79 #endif
80 
81 }
82 
83 void SingleChainMCMC::Setup(pt::ptree pt, std::shared_ptr<AbstractSamplingProblem> const& problem) {
84 
85  std::string kernelString = pt.get<std::string>("KernelList");
86  std::vector<std::string> kernelNames = StringUtilities::Split(kernelString, ',');
87 
88  std::vector<std::shared_ptr<TransitionKernel>> kernelVec;
89  unsigned int numBlocks = kernelNames.size();
90  assert(numBlocks>0);
91  kernelVec.resize(numBlocks);
92 
93  // Add the block id to a child tree and construct a kernel for each block
94  for(int i=0; i<numBlocks; ++i) {
95  boost::property_tree::ptree subTree = pt.get_child(kernelNames.at(i));
96  subTree.put("BlockIndex",i);
97 
98  problem->AddOptions(subTree);
99  kernelVec.at(i) = TransitionKernel::Construct(subTree, problem);
100  }
101 
102  Setup(pt, kernelVec);
103 }
104 
105 void SingleChainMCMC::PrintStatus(std::string prefix) const {
106  PrintStatus(prefix, numSamps);
107 }
108 
109 void SingleChainMCMC::PrintStatus(std::string prefix, unsigned int currInd) const
110 {
111  std::cout << prefix << int(std::floor(double((currInd - 1) * 100) / double(numSamps))) << "% Complete" << std::endl;
112  if(printLevel>1){
113  for(int blockInd=0; blockInd<kernels.size(); ++blockInd){
114  std::cout << prefix << " Block " << blockInd << ":\n";
115  kernels.at(blockInd)->PrintStatus(prefix + " ");
116  }
117  }
118 }
119 
120 std::shared_ptr<MarkovChain> SingleChainMCMC::Run(std::vector<Eigen::VectorXd> const& x0) {
121  if( !x0.empty() ) { SetState(x0); }
122 
123  // What is the next iteration that we want to print at
124  const unsigned int printIncr = std::floor(numSamps / double(10));
125  unsigned int nextPrintInd = printIncr;
126 
127  // Run until we've received the desired number of samples
128  if(printLevel>0)
129  std::cout << "Starting single chain MCMC sampler..." << std::endl;
130 
131  while(sampNum < numSamps)
132  {
133  // Should we print
134  if(sampNum > nextPrintInd){
135  if(printLevel>0){
136  PrintStatus(" ", sampNum);
137  }
138  nextPrintInd += printIncr;
139  }
140 
141  Sample();
142  }
143 
144 
145  if(printLevel>0){
146  PrintStatus(" ", numSamps+1);
147  std::cout << "Completed in " << totalTime << " seconds." << std::endl;
148  }
149 
150  return samples;
151 }
152 
154  if(prevState==nullptr){
155  std::stringstream msg;
156  msg << "\nERROR in SingleChainMCMC::Sample! Trying to sample chain but previous (or initial) state has not been set.\n";
157  throw std::runtime_error(msg.str());
158  }
159 
160  auto startTime = std::chrono::high_resolution_clock::now();
161 
162  std::vector<std::shared_ptr<SamplingState> > newStates;
163 
164  // Loop through each parameter block
165  for(int blockInd=0; blockInd<kernels.size(); ++blockInd){
166 
167  // Set some metadata that might be needed by the expensive sampling problem
168  prevState->meta["iteration"] = sampNum;
169  prevState->meta["IsProposal"] = false;
170 
171  // kernel prestep
172  kernels.at(blockInd)->PreStep(sampNum, prevState);
173 
174  // use the kernel to get the next state(s)
175  newStates = kernels.at(blockInd)->Step(sampNum, prevState);
176 
177  // save when these samples where created
178  const double now = std::chrono::duration<double>(std::chrono::high_resolution_clock::now()-startTime).count();
179  for( auto it=newStates.begin(); it!=newStates.end(); ++it ) {
180  (*it)->meta["time"] = now;
181  }
182 
183  // kernel post-processing
184  kernels.at(blockInd)->PostStep(sampNum, newStates);
185 
186  // add the new states to the SampleCollection (this also increments sampNum)
188  }
189 
190  auto endTime = std::chrono::high_resolution_clock::now();
191  totalTime += std::chrono::duration<double>(endTime - startTime).count();
192 }
193 
194 std::shared_ptr<SamplingState> SingleChainMCMC::SaveSamples(std::vector<std::shared_ptr<SamplingState> > const& newStates,
195  std::shared_ptr<SamplingState>& lastSavedState,
196  unsigned int& sampNum) const {
197  for( auto it : newStates ) {
198  // save the sample, if we want to
199  if( ShouldSave(sampNum) ) {
200  samples->Add(it);
201  if (it->HasMeta("QOI")) {
202  std::shared_ptr<SamplingState> qoi = AnyCast(it->meta["QOI"]);
203  QOIs->Add(qoi);
204  }
205  }
206 
207  // increment the number of samples and break of we hit the max. number
208  if( ++sampNum>=numSamps ) { return it; }
209  }
210 
211  return newStates.back();
212 }
213 
214 bool SingleChainMCMC::ShouldSave(unsigned int const sampNum) const { return ((sampNum>=burnIn) && (scheduler->ShouldSave(sampNum))); }
215 
216 void SingleChainMCMC::SetState(std::vector<Eigen::VectorXd> const& x0) {
217  SetState(std::make_shared<SamplingState>(x0));
218 }
219 
220 void SingleChainMCMC::SetState(std::shared_ptr<SamplingState> const& x0) {
221  prevState = x0;
222  if(ShouldSave(0))
223  samples->Add(prevState);
224 }
225 
226 
227 std::shared_ptr<MarkovChain> SingleChainMCMC::GetSamples() const { return samples; }
228 
229 std::shared_ptr<MarkovChain> SingleChainMCMC::GetQOIs() const { return QOIs; }
A class for storing and working with the results of Markov chain Monte Carlo algorithms.
Definition: MarkovChain.h:20
bool ShouldSave(unsigned int const sampNum) const
virtual std::shared_ptr< MarkovChain > GetSamples() const
std::shared_ptr< SamplingState > SaveSamples(std::vector< std::shared_ptr< SamplingState > > const &newStates, std::shared_ptr< SamplingState > &lastSavedState, unsigned int &sampNum) const
SingleChainMCMC(boost::property_tree::ptree pt, std::shared_ptr< parcer::Communicator > const &comm, std::vector< std::shared_ptr< TransitionKernel > > const &kernelsIn)
std::shared_ptr< parcer::Communicator > comm
std::shared_ptr< SamplingState > prevState
std::shared_ptr< SaveSchedulerBase > schedulerQOI
std::shared_ptr< MarkovChain > samples
void Setup(boost::property_tree::ptree pt, std::vector< std::shared_ptr< TransitionKernel >> const &kernelsIn)
std::vector< std::shared_ptr< TransitionKernel > > kernels
std::shared_ptr< MarkovChain > Run(Args const &... args)
virtual void SetState(std::shared_ptr< SamplingState > const &x0)
Set the state of the MCMC chain.
std::shared_ptr< SaveSchedulerBase > scheduler
std::shared_ptr< MarkovChain > QOIs
void PrintStatus(std::string prefix) const
std::shared_ptr< MarkovChain > GetQOIs() const
std::shared_ptr< SamplingState > lastSavedState
static std::shared_ptr< TransitionKernel > Construct(boost::property_tree::ptree const &pt, std::shared_ptr< AbstractSamplingProblem > problem)
Static constructor for the transition kernel.
Class for easily casting boost::any's in assignment operations.
Definition: AnyHelpers.h:34
std::vector< std::string > Split(std::string str, char delim=',')
Split a string into parts based on a particular character delimiter. Also Strips whitespace from part...
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.h:3956