StochTree 0.5.0.9000
Loading...
Searching...
No Matches
distributions.h
1#ifndef STOCHTREE_DISTRIBUTIONS_H
2#define STOCHTREE_DISTRIBUTIONS_H
3#include <numeric>
4#include <random>
5#include <boost/math/special_functions/erf.hpp>
14namespace StochTree {
15
19inline double norm_cdf(double x) {
20 return 0.5 * boost::math::erfc(-x / std::sqrt(2.0));
21}
22
26inline double norm_inv_cdf(double p) {
27 return -std::sqrt(2.0) * boost::math::erfc_inv(2.0 * p);
28}
29
31static constexpr double Phi_0 = 0.5;
32
37inline double standard_uniform_draw_53bit(std::mt19937& gen) {
38 int32_t a = gen() >> 5;
39 int32_t b = gen() >> 6;
40 return (a * 67108864.0 + b) / 9007199254740992.0;
41}
42
46inline double standard_uniform_draw_32bit(std::mt19937& gen) {
47 constexpr double inv_divisor = 1.0 / static_cast<double>(std::mt19937::max());
48 return (gen() * inv_divisor);
49}
50
57 public:
59 has_cached_value_ = false;
60 cached_value_ = 0.0;
61 }
62
63 inline double operator()(std::mt19937& gen) {
64 if (has_cached_value_) {
65 has_cached_value_ = false;
66 return cached_value_;
67 } else {
68 double u, v, r, s;
69 do {
70 u = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
71 v = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
72 s = u * u + v * v;
73 } while (s >= 1.0 || s == 0.0);
74 r = std::sqrt(-2.0 * std::log(s) / s);
75 has_cached_value_ = true;
76 cached_value_ = v * r;
77 return u * r;
78 }
79 }
80
81 private:
82 bool has_cached_value_;
83 double cached_value_;
84};
85
94inline double sample_standard_normal(double mean, double sd, std::mt19937& gen) {
95 double u, v, r, s;
96 do {
97 u = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
98 v = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
99 s = u * u + v * v;
100 } while (s >= 1.0 || s == 0.0);
101 r = std::sqrt(-2.0 * std::log(s) / s);
102 return u * r * sd + mean;
103};
104
109 public:
110 gamma_sampler() {
111 has_cached_normal_value_ = false;
112 cached_normal_value_ = 0.0;
113 }
114
115 inline double operator()(std::mt19937& gen, double shape, double scale) {
116 if (shape == 1.0) {
117 return -std::log(standard_uniform_draw_53bit(gen)) * scale;
118 } else if (shape < 1.0) {
119 // Modified Ahrens-Dieter used by numpy:
120 // https://github.com/numpy/numpy/blob/main/numpy/random/src/distributions/distributions.c
121 while (true) {
124 double v = -std::log(v0);
125 if (u <= 1.0 - shape) {
126 double x = std::pow(u, 1.0 / shape);
127 if (x <= v) {
128 return x * scale;
129 }
130 } else {
131 double y = -std::log((1 - u) / shape);
132 double x = std::pow(1.0 - shape + shape * y, 1.0 / shape);
133 if (x <= v + y) {
134 return x * scale;
135 }
136 }
137 }
138 } else if (shape > 1.0) {
139 // Marsaglia-Tsang from numpy
140 double b = shape - 1.0 / 3.0;
141 double c = 1.0 / std::sqrt(9.0 * b);
142 while (true) {
143 double x, v;
144 do {
145 x = normal_draw(gen);
146 v = 1.0 + c * x;
147 } while (v <= 0.0);
148 v = v * v * v;
150 if (u < 1.0 - 0.0331 * (x * x) * (x * x)) {
151 return b * v * scale;
152 }
153 if (std::log(u) < 0.5 * x * x + b * (1.0 - v + std::log(v))) {
154 return b * v * scale;
155 }
156 }
157 } else {
158 return 0.0;
159 }
160 }
161
162 inline double normal_draw(std::mt19937& gen) {
163 if (has_cached_normal_value_) {
164 has_cached_normal_value_ = false;
165 return cached_normal_value_;
166 } else {
167 double u, v, r, s;
168 do {
169 u = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
170 v = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
171 s = u * u + v * v;
172 } while (s >= 1.0 || s == 0.0);
173 r = std::sqrt(-2.0 * std::log(s) / s);
174 has_cached_normal_value_ = true;
175 cached_normal_value_ = v * r;
176 return u * r;
177 }
178 }
179
180 private:
181 bool has_cached_normal_value_;
182 double cached_normal_value_;
183};
184
193inline double sample_gamma(std::mt19937& gen, double shape, double scale) {
194 if (shape == 1.0) {
195 return -std::log(standard_uniform_draw_53bit(gen)) * scale;
196 } else if (shape < 1.0) {
197 // Modified Ahrens-Dieter used by numpy:
198 // https://github.com/numpy/numpy/blob/main/numpy/random/src/distributions/distributions.c
199 while (true) {
202 double v = -std::log(v0);
203 if (u <= 1.0 - shape) {
204 double x = std::pow(u, 1.0 / shape);
205 if (x <= v) {
206 return x * scale;
207 }
208 } else {
209 double y = -std::log((1 - u) / shape);
210 double x = std::pow(1.0 - shape + shape * y, 1.0 / shape);
211 if (x <= v + y) {
212 return x * scale;
213 }
214 }
215 }
216 } else if (shape > 1.0) {
217 // Marsaglia-Tsang from numpy
218 double b = shape - 1.0 / 3.0;
219 double c = 1.0 / std::sqrt(9.0 * b);
220 while (true) {
221 double x, v;
222 do {
223 // Marsaglia's polar method for standard normal
224 double u1, u2, s;
225 do {
226 u1 = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
227 u2 = standard_uniform_draw_53bit(gen) * 2.0 - 1.0;
228 s = u1 * u1 + u2 * u2;
229 } while (s >= 1.0 || s == 0.0);
230 x = u1 * std::sqrt(-2.0 * std::log(s) / s);
231 v = 1.0 + c * x;
232 } while (v <= 0.0);
233 v = v * v * v;
235 if (u < 1.0 - 0.0331 * (x * x) * (x * x)) {
236 return b * v * scale;
237 }
238 if (std::log(u) < 0.5 * x * x + b * (1.0 - v + std::log(v))) {
239 return b * v * scale;
240 }
241 }
242 } else {
243 return 0.0;
244 }
245}
246
254 public:
255 template <typename Iterator>
257 n_ = std::distance(first, last);
258 probability_.resize(n_);
259 alias_.resize(n_);
260
261 // Compute probability normalizing factor
262 double sum = 0.0;
263 for (auto it = first; it != last; ++it) {
264 sum += *it;
265 }
266
267 // Build alias table using Walker's algorithm
268 std::vector<double> p(n_);
269 std::vector<int> below_average, above_average;
270
271 for (int i = 0; i < n_; ++i) {
272 p[i] = (*(first + i)) * n_ / sum;
273 if (p[i] < 1.0) {
274 below_average.push_back(i);
275 } else {
276 above_average.push_back(i);
277 }
278 }
279
280 while (!below_average.empty() && !above_average.empty()) {
281 int j = below_average.back();
282 below_average.pop_back();
283 int i = above_average.back();
284 above_average.pop_back();
285
286 probability_[j] = p[j];
287 alias_[j] = i;
288 p[i] = (p[i] + p[j]) - 1.0;
289
290 if (p[i] < 1.0) {
291 below_average.push_back(i);
292 } else {
293 above_average.push_back(i);
294 }
295 }
296
297 while (!above_average.empty()) {
298 probability_[above_average.back()] = 1.0;
299 above_average.pop_back();
300 }
301
302 while (!below_average.empty()) {
303 probability_[below_average.back()] = 1.0;
304 below_average.pop_back();
305 }
306 }
307
308 int operator()(std::mt19937& gen) {
310 int i = static_cast<int>(u * n_);
311 double y = u * n_ - i;
312 return (y < probability_[i]) ? i : alias_[i];
313 }
314
315 private:
316 std::vector<double> probability_;
317 std::vector<int> alias_;
318 int n_;
319};
320
321inline int sample_discrete_stateless(std::mt19937& gen, std::vector<double>& weights) {
322 double sum_weight = std::accumulate(weights.begin(), weights.end(), 0.0);
324 double running_total_weight = 0.0;
325 for (int i = 0; i < weights.size(); ++i) {
327 if (running_total_weight > u) {
328 return i;
329 }
330 }
331 return weights.size() - 1;
332}
333
334inline int sample_discrete_stateless(std::mt19937& gen, std::vector<double>& weights, double sum_weights) {
336 double running_total_weight = 0.0;
337 for (int i = 0; i < weights.size(); ++i) {
339 if (running_total_weight > u) {
340 return i;
341 }
342 }
343 return weights.size() - 1;
344}
345
349inline double sample_std_truncnorm_upper(std::mt19937& gen) {
352}
353
357inline double sample_std_truncnorm_lower(std::mt19937& gen) {
360}
361
362} // namespace StochTree
363
364#endif // STOCHTREE_DISTRIBUTIONS_H
Definition distributions.h:108
Definition distributions.h:56
Definition distributions.h:253
static void GFRSampleOneIter(TreeEnsemble &active_forest, ForestTracker &tracker, ForestContainer &forests, LeafModel &leaf_model, ForestDataset &dataset, ColumnVector &residual, TreePrior &tree_prior, std::mt19937 &gen, std::vector< double > &variable_weights, std::vector< int > &sweep_update_indices, double global_variance, std::vector< FeatureType > &feature_types, int cutpoint_grid_size, bool keep_forest, bool pre_initialized, bool backfitting, int num_features_subsample, int num_threads, LeafSuffStatConstructorArgs &... leaf_suff_stat_args)
Definition tree_sampler.h:816
A collection of random number generation utilities.
Definition bart.h:15
double norm_cdf(double x)
Definition distributions.h:19
double sample_standard_normal(double mean, double sd, std::mt19937 &gen)
Definition distributions.h:94
double sample_gamma(std::mt19937 &gen, double shape, double scale)
Definition distributions.h:193
double standard_uniform_draw_53bit(std::mt19937 &gen)
Definition distributions.h:37
double standard_uniform_draw_32bit(std::mt19937 &gen)
Definition distributions.h:46
static constexpr double Phi_0
Definition distributions.h:31
double norm_inv_cdf(double p)
Definition distributions.h:26
double sample_std_truncnorm_lower(std::mt19937 &gen)
Definition distributions.h:357
double sample_std_truncnorm_upper(std::mt19937 &gen)
Definition distributions.h:349