1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.statistics.distribution;
18
19 import java.util.concurrent.ThreadLocalRandom;
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.junit.jupiter.api.Assertions;
22 import org.junit.jupiter.api.Test;
23 import org.junit.jupiter.params.ParameterizedTest;
24 import org.junit.jupiter.params.provider.ValueSource;
25
26
27
28
29 class DiscreteDistributionTest {
30
31
32
33 @Test
34 void testDefaultMethods() {
35
36 final DiscreteDistribution dist = new InvalidDiscreteDistribution() {
37 @Override
38 public double probability(int x) {
39 return x;
40 }
41
42 @Override
43 public double cumulativeProbability(int x) {
44
45
46 if (x < 0) {
47 return x < -5 ? 0.25 : 0.5;
48 }
49 return x > 5 ? 1.0 : 0.75;
50 }
51
52 @Override
53 public int inverseCumulativeProbability(double p) {
54
55 return (int) (10 * p);
56 }
57 };
58
59 for (final int x : new int[] {Integer.MIN_VALUE, -1, 0, 1, 2, Integer.MAX_VALUE}) {
60
61 Assertions.assertEquals(Math.log(x), dist.logProbability(x));
62
63 Assertions.assertEquals(1.0 - dist.cumulativeProbability(x), dist.survivalProbability(x));
64 }
65
66 for (final double p : new double[] {0.2, 0.5, 0.7}) {
67 Assertions.assertEquals(dist.inverseCumulativeProbability(1 - p),
68 dist.inverseSurvivalProbability(p));
69 }
70 }
71
72
73
74
75 @Test
76 void testDefaultProbabilityRange() {
77
78 final DiscreteDistribution dist = new InvalidDiscreteDistribution() {
79 @Override
80 public double probability(int x) {
81
82 return x + (1L << 31) + 1;
83 }
84
85 @Override
86 public double cumulativeProbability(int x) {
87
88 return x * 0x1.0p-31;
89 }
90
91 @Override
92 public int getSupportLowerBound() {
93 return Integer.MIN_VALUE;
94 }
95
96 @Override
97 public int getSupportUpperBound() {
98 return Integer.MAX_VALUE;
99 }
100 };
101
102
103 final int[] values = {
104 Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
105 -3, -2, -1, 0, 1, 2, 3,
106 Integer.MAX_VALUE - 1, Integer.MAX_VALUE
107 };
108 for (final int x0 : values) {
109
110 Assertions.assertEquals(0.0, dist.probability(x0, x0));
111 if (x0 < dist.getSupportUpperBound()) {
112
113 Assertions.assertEquals(dist.probability(x0 + 1), dist.probability(x0, x0 + 1));
114 for (final int x1 : values) {
115 if (x1 > x0 + 1) {
116
117 Assertions.assertEquals(dist.cumulativeProbability(x1) - dist.cumulativeProbability(x0),
118 dist.probability(x0, x1));
119 } else if (x1 < x0) {
120 Assertions.assertThrows(IllegalArgumentException.class, () -> dist.probability(x0, x1));
121 }
122 }
123 }
124 }
125 }
126
127
128
129
130
131 @Test
132 void testDefaultProbabilityRangeOverflow() {
133
134
135 final DiscreteDistribution dist = new InvalidDiscreteDistribution() {
136 @Override
137 public double probability(int x) {
138 return x;
139 }
140 };
141
142
143 final int min = Integer.MIN_VALUE;
144 final int max = Integer.MAX_VALUE;
145 Assertions.assertEquals(0.0, dist.probability(min, min));
146 Assertions.assertEquals(0.0, dist.probability(max, max));
147 Assertions.assertEquals(min + 1, dist.probability(min, min + 1));
148 Assertions.assertEquals(max, dist.probability(max - 1, max));
149 }
150
151
152
153
154
155
156 @ParameterizedTest
157 @ValueSource(longs = {0, 1, 13})
158 void testSamplerStreamMethods(long streamSize) {
159 final int seed = ThreadLocalRandom.current().nextInt();
160 final DiscreteDistribution.Sampler s1 = createIncrementSampler(seed);
161 final DiscreteDistribution.Sampler s2 = createIncrementSampler(seed);
162 final DiscreteDistribution.Sampler s3 = createIncrementSampler(seed);
163
164 final int[] x = new int[(int) streamSize];
165 for (int i = 0; i < x.length; i++) {
166 x[i] = s1.sample();
167 }
168
169 Assertions.assertArrayEquals(x, s2.samples().limit(streamSize).toArray(), "samples()");
170 Assertions.assertArrayEquals(x, s3.samples(streamSize).toArray(), "samples(long)");
171 }
172
173
174
175
176
177
178 @ParameterizedTest
179 @ValueSource(longs = {-1, -6576237846822L})
180 void testSamplerStreamMethodsThrow(long streamSize) {
181 final DiscreteDistribution.Sampler s = createIncrementSampler(42);
182 Assertions.assertThrows(IllegalArgumentException.class, () -> s.samples(streamSize));
183 }
184
185
186
187
188 @Test
189 void testSamplerStreamMethodsNotParallel() {
190 final DiscreteDistribution.Sampler s = createIncrementSampler(42);
191 Assertions.assertFalse(s.samples().isParallel(), "samples() should not be parallel");
192 Assertions.assertFalse(s.samples(11).isParallel(), "samples(long) should not be parallel");
193 }
194
195
196
197
198
199
200
201
202 private static DiscreteDistribution.Sampler createIncrementSampler(int seed) {
203 return new DiscreteDistribution.Sampler() {
204 private int x = seed;
205
206 @Override
207 public int sample() {
208 return x += 1;
209 }
210 };
211 }
212
213
214
215
216
217 private abstract static class InvalidDiscreteDistribution implements DiscreteDistribution {
218 @Override
219 public double probability(int x) {
220 throw new AssertionError();
221 }
222 @Override
223 public double cumulativeProbability(int x) {
224 throw new AssertionError();
225 }
226 @Override
227 public int inverseCumulativeProbability(double p) {
228 throw new AssertionError();
229 }
230 @Override
231 public double getMean() {
232 throw new AssertionError();
233 }
234 @Override
235 public double getVariance() {
236 throw new AssertionError();
237 }
238 @Override
239 public int getSupportLowerBound() {
240 throw new AssertionError();
241 }
242 @Override
243 public int getSupportUpperBound() {
244 throw new AssertionError();
245 }
246 @Override
247 public Sampler createSampler(UniformRandomProvider rng) {
248 throw new AssertionError();
249 }
250 }
251 }