1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.sampling.distribution;
18
19 import org.apache.commons.rng.RestorableUniformRandomProvider;
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.apache.commons.rng.sampling.RandomAssert;
22 import org.apache.commons.rng.simple.RandomSource;
23 import org.junit.jupiter.api.Assertions;
24 import org.junit.jupiter.api.Test;
25
26
27
28
29
30
31 class PoissonSamplerCacheTest {
32
33
34
35
36 private final int minRange = (int) Math.floor(PoissonSampler.PIVOT - 2);
37
38 private final int maxRange = (int) Math.floor(PoissonSampler.PIVOT + 6);
39
40 private final int midRange = (minRange + maxRange) / 2;
41
42
43
44
45
46 @Test
47 void testMinimumCachedMean() {
48 Assertions.assertEquals(PoissonSampler.PIVOT, PoissonSamplerCache.getMinimumCachedMean());
49 }
50
51
52
53
54
55
56
57
58 @Test
59 void testConstructorWithNoCache() {
60 final double min = 0;
61 final double max = PoissonSampler.PIVOT - 2;
62 final PoissonSamplerCache cache = createPoissonSamplerCache(min, max);
63 Assertions.assertFalse(cache.isValidRange());
64 Assertions.assertEquals(0, cache.getMinMean());
65 Assertions.assertEquals(0, cache.getMaxMean());
66 }
67
68
69
70
71
72
73 @Test
74 void testConstructorWhenMaxEqualsMin() {
75 final double min = PoissonSampler.PIVOT + 2;
76 final double max = min;
77 final PoissonSamplerCache cache = createPoissonSamplerCache(min, max);
78 Assertions.assertTrue(cache.isValidRange());
79 Assertions.assertEquals(min, cache.getMinMean());
80 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
81 cache.getMaxMean());
82 }
83
84
85
86
87
88
89 @Test
90 void testConstructorWhenMaxAboveMin() {
91 final double min = PoissonSampler.PIVOT + 2;
92 final double max = min + 10;
93 final PoissonSamplerCache cache = createPoissonSamplerCache(min, max);
94 Assertions.assertTrue(cache.isValidRange());
95 Assertions.assertEquals(min, cache.getMinMean());
96 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
97 cache.getMaxMean());
98 }
99
100
101
102
103 @Test
104 void testConstructorThrowsWhenMaxIsLessThanMin() {
105 final double min = PoissonSampler.PIVOT;
106 final double max = Math.nextDown(min);
107 Assertions.assertThrows(IllegalArgumentException.class,
108 () -> createPoissonSamplerCache(min, max));
109 }
110
111
112
113
114
115 @Test
116 void testConstructorWhenMinBelow0() {
117 final double min = -1;
118 final double max = PoissonSampler.PIVOT + 2;
119 final PoissonSamplerCache cache = createPoissonSamplerCache(min, max);
120 Assertions.assertTrue(cache.isValidRange());
121 Assertions.assertEquals(PoissonSampler.PIVOT, cache.getMinMean());
122 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
123 cache.getMaxMean());
124 }
125
126
127
128
129
130 @Test
131 void testConstructorWhenMaxBelow0() {
132 final double min = -10;
133 final double max = -1;
134 final PoissonSamplerCache cache = createPoissonSamplerCache(min, max);
135 Assertions.assertFalse(cache.isValidRange());
136 Assertions.assertEquals(0, cache.getMinMean());
137 Assertions.assertEquals(0, cache.getMaxMean());
138 }
139
140
141
142
143
144
145 @Test
146 void testWithRangeConstructorWithNoCache() {
147 final double min = 0;
148 final double max = PoissonSampler.PIVOT - 2;
149 final PoissonSamplerCache cache = createPoissonSamplerCache().withRange(min, max);
150 Assertions.assertFalse(cache.isValidRange());
151 Assertions.assertEquals(0, cache.getMinMean());
152 Assertions.assertEquals(0, cache.getMaxMean());
153 }
154
155
156
157
158
159
160 @Test
161 void testWithRangeConstructorWhenMaxEqualsMin() {
162 final double min = PoissonSampler.PIVOT + 2;
163 final double max = min;
164 final PoissonSamplerCache cache = createPoissonSamplerCache().withRange(min, max);
165 Assertions.assertTrue(cache.isValidRange());
166 Assertions.assertEquals(min, cache.getMinMean());
167 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
168 cache.getMaxMean());
169 }
170
171
172
173
174
175
176 @Test
177 void testWithRangeConstructorWhenMaxAboveMin() {
178 final double min = PoissonSampler.PIVOT + 2;
179 final double max = min + 10;
180 final PoissonSamplerCache cache = createPoissonSamplerCache().withRange(min, max);
181 Assertions.assertTrue(cache.isValidRange());
182 Assertions.assertEquals(min, cache.getMinMean());
183 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
184 cache.getMaxMean());
185 }
186
187
188
189
190 @Test
191 void testWithRangeConstructorThrowsWhenMaxIsLessThanMin() {
192 final double min = PoissonSampler.PIVOT;
193 final double max = Math.nextDown(min);
194 final PoissonSamplerCache cache = createPoissonSamplerCache();
195 Assertions.assertThrows(IllegalArgumentException.class,
196 () -> cache.withRange(min, max));
197 }
198
199
200
201
202
203 @Test
204 void testWithRangeConstructorWhenMinBelow0() {
205 final double min = -1;
206 final double max = PoissonSampler.PIVOT + 2;
207 final PoissonSamplerCache cache = createPoissonSamplerCache().withRange(min, max);
208 Assertions.assertTrue(cache.isValidRange());
209 Assertions.assertEquals(PoissonSampler.PIVOT, cache.getMinMean());
210 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
211 cache.getMaxMean());
212 }
213
214
215
216
217 @Test
218 void testWithRangeConstructorWhenCacheHasNoCapcity() {
219 final double min = PoissonSampler.PIVOT + 2;
220 final double max = min + 10;
221 final PoissonSamplerCache cache = createPoissonSamplerCache(0, 0).withRange(min, max);
222 Assertions.assertTrue(cache.isValidRange());
223 Assertions.assertEquals(min, cache.getMinMean());
224 Assertions.assertEquals(Math.nextDown(Math.floor(max) + 1),
225 cache.getMaxMean());
226 }
227
228
229
230
231
232 @Test
233 void testWithinRange() {
234 final double min = PoissonSampler.PIVOT + 10;
235 final double max = PoissonSampler.PIVOT + 20;
236 final PoissonSamplerCache cache = createPoissonSamplerCache(min, max);
237
238 Assertions.assertTrue(cache.withinRange(PoissonSampler.PIVOT - 1));
239 Assertions.assertFalse(cache.withinRange(min - 1));
240 Assertions.assertTrue(cache.withinRange(min));
241 Assertions.assertTrue(cache.withinRange(max));
242 Assertions.assertFalse(cache.withinRange(max + 10));
243 }
244
245
246
247
248
249
250
251
252 @Test
253 void testCreateSharedStateSamplerThrowsWithZeroMean() {
254 final UniformRandomProvider rng = RandomAssert.seededRNG();
255 final PoissonSamplerCache cache = createPoissonSamplerCache();
256 Assertions.assertThrows(IllegalArgumentException.class,
257 () -> cache.createSharedStateSampler(rng, 0));
258 }
259
260
261
262
263 @Test
264 void testCreateSharedStateSamplerThrowsWithNonIntegerMean() {
265 final UniformRandomProvider rng = RandomAssert.seededRNG();
266 final PoissonSamplerCache cache = createPoissonSamplerCache();
267 final double mean = Integer.MAX_VALUE + 1.0;
268 Assertions.assertThrows(IllegalArgumentException.class,
269 () -> cache.createSharedStateSampler(rng, mean));
270 }
271
272
273
274
275
276
277
278 @Test
279 void testCanComputeSameSamplesAsPoissonSamplerWithFullRangeCache() {
280 checkComputeSameSamplesAsPoissonSampler(minRange,
281 maxRange);
282 }
283
284
285
286
287
288 @Test
289 void testCanComputeSameSamplesAsPoissonSamplerWithNoCache() {
290 checkComputeSameSamplesAsPoissonSampler(0,
291 minRange - 2);
292 }
293
294
295
296
297
298 @Test
299 void testCanComputeSameSamplesAsPoissonSamplerWithPartialCacheCoveringLowerRange() {
300 checkComputeSameSamplesAsPoissonSampler(minRange,
301 midRange);
302 }
303
304
305
306
307
308 @Test
309 void testCanComputeSameSamplesAsPoissonSamplerWithPartialCacheCoveringUpperRange() {
310 checkComputeSameSamplesAsPoissonSampler(midRange,
311 maxRange);
312 }
313
314
315
316
317
318 @Test
319 void testCanComputeSameSamplesAsPoissonSamplerWithCacheAboveTheUpperRange() {
320 checkComputeSameSamplesAsPoissonSampler(maxRange + 10,
321 maxRange + 20);
322 }
323
324
325
326
327
328
329
330
331 private void checkComputeSameSamplesAsPoissonSampler(int minMean,
332 int maxMean) {
333
334 final RandomSource source = RandomSource.SPLIT_MIX_64;
335 final long seed = RandomSource.createLong();
336 final RestorableUniformRandomProvider rng1 = source.create(seed);
337 final RestorableUniformRandomProvider rng2 = source.create(seed);
338
339
340 final PoissonSamplerCache cache =
341 createPoissonSamplerCache(minMean, maxMean);
342
343
344 for (int i = minRange; i <= maxRange; i++) {
345
346 testPoissonSamples(rng1, rng2, cache, i);
347
348 testPoissonSamples(rng1, rng2, cache, i + 0.5);
349 }
350 }
351
352
353
354
355
356
357
358
359 private static PoissonSamplerCache createPoissonSamplerCache(double minMean,
360 double maxMean) {
361 return new PoissonSamplerCache(minMean, maxMean);
362 }
363
364
365
366
367
368
369 private static PoissonSamplerCache createPoissonSamplerCache() {
370 return new PoissonSamplerCache(PoissonSampler.PIVOT,
371 PoissonSampler.PIVOT + 10);
372 }
373
374
375
376
377
378
379
380
381
382
383
384 private static void testPoissonSamples(
385 final RestorableUniformRandomProvider rng1,
386 final RestorableUniformRandomProvider rng2,
387 PoissonSamplerCache cache,
388 double mean) {
389 final DiscreteSampler s1 = PoissonSampler.of(rng1, mean);
390 final DiscreteSampler s2 = cache.createSharedStateSampler(rng2, mean);
391 for (int j = 0; j < 10; j++) {
392 Assertions.assertEquals(s1.sample(), s2.sample());
393 }
394 }
395
396
397
398
399
400 @Test
401 void testCanComputeSameSamplesAsPoissonSamplerReusingCacheEntireRange() {
402 checkComputeSameSamplesAsPoissonSamplerReusingCache(midRange,
403 maxRange,
404 midRange,
405 maxRange);
406 }
407
408
409
410
411
412 @Test
413 void testCanComputeSameSamplesAsPoissonSamplerReusingCacheNoRange() {
414 checkComputeSameSamplesAsPoissonSamplerReusingCache(midRange,
415 maxRange,
416 maxRange + 10,
417 maxRange + 20);
418 }
419
420
421
422
423
424 @Test
425 void testCanComputeSameSamplesAsPoissonSamplerReusingCacheLowerRange() {
426 checkComputeSameSamplesAsPoissonSamplerReusingCache(midRange,
427 maxRange,
428 minRange,
429 midRange + 1);
430 }
431
432
433
434
435
436 @Test
437 void testCanComputeSameSamplesAsPoissonSamplerReusingCacheUpperRange() {
438 checkComputeSameSamplesAsPoissonSamplerReusingCache(midRange,
439 maxRange,
440 maxRange - 1,
441 maxRange + 5);
442 }
443
444
445
446
447
448
449
450
451
452
453
454
455
456 private void checkComputeSameSamplesAsPoissonSamplerReusingCache(int minMean,
457 int maxMean,
458 int minMean2,
459 int maxMean2) {
460
461 final RandomSource source = RandomSource.SPLIT_MIX_64;
462 final long seed = RandomSource.createLong();
463 final RestorableUniformRandomProvider rng1 = source.create(seed);
464 final RestorableUniformRandomProvider rng2 = source.create(seed);
465
466
467 final PoissonSamplerCache cache =
468 createPoissonSamplerCache(minMean, maxMean);
469
470
471 for (int i = minMean; i <= maxMean; i++) {
472 cache.createSharedStateSampler(rng1, i);
473 }
474
475 final PoissonSamplerCache cache2 = cache.withRange(minMean2, maxMean2);
476 Assertions.assertNotSame(cache, cache2, "WithRange cache is the same object");
477
478
479
480 for (int i = minRange; i <= maxRange; i++) {
481
482 testPoissonSamples(rng1, rng2, cache2, i);
483
484 testPoissonSamples(rng1, rng2, cache2, i + 0.5);
485 }
486 }
487
488
489
490
491
492 @SuppressWarnings("deprecation")
493 @Test
494 void testCreatePoissonSampler() {
495 final PoissonSamplerCache cache = createPoissonSamplerCache(0, 100);
496 final DiscreteSampler s2 = cache.createPoissonSampler(null, 42);
497 Assertions.assertTrue(s2 instanceof LargeMeanPoissonSampler);
498 }
499 }