1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng.simple;
18
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Modifier;
21 import java.time.Duration;
22 import java.util.SplittableRandom;
23 import java.util.stream.DoubleStream;
24 import java.util.stream.IntStream;
25 import java.util.stream.LongStream;
26 import org.apache.commons.rng.RandomProviderState;
27 import org.apache.commons.rng.RestorableUniformRandomProvider;
28 import org.apache.commons.rng.UniformRandomProvider;
29 import org.apache.commons.rng.core.source64.LongProvider;
30 import org.junit.jupiter.api.Assertions;
31 import org.junit.jupiter.api.Test;
32
33
34
35
36 class RandomSourceTest {
37 @Test
38 void testCreateInt() {
39 final int n = 4;
40 for (int i = 0; i < n; i++) {
41
42 Assertions.assertNotEquals(RandomSource.createInt(),
43 RandomSource.createInt());
44 }
45 }
46
47 @Test
48 void testCreateLong() {
49 final int n = 6;
50 for (int i = 0; i < n; i++) {
51
52 Assertions.assertNotEquals(RandomSource.createLong(),
53 RandomSource.createLong());
54 }
55 }
56
57 @Test
58 void testCreateIntArray() {
59 final int n = 13;
60 final int[] seed = RandomSource.createIntArray(n);
61 Assertions.assertEquals(n, seed.length);
62
63 for (int i = 1; i < n; i++) {
64
65 Assertions.assertNotEquals(seed[i - 1], seed[i]);
66 }
67 }
68
69 @Test
70 void testCreateLongArray() {
71 final int n = 9;
72 final long[] seed = RandomSource.createLongArray(n);
73 Assertions.assertEquals(n, seed.length);
74
75 for (int i = 1; i < n; i++) {
76
77 Assertions.assertNotEquals(seed[i - 1], seed[i]);
78 }
79 }
80
81 @Test
82 void testIsJumpable() {
83 Assertions.assertFalse(RandomSource.JDK.isJumpable(), "JDK is not Jumpable");
84 Assertions.assertTrue(RandomSource.XOR_SHIFT_1024_S_PHI.isJumpable(), "XOR_SHIFT_1024_S_PHI is Jumpable");
85 Assertions.assertTrue(RandomSource.XO_SHI_RO_256_SS.isJumpable(), "XO_SHI_RO_256_SS is Jumpable");
86 }
87
88 @Test
89 void testIsLongJumpable() {
90 Assertions.assertFalse(RandomSource.JDK.isLongJumpable(), "JDK is not LongJumpable");
91 Assertions.assertFalse(RandomSource.XOR_SHIFT_1024_S_PHI.isLongJumpable(), "XOR_SHIFT_1024_S_PHI is not LongJumpable");
92 Assertions.assertTrue(RandomSource.XO_SHI_RO_256_SS.isLongJumpable(), "XO_SHI_RO_256_SS is LongJumpable");
93 }
94
95 @Test
96 void testIsSplittable() {
97 Assertions.assertFalse(RandomSource.JDK.isSplittable(), "JDK is not Splittable");
98 Assertions.assertTrue(RandomSource.L32_X64_MIX.isSplittable(), "L32_X64_MIX is Splittable");
99 Assertions.assertTrue(RandomSource.L64_X128_MIX.isSplittable(), "L64_X128_MIX is Splittable");
100 }
101
102
103
104
105
106 @Test
107 void testMSWSCreateSeed() {
108 final LongProvider broken = new LongProvider() {
109 @Override
110 public long next() {
111 return 0;
112 }
113 };
114 Assertions.assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
115 RandomSource.MSWS.createSeed(broken);
116 });
117 }
118
119
120
121
122
123
124 @Test
125 void testUnrestorable() {
126
127 assertNoDefaultMethods(RestorableRNG.class);
128
129 final UniformRandomProvider rng1 = new RestorableRNG();
130 final RestorableRNG r = new RestorableRNG();
131 final UniformRandomProvider rng2 = RandomSource.unrestorable(r);
132 Assertions.assertNotSame(rng2, r);
133
134
135 assertNoDefaultMethods(rng2.getClass());
136
137
138
139
140
141 Assertions.assertNotSame(rng2, RandomSource.unrestorable(rng2));
142
143
144 RandomAssert.assertProduceSameSequence(rng1, rng2);
145
146
147 @SuppressWarnings("unused")
148 final RestorableUniformRandomProvider restorable = (RestorableUniformRandomProvider) rng1;
149
150 Assertions.assertThrows(ClassCastException.class, () -> {
151 @SuppressWarnings("unused")
152 final RestorableUniformRandomProvider dummy = (RestorableUniformRandomProvider) rng2;
153 });
154 }
155
156
157
158
159
160
161 private static void assertNoDefaultMethods(Class<?> cls) {
162 for (final Method method : cls.getMethods()) {
163 if ((method.getModifiers() & Modifier.PUBLIC) != 0) {
164 Assertions.assertTrue(!method.isDefault(),
165 () -> cls.getName() + " should override method: " + method.toGenericString());
166 }
167 }
168 }
169
170
171
172
173
174 private static class RestorableRNG implements RestorableUniformRandomProvider {
175
176 private final SplittableRandom rng = new SplittableRandom(123);
177
178 @Override
179 public void nextBytes(byte[] bytes) {
180 nextBytes(bytes, 0, bytes.length);
181 }
182
183 @Override
184 public void nextBytes(byte[] bytes, int start, int len) {
185 RestorableUniformRandomProvider.super.nextBytes(bytes, start, len);
186
187 for (int i = start + len; i-- > start;) {
188 bytes[i] += 1;
189 }
190 }
191
192 @Override
193 public int nextInt() {
194 return RestorableUniformRandomProvider.super.nextInt() + 1;
195 }
196
197 @Override
198 public int nextInt(int n) {
199 final int v = RestorableUniformRandomProvider.super.nextInt(n) + 1;
200 return v == n ? 0 : v;
201 }
202
203 @Override
204 public int nextInt(int origin, int bound) {
205 final int v = RestorableUniformRandomProvider.super.nextInt(origin, bound) + 1;
206 return v == bound ? origin : v;
207 }
208
209 @Override
210 public long nextLong() {
211
212 return rng.nextLong();
213 }
214
215 @Override
216 public long nextLong(long n) {
217 final long v = RestorableUniformRandomProvider.super.nextLong(n) + 1;
218 return v == n ? 0 : v;
219 }
220
221 @Override
222 public long nextLong(long origin, long bound) {
223 final long v = RestorableUniformRandomProvider.super.nextLong(origin, bound) + 1;
224 return v == bound ? origin : v;
225 }
226
227 @Override
228 public boolean nextBoolean() {
229 return !RestorableUniformRandomProvider.super.nextBoolean();
230 }
231
232 @Override
233 public float nextFloat() {
234 final float v = 1 - RestorableUniformRandomProvider.super.nextFloat();
235 return v == 1 ? 0 : v;
236 }
237
238 @Override
239 public float nextFloat(float bound) {
240 final float v = Math.nextUp(RestorableUniformRandomProvider.super.nextFloat(bound));
241 return v == bound ? 0 : v;
242 }
243
244 @Override
245 public float nextFloat(float origin, float bound) {
246 final float v = Math.nextUp(RestorableUniformRandomProvider.super.nextFloat(origin, bound));
247 return v == bound ? 0 : v;
248 }
249
250 @Override
251 public double nextDouble() {
252 final double v = 1 - RestorableUniformRandomProvider.super.nextDouble();
253 return v == 1 ? 0 : v;
254 }
255
256 @Override
257 public double nextDouble(double bound) {
258 final double v = Math.nextUp(RestorableUniformRandomProvider.super.nextDouble(bound));
259 return v == bound ? 0 : v;
260 }
261
262 @Override
263 public double nextDouble(double origin, double bound) {
264 final double v = Math.nextUp(RestorableUniformRandomProvider.super.nextDouble(origin, bound));
265 return v == bound ? 0 : v;
266 }
267
268
269
270 @Override
271 public IntStream ints() {
272 return IntStream.generate(() -> nextInt() + 1).sequential();
273 }
274
275 @Override
276 public IntStream ints(int origin, int bound) {
277 return IntStream.generate(() -> {
278 final int v = nextInt(origin, bound) + 1;
279 return v == bound ? origin : v;
280 }).sequential();
281 }
282
283 @Override
284 public IntStream ints(long streamSize) {
285 return ints().limit(streamSize);
286 }
287
288 @Override
289 public IntStream ints(long streamSize, int origin, int bound) {
290 return ints(origin, bound).limit(streamSize);
291 }
292
293 @Override
294 public LongStream longs() {
295 return LongStream.generate(() -> nextLong() + 1).sequential();
296 }
297
298 @Override
299 public LongStream longs(long origin, long bound) {
300 return LongStream.generate(() -> {
301 final long v = nextLong(origin, bound) + 1;
302 return v == bound ? origin : v;
303 }).sequential();
304 }
305
306 @Override
307 public LongStream longs(long streamSize) {
308 return longs().limit(streamSize);
309 }
310
311 @Override
312 public LongStream longs(long streamSize, long origin, long bound) {
313 return longs(origin, bound).limit(streamSize);
314 }
315
316 @Override
317 public DoubleStream doubles() {
318 return DoubleStream.generate(() -> {
319 final double v = Math.nextUp(nextDouble());
320 return v == 1 ? 0 : v;
321 }).sequential();
322 }
323
324 @Override
325 public DoubleStream doubles(double origin, double bound) {
326 return DoubleStream.generate(() -> {
327 final double v = Math.nextUp(nextDouble(origin, bound));
328 return v == bound ? origin : v;
329 }).sequential();
330 }
331
332 @Override
333 public DoubleStream doubles(long streamSize) {
334 return doubles().limit(streamSize);
335 }
336
337 @Override
338 public DoubleStream doubles(long streamSize, double origin, double bound) {
339 return doubles(origin, bound).limit(streamSize);
340 }
341
342 @Override
343 public RandomProviderState saveState() {
344
345 return null;
346 }
347
348 @Override
349 public void restoreState(RandomProviderState state) {
350
351 }
352 }
353 }