1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.random;
23
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26
27 import java.util.Arrays;
28
29 import org.hipparchus.UnitTestUtils;
30 import org.hipparchus.exception.MathIllegalArgumentException;
31 import org.hipparchus.util.FastMath;
32 import org.junit.Assert;
33 import org.junit.Before;
34 import org.junit.Test;
35
36
37
38
39
40
41
42
43
44
45
46 public abstract class RandomGeneratorAbstractTest extends RandomDataGeneratorTest {
47
48
49 protected RandomGenerator generator;
50
51
52
53
54
55 protected abstract RandomGenerator makeGenerator();
56
57
58
59
60 public RandomGeneratorAbstractTest() {
61 generator = makeGenerator();
62 randomData = RandomDataGenerator.of(generator);
63 }
64
65
66
67
68 @Before
69 public void setUp() {
70 generator = makeGenerator();
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85 @Test
86 public void testNextIntDirect() {
87
88 int[] testValues = new int[] {4, 10, 12, 32, 100, 10000, 0, 0, 0, 0};
89 for (int i = 6; i < 10; i++) {
90 final int val = generator.nextInt();
91 testValues[i] = val < 0 ? -val : val + 1;
92 }
93
94 final int numTests = 1000;
95 for (int i = 0; i < testValues.length; i++) {
96 final int n = testValues[i];
97
98 int[] binUpperBounds;
99 if (n < 32) {
100 binUpperBounds = new int[n];
101 for (int k = 0; k < n; k++) {
102 binUpperBounds[k] = k;
103 }
104 } else {
105 binUpperBounds = new int[10];
106 final int step = n / 10;
107 for (int k = 0; k < 9; k++) {
108 binUpperBounds[k] = (k + 1) * step;
109 }
110 binUpperBounds[9] = n - 1;
111 }
112
113 int numFailures = 0;
114 final int binCount = binUpperBounds.length;
115 final long[] observed = new long[binCount];
116 final double[] expected = new double[binCount];
117 expected[0] = binUpperBounds[0] == 0 ? (double) smallSampleSize / (double) n :
118 (double) ((binUpperBounds[0] + 1) * smallSampleSize) / (double) n;
119 for (int k = 1; k < binCount; k++) {
120 expected[k] = (double) smallSampleSize *
121 (double) (binUpperBounds[k] - binUpperBounds[k - 1]) / n;
122 }
123 for (int j = 0; j < numTests; j++) {
124 Arrays.fill(observed, 0);
125 for (int k = 0; k < smallSampleSize; k++) {
126 final int value = generator.nextInt(n);
127 assertTrue("nextInt range",(value >= 0) && (value < n));
128 for (int l = 0; l < binCount; l++) {
129 if (binUpperBounds[l] >= value) {
130 observed[l]++;
131 break;
132 }
133 }
134 }
135 if (UnitTestUtils.chiSquareTest(expected, observed) < 0.01) {
136 numFailures++;
137 }
138 }
139 if ((double) numFailures / (double) numTests > 0.02) {
140 fail("Too many failures for n = " + n +
141 " " + numFailures + " out of " + numTests + " tests failed.");
142 }
143 }
144 }
145
146 @Test
147 public void testNextLongDirect() {
148 long q1 = Long.MAX_VALUE/4;
149 long q2 = 2 * q1;
150 long q3 = 3 * q1;
151
152 long[] observed = new long[4];
153 long val = 0;
154 for (int i = 0; i < smallSampleSize; i++) {
155 val = generator.nextLong();
156 val = val < 0 ? -val : val;
157 if (val < q1) {
158 observed[0] = ++observed[0];
159 } else if (val < q2) {
160 observed[1] = ++observed[1];
161 } else if (val < q3) {
162 observed[2] = ++observed[2];
163 } else {
164 observed[3] = ++observed[3];
165 }
166 }
167
168
169
170
171 assertTrue("chi-square test -- will fail about 1 in 1000 times",
172 UnitTestUtils.chiSquare(expected,observed) < 16.27);
173 }
174
175 @Test
176 public void testNextBooleanDirect() {
177 long halfSampleSize = smallSampleSize / 2;
178 double[] expected = {halfSampleSize, halfSampleSize};
179 long[] observed = new long[2];
180 for (int i=0; i<smallSampleSize; i++) {
181 if (generator.nextBoolean()) {
182 observed[0]++;
183 } else {
184 observed[1]++;
185 }
186 }
187
188
189
190 assertTrue("chi-square test -- will fail about 1 in 1000 times",
191 UnitTestUtils.chiSquare(expected,observed) < 10.828);
192 }
193
194 @Test
195 public void testNextFloatDirect() {
196 long[] observed = new long[4];
197 for (int i=0; i<smallSampleSize; i++) {
198 float val = generator.nextFloat();
199 if (val < 0.25) {
200 observed[0] = ++observed[0];
201 } else if (val < 0.5) {
202 observed[1] = ++observed[1];
203 } else if (val < 0.75) {
204 observed[2] = ++observed[2];
205 } else {
206 observed[3] = ++observed[3];
207 }
208 }
209
210
211
212
213 assertTrue("chi-square test -- will fail about 1 in 1000 times",
214 UnitTestUtils.chiSquare(expected,observed) < 16.27);
215 }
216
217 @Test
218 public void testNextDouble() {
219 final double[] sample = new double[10000];
220 final double[] expected = new double[100];
221 final long[] observed = new long[100];
222 Arrays.fill(expected, 100d);
223 for (int i = 0; i < sample.length; i++) {
224 sample[i] = generator.nextDouble();
225 int j = 0;
226 while (sample[i] < j / 100) {
227 j++;
228 }
229 observed[j] = observed[j]++;
230 }
231 UnitTestUtils.assertChiSquareAccept(expected, observed, 0.01);
232 }
233
234
235 @Test(expected=MathIllegalArgumentException.class)
236 public void testNextIntPrecondition1() {
237 generator.nextInt(-1);
238 }
239
240 @Test(expected=MathIllegalArgumentException.class)
241 public void testNextIntPrecondition2() {
242 generator.nextInt(0);
243 }
244
245 @Test
246 public void testNextInt2() {
247 int walk = 0;
248 final int N = 10000;
249 for (int k = 0; k < N; ++k) {
250 if (generator.nextInt() >= 0) {
251 ++walk;
252 } else {
253 --walk;
254 }
255 }
256 assertTrue("Walked too far astray: " + walk + "\nNote: This " +
257 "test will fail randomly about 1 in 100 times.",
258 FastMath.abs(walk) < FastMath.sqrt(N) * 2.576);
259 }
260
261 @Test
262 public void testNextLong2() {
263 int walk = 0;
264 final int N = 1000;
265 for (int k = 0; k < N; ++k) {
266 if (generator.nextLong() >= 0) {
267 ++walk;
268 } else {
269 --walk;
270 }
271 }
272 assertTrue("Walked too far astray: " + walk + "\nNote: This " +
273 "test will fail randomly about 1 in 100 times.",
274 FastMath.abs(walk) < FastMath.sqrt(N) * 2.576);
275 }
276
277 @Test
278 public void testNextBoolean2() {
279 int walk = 0;
280 final int N = 10000;
281 for (int k = 0; k < N; ++k) {
282 if (generator.nextBoolean()) {
283 ++walk;
284 } else {
285 --walk;
286 }
287 }
288 assertTrue("Walked too far astray: " + walk + "\nNote: This " +
289 "test will fail randomly about 1 in 100 times.",
290 FastMath.abs(walk) < FastMath.sqrt(N) * 2.576);
291 }
292
293 @Test
294 public void testNextBytes() {
295 long[] count = new long[256];
296 byte[] bytes = new byte[10];
297 double[] expected = new double[256];
298 final int sampleSize = 100000;
299
300 for (int i = 0; i < 256; i++) {
301 expected[i] = (double) sampleSize / 265f;
302 }
303
304 for (int k = 0; k < sampleSize; ++k) {
305 generator.nextBytes(bytes);
306 for (byte b : bytes) {
307 ++count[b + 128];
308 }
309 }
310
311 UnitTestUtils.assertChiSquareAccept(expected, count, 0.001);
312 }
313
314
315 @Test
316 public void testNextBytesChunks() {
317 final int[] chunkSizes = { 4, 8, 12, 16 };
318 final int[] chunks = { 1, 2, 3, 4, 5 };
319 for (int chunkSize : chunkSizes) {
320 for (int numChunks : chunks) {
321 checkNextBytesChunks(chunkSize, numChunks);
322 }
323 }
324 }
325
326 @Test
327 public void testSeeding() {
328
329 RandomGenerator gen = makeGenerator();
330 RandomGenerator gen1 = makeGenerator();
331 checkSameSequence(gen, gen1);
332
333
334 gen.setSeed(100);
335 gen1 = makeGenerator();
336 gen1.setSeed(100);
337 checkSameSequence(gen, gen1);
338 }
339
340 private void checkSameSequence(RandomGenerator gen1, RandomGenerator gen2) {
341 final int len = 11;
342 final double[][] values = new double[2][len];
343 for (int i = 0; i < len; i++) {
344 values[0][i] = gen1.nextDouble();
345 }
346 for (int i = 0; i < len; i++) {
347 values[1][i] = gen2.nextDouble();
348 }
349 assertTrue(Arrays.equals(values[0], values[1]));
350 for (int i = 0; i < len; i++) {
351 values[0][i] = gen1.nextFloat();
352 }
353 for (int i = 0; i < len; i++) {
354 values[1][i] = gen2.nextFloat();
355 }
356 assertTrue(Arrays.equals(values[0], values[1]));
357 for (int i = 0; i < len; i++) {
358 values[0][i] = gen1.nextInt();
359 }
360 for (int i = 0; i < len; i++) {
361 values[1][i] = gen2.nextInt();
362 }
363 assertTrue(Arrays.equals(values[0], values[1]));
364 for (int i = 0; i < len; i++) {
365 values[0][i] = gen1.nextLong();
366 }
367 for (int i = 0; i < len; i++) {
368 values[1][i] = gen2.nextLong();
369 }
370 assertTrue(Arrays.equals(values[0], values[1]));
371 for (int i = 0; i < len; i++) {
372 values[0][i] = gen1.nextInt(len);
373 }
374 for (int i = 0; i < len; i++) {
375 values[1][i] = gen2.nextInt(len);
376 }
377 assertTrue(Arrays.equals(values[0], values[1]));
378 for (int i = 0; i < len; i++) {
379 values[0][i] = gen1.nextBoolean() ? 1 : 0;
380 }
381 for (int i = 0; i < len; i++) {
382 values[1][i] = gen2.nextBoolean() ? 1 : 0;
383 }
384 assertTrue(Arrays.equals(values[0], values[1]));
385 for (int i = 0; i < len; i++) {
386 values[0][i] = gen1.nextGaussian();
387 }
388 for (int i = 0; i < len; i++) {
389 values[1][i] = gen2.nextGaussian();
390 }
391 assertTrue(Arrays.equals(values[0], values[1]));
392 }
393
394
395 private void checkNextBytesChunks(int chunkSize,
396 int numChunks) {
397 final RandomGenerator rg = makeGenerator();
398 final long seed = 1234567L;
399
400 final byte[] b1 = new byte[chunkSize * numChunks];
401 final byte[] b2 = new byte[chunkSize];
402
403
404 rg.setSeed(seed);
405 rg.nextBytes(b1);
406
407
408 rg.setSeed(seed);
409
410 for (int i = 0; i < numChunks; i++) {
411 rg.nextBytes(b2);
412 }
413
414
415 final byte[] b3 = new byte[chunkSize];
416 System.arraycopy(b1, b1.length - b3.length, b3, 0, b3.length);
417
418
419 Assert.assertArrayEquals("chunkSize=" + chunkSize + " numChunks=" + numChunks,
420 b2, b3);
421 }
422
423 @Override
424 public void testNextZipf() {
425
426 }
427 }