Fleet  0.0.9
Inference in the LOT
Random.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <fstream>
4 #include <random>
5 #include <functional>
6 
7 #include "Errors.h"
8 #include "Numerics.h"
9 #include "Rng.h"
10 
11 double uniform() {
16  std::uniform_real_distribution<double> d(0.0, 1.0);
17  return d(DefaultRNG);
18 }
19 
20 double uniform(const double a, const double b) {
21  std::uniform_real_distribution<double> d(a,b);
22  return d(DefaultRNG);
23 }
24 
25 bool flip(float p = 0.5) {
31  return uniform() < p;
32 }
33 
34 int rbinomial(const int n, const double p) {
35  std::binomial_distribution<int> bd(n,p);
36  return bd(DefaultRNG);
37 }
38 
39 double random_normal(double mu=0, double sd=1.0) {
40  std::normal_distribution<float> normal(0.0, 1.0);
41  return normal(DefaultRNG)*sd + mu;
42 }
43 
44 template<typename T>
45 T normal_lpdf(T x, T mu=0.0, T sd=1.0) {
54  //https://stackoverflow.com/questions/10847007/using-the-gaussian-probability-density-function-in-c
55  const T linv_sqrt_2pi = -0.5*log(2*pi*sd*sd);
56  const T z = (x-mu)/sd;
57  return linv_sqrt_2pi - z*z / 2.0;
58 }
59 
60 template<typename T>
61 T normal_cdf(T x, T mu, T sd) {
62  T z = (x-mu)/sd;
63  return std::erfc(-z/std::sqrt(2))/2;
64 }
65 
66 template<typename T>
67 T random_t(T nu) {
68  std::student_t_distribution<double> dist(nu);
69  return dist(DefaultRNG);
70 }
71 
72 template<typename T>
73 T t_lpdf(T x, T nu) {
74  return mylgamma((nu+1)/2) - log(nu*pi)/2 - mylgamma(nu/2) +
75  log(1+x*x/nu)*(-(nu+1)/2);
76 }
77 
78 
79 double random_cauchy() {
85  return tan(pi*(uniform()-0.5));
86 }
87 
88 
89 template<typename T>
90 T cauchy_lpdf(T x, T loc=0.0, T gamma=1.0) {
99  return -log(pi) - log(gamma) - log(1+((x-loc)/gamma)*((x-loc)/gamma));
100 }
101 
102 
103 template<typename T>
104 T laplace_lpdf(T x, T mu=0.0, T b=1.0) {
113  //https://stackoverflow.com/questions/10847007/using-the-gaussian-probability-density-function-in-c
114  return -log(2*b) - std::abs(x-mu)/b;
115 }
116 
117 
118 template<typename T>
119 T random_exponential(T l=1.0) {
127  return -log(uniform())/l;
128 }
129 
130 
131 template<typename T>
132 T random_laplace(T mu=0.0, T b=1.0) {
140  return mu + random_exponential(b) - random_exponential(b);
141 }
142 
143 
144 double geometric_lpdf(size_t k, double p) {
145  return log(p) + (k-1)*log(1-p);
146 }
147 
148 double random_gamma(double a, double b) {
149  std::gamma_distribution<double> g(a,b);
150  return g(DefaultRNG);
151 }
152 
153 template<typename t>
154 std::vector<t> random_multinomial(t a, size_t len) {
162  std::gamma_distribution<t> g(a, 1.0);
163  std::vector<t> out(len);
164  t total = 0.0;
165  for(size_t i =0;i<len;i++){
166  out[i] = g(DefaultRNG);
167  total += out[i];
168  }
169  for(size_t i=0;i<len;i++){
170  out[i] /= total;
171  }
172  return out;
173 }
174 
175 template<typename T>
176 T myrandom(T max) {
182  assert(max>0);
183  std::uniform_int_distribution<T> r(0, max-1);
184  return r(DefaultRNG);
185 }
186 
187 template<typename T>
188 T myrandom(T min, T max) {
196  std::uniform_int_distribution<T> r(min,max-1);
197  return r(DefaultRNG);
198 }
199 
200 std::vector<int> random_int_vector(int min, int max, size_t n) {
207  std::vector<int> out; out.reserve(n);
208  for(size_t i=0;i<n;i++) {
209  out.push_back(myrandom(min,max));
210  }
211  return out;
212 }
213 
214 
220 std::vector<bool> random_nonempty_subset(const size_t n, const double p) {
221  assert(n>0);
222 
223  std::vector<bool> myout(n, false);
224  for(size_t i=0;i<n;i++) {
225  myout[i] = flip(p);
226  }
227  myout[myrandom(n)] = true; // always ensure one is true
228 
229  return myout;
230 }
231 
232 
233 
234 
235 
236 
237 template<typename t, typename T>
238 double sample_z(const T& s, const std::function<double(const t&)>& f) {
246  double z = 0.0;
247  for(auto& x: s) {
248  auto fx = f(x);
249  if(not std::isnan(fx)) {
250  assert(fx >= 0.0 && "*** Cannot use sample/sample_z with negative probabilities. Did you mean to use sample_lp/sample_lp_z?");
251  z += f(x);
252  }
253  }
254  return z;
255 }
256 
257 template<typename t, typename T>
258 std::pair<t*,double> sample(const T& s, double z, const std::function<double(const t&)>& f = [](const t& v){return 1.0;}) {
259  // this takes a collection T of elements t, and a function f
260  // which assigns them each a probability, and samples from them according
261  // to the probabilities in f. The probability that is returned is only the probability
262  // of selecting that *element* (index), not the probability of selecting anything equal to it
263  // (i.e. we defaultly don't double-count equal options). For that, use p_sample_eq below
264  // here z is the normalizer, z = sum_x f(x)
265  assert(z > 0 && "*** Cannot call sample with zero normalizer -- is s empty?");
266  double r = z * uniform();
267  for(auto& x : s) {
268 
269  auto fx = f(x);
270  if(std::isnan(fx)) continue; // treat as zero prob
271  assert(fx >= 0.0);
272  r -= fx;
273  if(r <= 0.0)
274  return std::make_pair(const_cast<t*>(&x), log(fx)-log(z));
275  }
276 
277  throw YouShouldNotBeHereError("*** Should not get here in sampling");
278 }
279 
280 template<typename t, typename T>
281 std::pair<t*,double> sample(const T& s, const std::function<double(const t&)>& f = [](const t& v){return 1.0;}) {
282  // An interface to sample that computes the normalizer for you
283  return sample<t,T>(s, sample_z<t,T>(s,f), f);
284 }
285 
286 
287 template<typename t, typename T>
288 double sample_lp_z(const T& s, const std::function<double(const t&)>& f) {
294  double z = -infinity;
295  for(auto& x: s) {
296  auto fx = f(x);
297  if(not std::isnan(fx))
298  z = logplusexp(z,fx);
299  }
300  return z;
301 }
302 
303 template<typename t, typename T>
304 std::pair<t*,double> sample_lp(const T& s, double z, const std::function<double(const t&)>& f = [](const t& v){return 0.0;}) {
305  // Sample where f gives LOG probabilities
306  assert(z > -infinity && "*** Cannot call sample with zero (-infinity) normalizer -- is s empty?");
307  double r = z + log(uniform());
308  double tot = -infinity;
309  for(auto& x : s) {
310  auto fx = f(x);
311  if(std::isnan(fx)) continue; // treat as zero prob
312  tot = logplusexp(tot, fx);
313  if(tot > r) return std::make_pair(const_cast<t*>(&x), log(fx)-log(z));
314  }
315 
316  throw YouShouldNotBeHereError("*** Should not get here in sampling");
317 }
318 
319 template<typename t, typename T>
320 std::pair<t*,double> sample_lp(const T& s, const std::function<double(const t&)>& f = [](const t& v){return 0.0;}) {
321  // An interface to sample that computes the normalizer for you
322  return sample_lp<t,T>(s, sample_lp_z<t,T>(s,f), f);
323 }
324 
325 
326 
327 
328 
329 
330 std::pair<int,double> sample_int(unsigned int max, const std::function<double(const int)>& f = [](const int v){return 1.0;}) {
331  // special form for where the ints (e.g. indices) are what f takes
332  double z = 0.0;
333  for(size_t i=0;i<max;i++){
334  z += f(i);
335  }
336 
337  double r = z * uniform();
338 
339  for(size_t i=0;i<max;i++){
340  double fx = f(i);
341  if(std::isnan(fx)) continue; // treat as zero prob
342  assert(fx >= 0.0);
343  r -= fx;
344  if(r <= 0.0)
345  return std::make_pair(i, log(fx)-log(z));
346  }
347 
348  throw YouShouldNotBeHereError("*** Should not get here in sampling");
349 }
350 
351 
352 std::pair<int,double> sample_int_lp(unsigned int max, const std::function<double(const int)>& f = [](const int v){return 1.0;}) {
353  // special form for where the ints (e.g. indices) Are what f takes)
354  double z = -infinity;
355  for(size_t i=0;i<max;i++){
356  double fx = f(i);
357  if(std::isnan(fx)) continue; // treat as zero prob
358  z = logplusexp(z, fx);
359  }
360 
361  double r = z + log(uniform());
362 
363  double fz = -infinity;
364  for(size_t i=0;i<max;i++){
365  double fx = f(i);
366  if(std::isnan(fx)) continue; // treat as zero prob
367  //assert(fx <= 0.0); // we actually can have lp > 0 if we wanted...
368  fz = logplusexp(fz, fx);
369  if(r <= fz)
370  return std::make_pair(i, fx-z);
371  }
372 
373  throw YouShouldNotBeHereError("*** Should not get here in sampling");
374 }
375 
376 
377 template<typename t, typename T>
378 std::pair<size_t,double> arg_max(const T& s, const std::function<double(const t&)>& f) {
379  // Same interface as sample but choosing the max
380  double mx = -infinity;
381  size_t max_idx = 0;
382  size_t idx = 0;
383  for(auto& x : s) {
384  double fx = f(x);
385  if(fx > mx) {
386  mx = fx;
387  max_idx = idx;
388  }
389  idx++;
390  }
391  return std::make_pair(max_idx, mx);
392 }
393 
394 
395 std::pair<size_t,double> arg_max_int(unsigned int max, const std::function<double(const int)>& f) {
396  double mx = -infinity;
397  size_t max_idx=0;
398  for(size_t i=0;i<max;i++){
399  double fx = f(i);
400  if(std::isnan(fx)) continue; // treat as zero prob
401  if(fx > mx) {
402  max_idx = i;
403  mx = fx;
404  }
405  }
406  return std::make_pair(max_idx, mx);
407 }
408 
409 template<typename t, typename T>
410 std::pair<t*,double> max_of(const T& s, const std::function<double(const t&)>& f) {
411  // Same interface as sample but choosing the max
412  double mx = -infinity;
413  t* out = nullptr;
414  for(auto& x : s) {
415  double fx = f(x);
416  if(fx > mx) {
417  mx = fx;
418  out = const_cast<t*>(&x);
419  }
420  }
421  return std::make_pair(out, mx);
422 }
423 
424 template<typename t, typename T>
425 std::pair<t*,double> sample(const T& s, double(*f)(const t&)) {
426  std::function sf = f;
427  return sample<t,T>(s,sf);
428 }
429 
430 template<typename t, typename T>
431 double lp_sample_eq(const t& x, const T& s, std::function<double(const t&)>& f = [](const t& v){return 1.0;}) {
432  // the probability of sampling *anything* equal to x out of s (including double counts)
433 
434  double z = sample_z(s,f);
435  double px = 0.0; // find the probability of anything *equal* to x
436  for(const auto& y : s) {
437  if(y == x)
438  px += f(y);
439  }
440 
441  assert(px <= z);
442 
443  return log(px)-log(z);
444 }
445 
446 template<typename t, typename T>
447 double lp_sample_eq(const t& x, const T& s, double(*f)(const t&)) {
448  std::function sf = f;
449  return lp_sample_eq<t,T>(x,s,sf);
450 }
451 
452 template<typename t, typename T>
453 double lp_sample_one(const t& x, const T& s, std::function<double(const t&)>& f = [](const t& v){return 1.0;}) {
454  // probability of sampling just this one
455  // NOTE: does not check that x is in s!
456 
457  double z = sample_z(s,f);
458  return log(f(x))-log(z);
459 }
460 template<typename t, typename T>
461 double lp_sample_one(const t& x, const T& s, double(*f)(const t&)) {
462  std::function sf = f;
463  return lp_sample_one<t,T>(x,s,sf);
464 }
std::vector< bool > random_nonempty_subset(const size_t n, const double p)
Returns a random nonempty subset of n elements, as a vector<bool> of length n with trues for elements...
Definition: Random.h:220
T myrandom(T max)
Definition: Random.h:176
double lp_sample_one(const t &x, const T &s, std::function< double(const t &)> &f=[](const t &v){return 1.0;})
Definition: Random.h:453
T random_t(T nu)
Definition: Random.h:67
std::pair< size_t, double > arg_max(const T &s, const std::function< double(const t &)> &f)
Definition: Random.h:378
T t_lpdf(T x, T nu)
Definition: Random.h:73
std::pair< t *, double > sample(const T &s, double z, const std::function< double(const t &)> &f=[](const t &v){return 1.0;})
Definition: Random.h:258
double uniform()
Definition: Random.h:11
constexpr double pi
Definition: Numerics.h:22
std::pair< int, double > sample_int_lp(unsigned int max, const std::function< double(const int)> &f=[](const int v){return 1.0;})
Definition: Random.h:352
int rbinomial(const int n, const double p)
Definition: Random.h:34
double mylgamma(double v)
Definition: Numerics.h:216
double sample_lp_z(const T &s, const std::function< double(const t &)> &f)
Definition: Random.h:288
T laplace_lpdf(T x, T mu=0.0, T b=1.0)
Definition: Random.h:104
Rng DefaultRNG
std::pair< int, double > sample_int(unsigned int max, const std::function< double(const int)> &f=[](const int v){return 1.0;})
Definition: Random.h:330
double geometric_lpdf(size_t k, double p)
Definition: Random.h:144
Definition: Errors.h:18
double random_gamma(double a, double b)
Definition: Random.h:148
bool flip(float p=0.5)
Definition: Random.h:25
std::vector< int > random_int_vector(int min, int max, size_t n)
Definition: Random.h:200
T random_exponential(T l=1.0)
Definition: Random.h:119
std::vector< t > random_multinomial(t a, size_t len)
Definition: Random.h:154
T random_laplace(T mu=0.0, T b=1.0)
Definition: Random.h:132
double random_normal(double mu=0, double sd=1.0)
Definition: Random.h:39
double random_cauchy()
Definition: Random.h:79
constexpr double infinity
Definition: Numerics.h:20
T logplusexp(const T a, const T b)
Definition: Numerics.h:131
double lp_sample_eq(const t &x, const T &s, std::function< double(const t &)> &f=[](const t &v){return 1.0;})
Definition: Random.h:431
std::pair< t *, double > max_of(const T &s, const std::function< double(const t &)> &f)
Definition: Random.h:410
T normal_cdf(T x, T mu, T sd)
Definition: Random.h:61
std::pair< t *, double > sample_lp(const T &s, double z, const std::function< double(const t &)> &f=[](const t &v){return 0.0;})
Definition: Random.h:304
T cauchy_lpdf(T x, T loc=0.0, T gamma=1.0)
Definition: Random.h:90
std::pair< size_t, double > arg_max_int(unsigned int max, const std::function< double(const int)> &f)
Definition: Random.h:395
T normal_lpdf(T x, T mu=0.0, T sd=1.0)
Definition: Random.h:45
double sample_z(const T &s, const std::function< double(const t &)> &f)
Definition: Random.h:238