aboutsummaryrefslogtreecommitdiff
path: root/poissonier.h
blob: 95da15ec9114b1e5849c1c72fefb1aa75bb18e66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#ifndef POISSONIER_H
#define POISSONIER_H

#include <random>       /* for seed_seq */
#include <iostream>
#include <time.h>       /* for clock_gettime */
#include <vector>
#ifdef BOOST_CPD
#  include <boost/math/distributions/poisson.hpp>
#endif

static char const printable[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                 "abcdefghijklmnopqrstuvwxyz"
                 "0123456789._";

std::string base64(unsigned long int arg) {
  std::string str;
  for (;;) {
    str = printable[arg & 63] + str;
    arg >>= 6;
    if (! arg) break;
  }
  return str;
}

std::string randomstr(unsigned int const nn=15) {
  using namespace std;
// FIXME: ??? Could maybe use std::bitset here:
  random_device rd;
  string str;
  while (str.length() < nn) {
    unsigned int foo(rd());
    int nch = (sizeof(foo) * 8) / 6;
    for (int ii = 0; ii < nch; ii++) {
      str += printable[foo & 63];
      foo >>= 6;
    }
  }
  return str;
}

class poissonier {
public:
  std::mt19937 basegen;
  std::string graine;           // last seed fed to basegen

// constructor
  poissonier () {
    timespec time;
    clock_gettime(CLOCK_REALTIME, &time);
    graine = base64(time.tv_sec);
    graine += base64(time.tv_nsec);
    seed(graine);
  }
  double sample(double const lambda) {
// There is no way to change the intensity after the
// distro is constructed, so construct a new one each time:
    return std::poisson_distribution<>(lambda)(basegen);
  }
  void seed(std::string const seed) {
// Need a temporary variable here, because the seed() function
// modifies it:
    graine = seed;
    std::seed_seq seed1(seed.begin(), seed.end());
    basegen.seed(seed1);
  }
  std::string randomize() {
    graine = randomstr(15);
    seed(graine);
    return graine;
  }
  void check(double const rate) {
    using namespace std;
    cout << "Checking: " << rate
        << "  gives: " << sample(rate)
        << endl;
  }

// Note this is stateless. Static member function.
//
// Log of the probability mass distribution:
  static double lpmd(double const lambda, int const k){
    // https://en.wikipedia.org/wiki/Poisson_distribution#Definition
    if (lambda < 0) throw std::invalid_argument("negative Poisson intensity");
    if (lambda == 0) {
      if (k == 0) return 0;     // 100% probability
      return -INFINITY;         //   0% probability
    }
    return k * log(lambda) - lambda - lgamma(k + 1.0);
  }

// pmd = probability mass distribution
  inline static double pmd(double const lambda, int const k){
    return exp(lpmd(lambda, k));
  }

#ifdef BOOST_CPD
// not implemented
// not needed, and would require boost
// cpd = cumulative probability distribution
  static double cpd(double const lambda, int const k){
    boost::math::poisson_distribution<> pd(lambda);
    return boost::math::cpd(pd, k);
  }
#endif
};

#endif /* POISSONIER_H */