Pakman
ABCSMCController.cc
1 #include <string>
2 #include <vector>
3 #include <stdexcept>
4 #include <sstream>
5 #include <iostream>
6 #include <random>
7 
8 #include <assert.h>
9 
10 #include "spdlog/spdlog.h"
11 
12 #include "core/common.h"
13 #include "core/OutputStreamHandler.h"
14 #include "interface/protocols.h"
15 #include "interface/output.h"
16 #include "master/AbstractMaster.h"
17 
18 #include "smc_weight.h"
19 #include "sample_population.h"
20 
21 #include "ABCSMCController.h"
22 
23 // Constructor
25  m_epsilons(input_obj.epsilons),
26  m_parameter_names(input_obj.parameter_names),
27  m_population_size(input_obj.population_size),
28  m_simulator(input_obj.simulator),
29  m_prior_sampler(input_obj.prior_sampler),
30  m_prior_pdf(input_obj.prior_pdf),
31  m_perturber(input_obj.perturber),
32  m_perturbation_pdf(input_obj.perturbation_pdf),
33  m_generator(input_obj.seed),
34  m_distribution(0.0, 1.0),
35  m_prmtr_accepted_old(input_obj.population_size),
36  m_weights_old(input_obj.population_size)
37 {
38 }
39 
40 // Iterate function
42 {
43  // This function should never be called recursively
44  assert(!m_entered);
45  m_entered = true;
46 
47  // Display message if first iteration
48  if (m_first)
49  {
50  spdlog::info("Computing generation {}, epsilon = {}", m_t,
51  m_epsilons[m_t].str());
52  m_first = false;
53  }
54 
55  // If m_t is equal to the number of epsilons, something went wrong because
56  // the algorithm should have finished
57  assert(m_t < m_epsilons.size());
58 
59  // Check if there are any new accepted parameters
60  while (!m_p_master->finishedTasksEmpty()
61  && m_prmtr_accepted_new.size() < m_population_size)
62  {
63  // m_prior_pdf_pending should not be empty
64  assert(!m_prior_pdf_pending.empty());
65 
66  // Increment counter
67  m_number_simulated++;
68 
69  // Get reference to front finished task
70  TaskHandler& task = m_p_master->frontFinishedTask();
71 
72  // Check if error occured
73  if (!task.didErrorOccur())
74  {
75  // Check if parameter was accepted
77  {
78  // Declare raw parameter
79  std::string raw_parameter;
80 
81  // Get input string
82  std::stringstream input_sstrm(task.getInputString());
83 
84  // Discard epsilon
85  std::getline(input_sstrm, raw_parameter);
86 
87  // Read accepted parameter
88  std::getline(input_sstrm, raw_parameter);
89 
90  // Push accepted parameter
91  m_prmtr_accepted_new.push_back(std::move(raw_parameter));
92 
93  // Push prior_pdf of accepted parameter
94  m_prior_pdf_accepted.push_back(m_prior_pdf_pending.front());
95  }
96  }
97  // If error occurred, check if g_ignore_errors is set
98  else if (!g_ignore_errors)
99  {
100  std::runtime_error e("Task finished with error!");
101  throw e;
102  }
103 
104  // Pop finished task
105  m_p_master->popFinishedTask();
106 
107  // Pop prior_pdf of finished task
108  m_prior_pdf_pending.pop();
109  }
110 
111  // Iterate over parameters whose weights have not yet been computed
112  for (int i = m_weights_new.size(); i < m_prmtr_accepted_new.size(); i++)
113  m_weights_new.push_back(smc_weight(
114  m_perturbation_pdf,
115  m_prior_pdf_accepted[i],
116  m_t,
117  m_prmtr_accepted_old,
118  m_weights_old,
119  m_prmtr_accepted_new[i]));
120 
121  // If enough parameters have been accepted for this generation, check if we
122  // are in the last generation. If we are in the last generation, then
123  // print the accepted parameters and terminate Master. If we are not in
124  // the last generation, then swap the weights and populations
125  if (m_prmtr_accepted_new.size() == m_population_size)
126  {
127  // Print message
128  spdlog::info("Accepted/simulated: {}/{} ({:5.2f}%)",
129  m_population_size, m_number_simulated,
130  (100.0 * m_population_size / (double) m_number_simulated));
131  m_number_simulated = 0;
132 
133  // Increment generation counter
134  m_t++;
135 
136  // Check if we are in the last generation
137  if (m_t == m_epsilons.size())
138  {
139  // Print accepted parameters
140  write_parameters(OutputStreamHandler::instance()->getOutputStream(),
141  m_parameter_names, m_prmtr_accepted_new);
142 
143  // Terminate Master
144  m_p_master->terminate();
145  m_entered = false;
146  return;
147  }
148 
149  // Swap population and weights
150  std::swap(m_weights_old, m_weights_new);
151  std::swap(m_prmtr_accepted_old, m_prmtr_accepted_new);
152 
153  // Normalize and compute cumulative sum
154  m_weights_cumsum.resize(m_weights_old.size());
155  normalize(m_weights_old);
156  cumsum(m_weights_old, m_weights_cumsum);
157 
158  // Clear m_weights_new, m_prmtr_accepted_new and m_prior_pdf_accepted
159  m_weights_new.clear();
160  m_prmtr_accepted_new.clear();
161  m_prior_pdf_accepted.clear();
162 
163  // Flush Master
164  m_p_master->flush();
165  m_entered = false;
166 
167  // Clear m_prior_pdf_pending
168  while (!m_prior_pdf_pending.empty())
169  m_prior_pdf_pending.pop();
170 
171  // Print message
172  spdlog::info("Computing generation {}, epsilon = {}", m_t,
173  m_epsilons[m_t].str());
174  return;
175  }
176 
177  // There is still work to be done, so make sure there are as many tasks
178  // queued as there are Managers
179  while (m_p_master->needMorePendingTasks())
180  m_p_master->pushPendingTask(
182  m_epsilons[m_t].str(), sampleParameter()));
183 
184  m_entered = false;
185 }
186 
188 {
189  return m_simulator;
190 }
191 
192 Parameter ABCSMCController::sampleParameter()
193 {
194  // If in generation 0
195  if (m_t == 0)
196  {
197  // Push dummy prior_pdf to m_prior_pdf_pending
198  m_prior_pdf_pending.push(0.0);
199 
200  // Sample from prior
201  return sample_from_prior(m_prior_sampler);
202  }
203 
204  // Else, sample from previous population and perturb until the prior pdf is
205  // nonzero
206  Parameter sampled_parameter;
207  double sampled_prior_pdf = 0.0;
208  do
209  {
210  // Sample parameter population
211  int idx = sample_population(m_weights_cumsum, m_distribution,
212  m_generator);
213  Parameter source_parameter = m_prmtr_accepted_old[idx];
214 
215  // Perturb parameter
216  sampled_parameter = perturb_parameter(m_perturber, m_t,
217  source_parameter);
218 
219  // Calculate prior_pdf
220  sampled_prior_pdf = get_prior_pdf(m_prior_pdf, sampled_parameter);
221  } while (sampled_prior_pdf == 0.0);
222 
223  // Push sampled_prior_pdf to m_prior_pdf_pending
224  m_prior_pdf_pending.push(sampled_prior_pdf);
225 
226  return sampled_parameter;
227 }
virtual Command getSimulator() const override
std::string format_simulator_input(const Epsilon &epsilon, const Parameter &parameter)
Definition: protocols.cc:11
std::string getOutputString() const
Definition: TaskHandler.cc:53
ABCSMCController(const Input &input_obj)
Parameter sample_from_prior(const Command &prior_sampler)
Definition: protocols.cc:294
virtual void iterate() override
Parameter perturb_parameter(const Command &perturber, int t, Parameter source_parameter)
Definition: protocols.cc:301
static OutputStreamHandler * instance()
void write_parameters(std::ostream &ostrm, const std::vector< ParameterName > &parameter_names, const std::vector< Parameter > &parameters)
Definition: output.cc:11
std::string getInputString() const
Definition: TaskHandler.cc:46
double get_prior_pdf(const Command &prior_pdf, Parameter parameter)
Definition: protocols.cc:311
bool didErrorOccur() const
Definition: TaskHandler.cc:37
std::shared_ptr< AbstractMaster > m_p_master
bool g_ignore_errors
Definition: main.cc:28
bool parse_simulator_output(const std::string &simulator_output)
Definition: protocols.cc:24