1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.core;
18
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.ArrayList;
22 import java.util.concurrent.Callable;
23 import java.io.IOException;
24 import java.io.ObjectOutputStream;
25 import java.io.ObjectInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.ByteArrayInputStream;
28
29 import org.junit.Assert;
30 import org.junit.Test;
31 import org.junit.Assume;
32 import org.junit.Ignore;
33 import org.junit.runner.RunWith;
34 import org.junit.runners.Parameterized;
35 import org.junit.runners.Parameterized.Parameters;
36
37 import org.apache.commons.rng.UniformRandomProvider;
38 import org.apache.commons.rng.RestorableUniformRandomProvider;
39 import org.apache.commons.rng.RandomProviderState;
40
41
42
43
44 @RunWith(value=Parameterized.class)
45 public class ProvidersCommonParametricTest {
46
47 private final RestorableUniformRandomProvider generator;
48
49
50
51
52
53
54 public ProvidersCommonParametricTest(RestorableUniformRandomProvider rng) {
55 generator = rng;
56 }
57
58 @Parameters(name = "{index}: data={0}")
59 public static Iterable<RestorableUniformRandomProvider[]> getList() {
60 return ProvidersList.list();
61 }
62
63
64
65
66 @Test(expected=IllegalArgumentException.class)
67 public void testPreconditionNextInt1() {
68 generator.nextInt(-1);
69 }
70
71 @Test(expected=IllegalArgumentException.class)
72 public void testPreconditionNextInt2() {
73 generator.nextInt(0);
74 }
75
76 @Test(expected=IllegalArgumentException.class)
77 public void testPreconditionNextLong1() {
78 generator.nextLong(-1);
79 }
80
81 @Test(expected=IllegalArgumentException.class)
82 public void testPreconditionNextLong2() {
83 generator.nextLong(0);
84 }
85
86 @Test(expected=IndexOutOfBoundsException.class)
87 public void testPreconditionNextBytes1() {
88 final int size = 10;
89 final int num = 1;
90 final byte[] buf = new byte[size];
91 generator.nextBytes(buf, -1, num);
92 }
93 @Test(expected=IndexOutOfBoundsException.class)
94 public void testPreconditionNextBytes2() {
95 final int size = 10;
96 final byte[] buf = new byte[size];
97 generator.nextBytes(buf, size, 0);
98 }
99 @Test(expected=IndexOutOfBoundsException.class)
100 public void testPreconditionNextBytes3() {
101 final int size = 10;
102 final int offset = 2;
103 final byte[] buf = new byte[size];
104 generator.nextBytes(buf, offset, size - offset + 1);
105 }
106 @Test(expected=IndexOutOfBoundsException.class)
107 public void testPreconditionNextBytes4() {
108 final int size = 10;
109 final int offset = 1;
110 final byte[] buf = new byte[size];
111 generator.nextBytes(buf, offset, -1);
112 }
113
114
115
116
117 @Test
118 public void testUniformNextBytesFullBuffer() {
119
120
121 final int size = 23;
122 final byte[] buffer = new byte[size];
123
124 final Runnable nextMethod = new Runnable() {
125 @Override
126 public void run() {
127 generator.nextBytes(buffer);
128 }
129 };
130
131 Assert.assertTrue(isUniformNextBytes(buffer, 0, size, nextMethod));
132 }
133
134 @Test
135 public void testUniformNextBytesPartialBuffer() {
136 final int totalSize = 1234;
137 final int offset = 567;
138 final int size = 89;
139
140 final byte[] buffer = new byte[totalSize];
141
142 final Runnable nextMethod = new Runnable() {
143 @Override
144 public void run() {
145 generator.nextBytes(buffer, offset, size);
146 }
147 };
148
149
150 Assert.assertTrue(isUniformNextBytes(buffer, offset, offset + size, nextMethod));
151
152
153 Assert.assertFalse(isUniformNextBytes(buffer, 0, offset, nextMethod));
154 Assert.assertFalse(isUniformNextBytes(buffer, offset + size, buffer.length, nextMethod));
155 }
156
157 @Test
158 public void testUniformNextIntegerInRange() {
159 checkNextIntegerInRange(4, 1000);
160 checkNextIntegerInRange(10, 1000);
161 checkNextIntegerInRange(12, 1000);
162 checkNextIntegerInRange(31, 1000);
163 checkNextIntegerInRange(32, 1000);
164 checkNextIntegerInRange(2016128993, 1000);
165 checkNextIntegerInRange(1834691456, 1000);
166 checkNextIntegerInRange(869657561, 1000);
167 checkNextIntegerInRange(1570504788, 1000);
168 }
169
170 @Test
171 public void testUniformNextLongInRange() {
172 checkNextLongInRange(4, 1000);
173 checkNextLongInRange(11, 1000);
174 checkNextLongInRange(19, 1000);
175 checkNextLongInRange(31, 1000);
176 checkNextLongInRange(32, 1000);
177
178 final long q = Long.MAX_VALUE / 4;
179 checkNextLongInRange(q, 1000);
180 checkNextLongInRange(2 * q, 1000);
181 checkNextLongInRange(3 * q, 1000);
182 }
183
184 @Test
185 public void testUniformNextFloat() {
186 checkNextFloat(1000);
187 }
188
189 @Test
190 public void testUniformNextDouble() {
191 checkNextDouble(1000);
192 }
193
194 @Test
195 public void testUniformNextIntRandomWalk() {
196 final Callable<Boolean> nextMethod = new Callable<Boolean>() {
197 @Override
198 public Boolean call() throws Exception {
199 return generator.nextInt() >= 0;
200 }
201 };
202
203 checkRandomWalk(1000, nextMethod);
204 }
205
206 @Test
207 public void testUniformNextLongRandomWalk() {
208 final Callable<Boolean> nextMethod = new Callable<Boolean>() {
209 @Override
210 public Boolean call() throws Exception {
211 return generator.nextLong() >= 0;
212 }
213 };
214
215 checkRandomWalk(1000, nextMethod);
216 }
217
218 @Test
219 public void testUniformNextBooleanRandomWalk() {
220 final Callable<Boolean> nextMethod = new Callable<Boolean>() {
221 @Override
222 public Boolean call() throws Exception {
223 return generator.nextBoolean();
224 }
225 };
226
227 checkRandomWalk(1000, nextMethod);
228 }
229
230
231
232 @Test
233 public void testStateSettable() {
234
235
236 final int n = 10000;
237
238
239 final RandomProviderState state = generator.saveState();
240
241 final List<Number> listOrig = makeList(n);
242
243 final List<Number> listDiscard = makeList(n);
244 Assert.assertTrue(listDiscard.size() != 0);
245 Assert.assertFalse(listOrig.equals(listDiscard));
246
247 generator.restoreState(state);
248
249 final List<Number> listReplay = makeList(n);
250 Assert.assertFalse(listOrig == listReplay);
251
252 Assert.assertTrue(listOrig.equals(listReplay));
253 }
254
255 @Test(expected=IllegalArgumentException.class)
256 public void testStateWrongSize() {
257
258 Assume.assumeTrue(generator.toString().indexOf("JDKRandom") == -1);
259
260 final RandomProviderState state = new DummyGenerator().saveState();
261
262 generator.restoreState(state);
263 }
264
265 @Test(expected=IllegalArgumentException.class)
266 public void testRestoreForeignState() {
267 generator.restoreState(new RandomProviderState() {});
268 }
269
270
271
272
273
274
275
276
277
278
279 private List<Number> makeList(int n) {
280 final List<Number> list = new ArrayList<Number>();
281
282 for (int i = 0; i < n; i++) {
283
284 list.add(generator.nextInt());
285 list.add(generator.nextInt(21));
286 list.add(generator.nextInt(436));
287 list.add(generator.nextLong());
288 list.add(generator.nextLong(157894));
289 list.add(generator.nextLong(5745833));
290 list.add(generator.nextFloat());
291 list.add(generator.nextFloat());
292 list.add(generator.nextDouble());
293 list.add(generator.nextDouble());
294 list.add(generator.nextDouble());
295 }
296
297 return list;
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 private boolean isUniformNextBytes(byte[] buffer,
315 int first,
316 int last,
317 Runnable nextMethod) {
318 final int sampleSize = 10000;
319
320
321 final int byteRange = 256;
322
323
324 final double chi2CriticalValue = 311.560343;
325
326 final int byteRangeOffset = 128;
327
328
329 final long[] observed = new long[byteRange];
330 final double[] expected = new double[byteRange];
331
332 for (int i = 0; i < byteRange; i++) {
333 expected[i] = sampleSize * (last - first) / (double) byteRange;
334 }
335
336 try {
337 for (int k = 0; k < sampleSize; k++) {
338 nextMethod.run();
339
340 for (int i = first; i < last; i++) {
341 final byte b = buffer[i];
342 ++observed[b + byteRangeOffset];
343 }
344 }
345 } catch (Exception e) {
346
347 throw new RuntimeException("Unexpected");
348 }
349
350
351 double chi2 = 0;
352 for (int k = 0; k < byteRange; k++) {
353 final double diff = observed[k] - expected[k];
354 chi2 += diff * diff / expected[k];
355 }
356
357
358 return chi2 < chi2CriticalValue;
359 }
360
361
362
363
364
365
366
367
368
369
370 private void checkRandomWalk(int sampleSize,
371 Callable<Boolean> nextMethod) {
372 int walk = 0;
373
374 try {
375 for (int k = 0; k < sampleSize; ++k) {
376 if (nextMethod.call()) {
377 ++walk;
378 } else {
379 --walk;
380 }
381 }
382 } catch (Exception e) {
383
384 throw new RuntimeException("Unexpected");
385 }
386
387 final double actual = Math.abs(walk);
388 final double max = Math.sqrt(sampleSize) * 2.576;
389 Assert.assertTrue(generator + ": Walked too far astray: " + actual +
390 " > " + max +
391 " (test will fail randomly about 1 in 100 times)",
392 actual < max);
393 }
394
395
396
397
398
399
400
401 private void checkNextIntegerInRange(final int max,
402 int sampleSize) {
403 checkNextIntegerInRange(generator, max, sampleSize);
404 }
405
406
407
408
409
410
411
412
413 private void checkNextIntegerInRange(final UniformRandomProvider rng,
414 final int max,
415 int sampleSize) {
416 final Callable<Integer> nextMethod = new Callable<Integer>() {
417 @Override
418 public Integer call() throws Exception {
419 return rng.nextInt(max);
420 }
421 };
422
423 checkNextInRange(max, sampleSize, nextMethod);
424 }
425
426
427
428
429
430
431
432 private void checkNextLongInRange(final long max,
433 int sampleSize) {
434 final Callable<Long> nextMethod = new Callable<Long>() {
435 @Override
436 public Long call() throws Exception {
437 return generator.nextLong(max);
438 }
439 };
440
441 checkNextInRange(max, sampleSize, nextMethod);
442 }
443
444
445
446
447
448
449 private void checkNextFloat(int sampleSize) {
450 final int max = 1234;
451 final Callable<Integer> nextMethod = new Callable<Integer>() {
452 @Override
453 public Integer call() throws Exception {
454 return (int) (max * generator.nextFloat());
455 }
456 };
457
458 checkNextInRange(max, sampleSize, nextMethod);
459 }
460
461
462
463
464
465
466 private void checkNextDouble(int sampleSize) {
467 final int max = 578;
468 final Callable<Integer> nextMethod = new Callable<Integer>() {
469 @Override
470 public Integer call() throws Exception {
471 return (int) (max * generator.nextDouble());
472 }
473 };
474
475 checkNextInRange(max, sampleSize, nextMethod);
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490 private <T extends Number> void checkNextInRange(T max,
491 int sampleSize,
492 Callable<T> nextMethod) {
493 final int numTests = 500;
494
495
496 final int numBins = 10;
497
498
499 final long n = max.longValue();
500 final long[] binUpperBounds = new long[numBins];
501 final double step = n / (double) numBins;
502 for (int k = 0; k < numBins; k++) {
503 binUpperBounds[k] = (long) ((k + 1) * step);
504 }
505
506
507 int numFailures = 0;
508
509 final double[] expected = new double[numBins];
510 long previousUpperBound = 0;
511 for (int k = 0; k < numBins; k++) {
512 final long range = binUpperBounds[k] - previousUpperBound;
513 expected[k] = sampleSize * (range / (double) n);
514 previousUpperBound = binUpperBounds[k];
515 }
516
517 final int[] observed = new int[numBins];
518
519
520 final double chi2CriticalValue = 21.67;
521
522 try {
523 for (int i = 0; i < numTests; i++) {
524 Arrays.fill(observed, 0);
525 for (int j = 0; j < sampleSize; j++) {
526 final long value = nextMethod.call().longValue();
527 Assert.assertTrue("Range", (value >= 0) && (value < n));
528
529 for (int k = 0; k < numBins; k++) {
530 if (value < binUpperBounds[k]) {
531 ++observed[k];
532 break;
533 }
534 }
535 }
536
537
538 double chi2 = 0;
539 for (int k = 0; k < numBins; k++) {
540 final double diff = observed[k] - expected[k];
541 chi2 += diff * diff / expected[k];
542 }
543
544
545 if (chi2 > chi2CriticalValue) {
546 ++numFailures;
547 }
548 }
549 } catch (Exception e) {
550
551 throw new RuntimeException("Unexpected", e);
552 }
553
554 if ((double) numFailures / (double) numTests > 0.02) {
555 Assert.fail(generator + ": Too many failures for n = " + n +
556 " (" + numFailures + " out of " + numTests + " tests failed)");
557 }
558 }
559
560
561
562
563
564
565 static void checkNextBytesChunks(RestorableUniformRandomProvider rng,
566 int chunkSize,
567 int numChunks) {
568 final byte[] b1 = new byte[chunkSize * numChunks];
569 final byte[] b2 = new byte[chunkSize];
570
571 final RandomProviderState state = rng.saveState();
572
573
574 rng.nextBytes(b1);
575
576
577 rng.restoreState(state);
578
579
580 for (int i = 0; i < numChunks; i++) {
581 rng.nextBytes(b2);
582 }
583
584
585 final byte[] b3 = new byte[chunkSize];
586 System.arraycopy(b1, b1.length - b3.length, b3, 0, b3.length);
587
588
589 Assert.assertArrayEquals("chunkSize=" + chunkSize + " numChunks=" + numChunks,
590 b2, b3);
591 }
592
593
594
595
596 class DummyGenerator extends org.apache.commons.rng.core.source32.IntProvider {
597
598 @Override
599 public int next() {
600 return 4;
601 }
602
603
604 @Override
605 protected byte[] getStateInternal() {
606 return new byte[0];
607 }
608
609
610 @Override
611 protected void setStateInternal(byte[] s) {
612
613 }
614 }
615 }