Fleet  0.0.9
Inference in the LOT
Bayesable.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <utility>
4 #include <iomanip>
5 #include <signal.h>
6 
7 #include "FleetArgs.h"
8 #include "Errors.h"
9 #include "Datum.h"
10 #include "IO.h"
12 #include "Miscellaneous.h"
14 
15 // if we define this, then we won't use breakouts
16 //#define NO_BREAKOUT 1
17 
18 extern std::atomic<bool> CTRL_C;
19 
30 //cache::lru_cache<size_t, std::tuple<double,double,double>> posterior_cache(10);
31 
32 template<typename _datum_t, typename _data_t=std::vector<_datum_t>>
33 class Bayesable {
34 public:
35 
36  // We'll define a vector of pairs of inputs and outputs
37  // this may be used externally to define what data is
38  typedef _datum_t datum_t;
39  typedef _data_t data_t;
40 
41  // log values for all
42  double prior;
43  double likelihood;
44  double posterior; // Posterior always stores at temperature 1
45 
46  // some born info/statistics
47  uintmax_t born; // what count were you born at?
48  size_t born_chain_idx; // if we came from a ChainPool, what chain index were we born on?
49 
50  Bayesable() : prior(NaN), likelihood(NaN), posterior(NaN), born(++FleetStatistics::hypothesis_births), born_chain_idx(0) { }
51 
52  // Stuff for subclasses to implement:
53  virtual size_t hash() const=0;
54  virtual std::string string(std::string prefix="") const = 0;
55  virtual double compute_prior() = 0;
56 
61  virtual double compute_single_likelihood(const datum_t& datum) {
62  throw NotImplementedError();
63  }
64 
65  virtual void clear_bayes() {
70  // necessary for inserting into big collections not by prior
71  prior = 0.0;
72  likelihood = 0.0;
73  posterior = 0.0;
74  }
75 
83  virtual double compute_likelihood(const data_t& data, const double breakout=-infinity) {
84 
85  // include this in case a subclass overrides to make it non-iterable -- then it must define its own likelihood
86  if constexpr (is_iterable_v<data_t>) {
87  // defaultly a sum over datums in data (e.g. assuming independence)
88  likelihood = 0.0;
89  for(const auto& d : data) {
90 
91 
92  auto sll = compute_single_likelihood(d);
93 
94  likelihood += sll;
95 
96  if(likelihood == -infinity or std::isnan(likelihood)) break; // no need to continue
97 
98  // This is a breakout in case our ll is too low
100  assert((sll <= 0 or breakout==-infinity) && "*** Cannot use breakout if likelihoods are positive");
101  if(likelihood < breakout) {
102  return likelihood = -infinity; // should not matter what value, but let's make it -infinity
103  }
104  }
105 
106  // add a break here
107  if(CTRL_C) break;
108  }
109 
110  return likelihood;
111  }
112  else {
113  // should never execute this because it must be defined
114  throw NotImplementedError("*** If you use a non-iterable data_t, then you must define compute_likelihood on your own.");
115  }
116  }
117 
118 
119  virtual double compute_tempered_likelihood(const data_t& data, int ladder_rank, const double breakout=-infinity) {
120  return compute_likelihood(data,breakout);
121  }
122 
140  virtual double compute_posterior(const data_t& data, const std::pair<double,double> breakoutpair=std::make_pair(-infinity,1.0)) {
141 
142  ++FleetStatistics::posterior_calls; // just keep track of how many calls
143 
144  // Always compute a prior
145  prior = compute_prior();
146 
147  // if the prior is -inf, then we don't have to compute likelihood
148  if(prior == -infinity) {
149  likelihood = NaN;
150  posterior = -infinity;
151  }
152  else {
153  // NOTE: here we *subtract* off prior so the breakout in compute_likelihood is ONLY for the likelihood
154  auto [b,t] = breakoutpair; // see MCMCChain.h to understand this and hte next line
155  likelihood = compute_likelihood(data, (b-prior)*t);
156  posterior = prior + likelihood;
157  }
158 
159  return posterior;
160  }
161 
162  virtual double at_temperature(double t) const {
169  // temperature here applies to the likelihood only
170  return prior + likelihood/t;
171  }
172 
173  // Defaultly we search by posterior
174  auto operator<=>(const Bayesable<datum_t,data_t>& other) const {
183  if(posterior != other.posterior) {
184  return fp_ordering(posterior, other.posterior);
185  }
186  else if(prior != other.prior) {
187  return fp_ordering(prior,other.prior);
188  }
189  else {
190  // we could be equal, but we only want to say that if we are.
191  // otherwise this is decided by the hash function
192  // so we must ensure that the hash function is only equal for equal values
193  return this->hash() <=> other.hash();
194  }
195  }
196 
197  virtual void show(std::string prefix="") {
202  if(prefix != "") {
203  print(prefix, this->posterior, this->prior, this->likelihood, QQ(this->string()));
204  }
205  else {
206  print(this->posterior, this->prior, this->likelihood, QQ(this->string()));
207  }
208  }
209 };
210 
211 
212 
213 template<typename _datum_t, typename _data_t>
214 std::ostream& operator<<(std::ostream& o, Bayesable<_datum_t,_data_t>& x) {
215  o << x.string();
216  return o;
217 }
218 
219 
220 // little helper functions
221 template<typename HYP>
222 std::function get_posterior = [](const HYP& h) {return h.posterior; };
223 
224 template<typename HYP>
225 std::function get_prior = [](const HYP& h) {return h.prior; };
226 
227 template<typename HYP>
228 std::function get_likelihood = [](const HYP& h) {return h.likelihood; };
229 
230 
231 // Interface for std::fmt
232 //#include "fmt/format.h"
233 //
234 //template<typename _datum_t, typename _data_t>
235 //struct fmt::formatter<Bayesable<_datum_t,_data_t>&> {
236 // constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
237 //
238 // template <typename FormatContext>
239 // auto format(const Bayesable<_datum_t,_data_t>& h, FormatContext& ctx) {
240 // return format_to(ctx.out(), "{}", h.string());
241 // }
242 //};
virtual size_t hash() const =0
std::string QQ(const std::string &x)
Definition: Strings.h:190
virtual double compute_tempered_likelihood(const data_t &data, int ladder_rank, const double breakout=-infinity)
Definition: Bayesable.h:119
double likelihood
Definition: Bayesable.h:43
virtual double compute_posterior(const data_t &data, const std::pair< double, double > breakoutpair=std::make_pair(-infinity, 1.0))
Compute the posterior, by calling prior and likelihood. This includes only a little bit of fanciness...
Definition: Bayesable.h:140
virtual double compute_single_likelihood(const datum_t &datum)
Compute the likelihood of a single data point.
Definition: Bayesable.h:61
A datum is the default data point for likelihoods, consisting of an input and output type...
virtual double at_temperature(double t) const
Definition: Bayesable.h:162
Definition: FleetStatistics.h:5
virtual double compute_prior()=0
double prior
Definition: Bayesable.h:42
Mostly for error checking.
virtual void clear_bayes()
Definition: Bayesable.h:65
double posterior
Definition: Bayesable.h:44
uintmax_t born
Definition: Bayesable.h:47
void print(FIRST f, ARGS... args)
Lock output_lock and print to std:cout.
Definition: IO.h:53
constexpr double infinity
Definition: Numerics.h:20
std::atomic< uintmax_t > posterior_calls(0)
virtual void show(std::string prefix="")
Definition: Bayesable.h:197
Definition: Bayesable.h:33
bool LIKELIHOOD_BREAKOUT
Definition: FleetArgs.h:61
std::function get_likelihood
Definition: Bayesable.h:228
size_t born_chain_idx
Definition: Bayesable.h:48
_datum_t datum_t
Definition: Bayesable.h:38
virtual std::string string(std::string prefix="") const =0
std::atomic< uintmax_t > hypothesis_births(0)
Definition: Errors.h:7
constexpr double NaN
Definition: Numerics.h:21
std::function get_prior
Definition: Bayesable.h:225
_data_t data_t
Definition: Bayesable.h:39
std::atomic< bool > CTRL_C
virtual double compute_likelihood(const data_t &data, const double breakout=-infinity)
Compute the likelihood of a collection of data, by calling compute_single_likelihood on each...
Definition: Bayesable.h:83
std::function get_posterior
Definition: Bayesable.h:222
Bayesable()
Definition: Bayesable.h:50