Skip to content

Commit 36d1336

Browse files
author
Vladimir Sitnikov
committed
WIP: use L128X1024Mix for random generator
fixes #363
1 parent 7a37d8d commit 36d1336

File tree

154 files changed

+1191
-876
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

154 files changed

+1191
-876
lines changed

CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ Use _jqwik_ itself for all tests and properties.
3737

3838
Use _AssertJ_ for non trivial assertions.
3939

40-
Use `@ForAll Random random` parameter if you need a random value.
40+
Use `@ForAll JqwikRandom random` parameter if you need a random value.

api/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,6 @@ signing {
5353
dependencies {
5454
api("org.opentest4j:opentest4j:${opentest4jVersion}")
5555
api("org.junit.platform:junit-platform-commons:${junitPlatformVersion}")
56+
api(platform("org.apache.commons:commons-rng-bom:1.5"))
57+
api("org.apache.commons:commons-rng-client-api")
5658
}

api/src/main/java/net/jqwik/api/Arbitraries.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import javax.annotation.*;
44
import java.util.*;
55
import java.util.function.*;
6-
import java.util.stream.*;
76

87
import org.apiguardian.api.*;
98

@@ -112,7 +111,7 @@ public static <T> Arbitrary<T> fromGenerator(RandomGenerator<T> generator) {
112111
* @param <T> The type of values to generate
113112
* @return a new arbitrary instance
114113
*/
115-
public static <T> Arbitrary<T> randomValue(Function<Random, T> generator) {
114+
public static <T> Arbitrary<T> randomValue(Function<JqwikRandom, T> generator) {
116115
return fromGenerator(random -> Shrinkable.unshrinkable(generator.apply(random)));
117116
}
118117

@@ -121,8 +120,8 @@ public static <T> Arbitrary<T> randomValue(Function<Random, T> generator) {
121120
*
122121
* @return a new arbitrary instance
123122
*/
124-
public static Arbitrary<Random> randoms() {
125-
return randomValue(random -> new Random(random.nextLong()));
123+
public static Arbitrary<JqwikRandom> randoms() {
124+
return randomValue(JqwikRandom::split);
126125
}
127126

128127
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package net.jqwik.api;
2+
3+
import net.jqwik.api.random.*;
4+
5+
import org.apache.commons.rng.*;
6+
7+
import java.util.*;
8+
9+
public interface JqwikRandom extends UniformRandomProvider {
10+
JqwikRandom jump();
11+
12+
default JqwikRandom split() {
13+
return split(this);
14+
}
15+
16+
JqwikRandom split(UniformRandomProvider source);
17+
18+
JqwikRandomState saveState();
19+
20+
void restoreState(JqwikRandomState state);
21+
22+
default Random asJdkRandom() {
23+
return new Random() {
24+
@Override
25+
protected int next(int bits) {
26+
int next = JqwikRandom.this.nextInt();
27+
next &= ((1L << bits) - 1);
28+
return next;
29+
}
30+
31+
@Override
32+
public long nextLong() {
33+
return JqwikRandom.this.nextLong();
34+
}
35+
};
36+
}
37+
}

api/src/main/java/net/jqwik/api/RandomDistribution.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package net.jqwik.api;
22

33
import java.math.*;
4-
import java.util.*;
54

65
import org.apiguardian.api.*;
76

@@ -61,7 +60,7 @@ interface RandomNumericGenerator {
6160
*
6261
* @return an instance of BigInteger. Never {@code null}.
6362
*/
64-
BigInteger next(Random random);
63+
BigInteger next(JqwikRandom random);
6564
}
6665

6766
/**

api/src/main/java/net/jqwik/api/RandomGenerator.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.util.function.*;
55
import java.util.stream.*;
66

7+
import net.jqwik.api.random.*;
8+
79
import org.apiguardian.api.*;
810

911
import static org.apiguardian.api.API.Status.*;
@@ -19,13 +21,13 @@ abstract class RandomGeneratorFacade {
1921
implementation = FacadeLoader.load(RandomGeneratorFacade.class);
2022
}
2123

22-
public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, RandomGenerator<U>> mapper, long nextLong);
24+
public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, RandomGenerator<U>> mapper, JqwikRandomState nextLong);
2325

2426
public abstract <T, U> Shrinkable<U> flatMap(
2527
Shrinkable<T> wrappedShrinkable,
2628
Function<T, Arbitrary<U>> mapper,
2729
int genSize,
28-
long nextLong,
30+
JqwikRandomState nextLong,
2931
boolean withEmbeddedEdgeCases
3032
);
3133

@@ -44,7 +46,7 @@ public abstract <T, U> Shrinkable<U> flatMap(
4446
* @param random the source of randomness. Injected by jqwik itself.
4547
* @return the next generated value wrapped within the Shrinkable interface. The method must ALWAYS return a next value.
4648
*/
47-
Shrinkable<T> next(Random random);
49+
Shrinkable<T> next(JqwikRandom random);
4850

4951
@API(status = INTERNAL)
5052
default <U> RandomGenerator<U> map(Function<T, U> mapper) {
@@ -63,7 +65,7 @@ default <U> RandomGenerator<U> mapShrinkable(Function<Shrinkable<T>, Shrinkable<
6365
default <U> RandomGenerator<U> flatMap(Function<T, RandomGenerator<U>> mapper) {
6466
return random -> {
6567
Shrinkable<T> wrappedShrinkable = RandomGenerator.this.next(random);
66-
return RandomGeneratorFacade.implementation.flatMap(wrappedShrinkable, mapper, random.nextLong());
68+
return RandomGeneratorFacade.implementation.flatMap(wrappedShrinkable, mapper, random.split().saveState());
6769
};
6870
}
6971

@@ -72,7 +74,7 @@ default <U> RandomGenerator<U> flatMap(Function<T, Arbitrary<U>> mapper, int gen
7274
return random -> {
7375
Shrinkable<T> wrappedShrinkable = RandomGenerator.this.next(random);
7476
return RandomGeneratorFacade.implementation
75-
.flatMap(wrappedShrinkable, mapper, genSize, random.nextLong(), withEmbeddedEdgeCases);
77+
.flatMap(wrappedShrinkable, mapper, genSize, random.split().saveState(), withEmbeddedEdgeCases);
7678
};
7779
}
7880

@@ -87,7 +89,7 @@ default RandomGenerator<T> withEdgeCases(int genSize, EdgeCases<T> edgeCases) {
8789
}
8890

8991
@API(status = INTERNAL)
90-
default Stream<Shrinkable<T>> stream(Random random) {
92+
default Stream<Shrinkable<T>> stream(JqwikRandom random) {
9193
return Stream.generate(() -> this.next(random));
9294
}
9395

api/src/main/java/net/jqwik/api/Shrinkable.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.util.function.*;
66
import java.util.stream.*;
77

8+
import net.jqwik.api.random.*;
9+
810
import org.apiguardian.api.*;
911

1012
import static org.apiguardian.api.API.Status.*;
@@ -26,7 +28,7 @@ abstract class ShrinkableFacade {
2628

2729
public abstract <T> Shrinkable<T> filter(Shrinkable<T> self, Predicate<T> filter);
2830

29-
public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, Arbitrary<U>> flatMapper, int tries, long randomSeed);
31+
public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, Arbitrary<U>> flatMapper, int tries, JqwikRandomState randomSeed);
3032
}
3133

3234
static <T> Shrinkable<T> unshrinkable(@Nullable T value) {
@@ -106,7 +108,7 @@ default Shrinkable<T> filter(Predicate<T> filter) {
106108
return ShrinkableFacade.implementation.filter(this, filter);
107109
}
108110

109-
default <U> Shrinkable<U> flatMap(Function<T, Arbitrary<U>> flatMapper, int tries, long randomSeed) {
111+
default <U> Shrinkable<U> flatMap(Function<T, Arbitrary<U>> flatMapper, int tries, JqwikRandomState randomSeed) {
110112
return ShrinkableFacade.implementation.flatMap(this, flatMapper, tries, randomSeed);
111113
}
112114

api/src/main/java/net/jqwik/api/facades/ShrinkingSupportFacade.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package net.jqwik.api.facades;
22

3-
import java.util.*;
4-
53
import org.apiguardian.api.*;
64

75
import net.jqwik.api.*;
@@ -17,9 +15,9 @@ public abstract class ShrinkingSupportFacade {
1715
implementation = FacadeLoader.load(ShrinkingSupportFacade.class);
1816
}
1917

20-
public abstract <T> T falsifyThenShrink(Arbitrary<? extends T> arbitrary, Random random, Falsifier<T> falsifier);
18+
public abstract <T> T falsifyThenShrink(Arbitrary<? extends T> arbitrary, JqwikRandom random, Falsifier<T> falsifier);
2119

22-
public abstract <T> T falsifyThenShrink(RandomGenerator<? extends T> arbitrary, Random random, Falsifier<T> falsifier);
20+
public abstract <T> T falsifyThenShrink(RandomGenerator<? extends T> arbitrary, JqwikRandom random, Falsifier<T> falsifier);
2321

2422
public abstract <T> T shrink(
2523
Shrinkable<T> falsifiedShrinkable,

api/src/main/java/net/jqwik/api/facades/TestingSupportFacade.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public abstract class TestingSupportFacade {
1313
implementation = FacadeLoader.load(TestingSupportFacade.class);
1414
}
1515

16-
public abstract <T> Shrinkable<T> generateUntil(RandomGenerator<T> generator, Random random, Function<T, Boolean> condition);
16+
public abstract <T> Shrinkable<T> generateUntil(RandomGenerator<T> generator, JqwikRandom random, Function<T, Boolean> condition);
1717

1818
public abstract String singleLineReport(Object any);
1919

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package net.jqwik.api.random;
2+
3+
public interface JqwikRandomSeed {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package net.jqwik.api.random;
2+
3+
public interface JqwikRandomState {
4+
Object getAlgorithm();
5+
}

documentation/src/docs/include/customized-parameter-generation.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ The starting point for generation usually is a static method call on class
195195
return Arbitraries.randomValue(random -> generatePrime(random));
196196
}
197197

198-
private Integer generatePrime(Random random) {
198+
private Integer generatePrime(JqwikRandom random) {
199199
int candidate;
200200
do {
201201
candidate = random.nextInt(10000) + 2;
@@ -309,7 +309,7 @@ Arbitraries.strings().ofMinLength(5).ofMaxLength(25)
309309

310310
#### java.util.Random
311311

312-
- [`Arbitrary<Random> randoms()`](/docs/${docsVersion}/javadoc/net/jqwik/api/Arbitraries.html#randoms()):
312+
- [`Arbitrary<JqwikRandom> randoms()`](/docs/${docsVersion}/javadoc/net/jqwik/api/Arbitraries.html#randoms()):
313313
Random instances will never be shrunk
314314

315315
#### Shuffling Permutations

documentation/src/docs/include/lifecycle-hooks.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ and publish the result using a [`Reporter`](/docs/${docsVersion}/javadoc/net/jqw
189189
```java
190190
@Property(tries = 100)
191191
@AddLifecycleHook(MeasureTime.class)
192-
void measureTimeSpent(@ForAll Random random) throws InterruptedException {
192+
void measureTimeSpent(@ForAll JqwikRandom random) throws InterruptedException {
193193
Thread.sleep(random.nextInt(50));
194194
}
195195

@@ -228,7 +228,7 @@ The following example shows how to fail if a single try will take longer than 10
228228
```java
229229
@Property(tries = 10)
230230
@AddLifecycleHook(FailIfTooSlow.class)
231-
void sleepingProperty(@ForAll Random random) throws InterruptedException {
231+
void sleepingProperty(@ForAll JqwikRandom random) throws InterruptedException {
232232
Thread.sleep(random.nextInt(101));
233233
}
234234

documentation/src/test/java/net/jqwik/docs/lifecycle/AroundPropertyHookExamples.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void countingTries(@ForAll String aString) {
3838

3939
@Property(tries = 100)
4040
@AddLifecycleHook(MeasureTime.class)
41-
void measureTimeSpent(@ForAll Random random) throws InterruptedException {
41+
void measureTimeSpent(@ForAll JqwikRandom random) throws InterruptedException {
4242
Thread.sleep(random.nextInt(50));
4343
}
4444

documentation/src/test/java/net/jqwik/docs/lifecycle/AroundTryHookExamples.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class AroundTryHookExamples {
1111

1212
@Property(tries = 10)
1313
@AddLifecycleHook(FailIfTooSlow.class)
14-
void sleepingProperty(@ForAll Random random) throws InterruptedException {
14+
void sleepingProperty(@ForAll JqwikRandom random) throws InterruptedException {
1515
Thread.sleep(random.nextInt(101));
1616
}
1717

engine/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ dependencies {
8282
api("org.opentest4j:opentest4j:${opentest4jVersion}")
8383
api("org.junit.platform:junit-platform-commons:${junitPlatformVersion}")
8484
implementation("org.junit.platform:junit-platform-engine:${junitPlatformVersion}")
85+
implementation("org.apache.commons:commons-rng-core")
86+
implementation("org.apache.commons:commons-rng-simple")
8587

8688
testImplementation(project(":testing"))
8789

0 commit comments

Comments
 (0)