Skip to content

WIP: use L128X1024Mix for random generator #424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ Use _jqwik_ itself for all tests and properties.

Use _AssertJ_ for non trivial assertions.

Use `@ForAll Random random` parameter if you need a random value.
Use `@ForAll JqwikRandom random` parameter if you need a random value.
2 changes: 2 additions & 0 deletions api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ signing {
dependencies {
api("org.opentest4j:opentest4j:${opentest4jVersion}")
api("org.junit.platform:junit-platform-commons:${junitPlatformVersion}")
api(platform("org.apache.commons:commons-rng-bom:1.5"))
api("org.apache.commons:commons-rng-client-api")
}
6 changes: 3 additions & 3 deletions api/src/main/java/net/jqwik/api/Arbitraries.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public static <T> Arbitrary<T> fromGenerator(RandomGenerator<T> generator) {
* @param <T> The type of values to generate
* @return a new arbitrary instance
*/
public static <T> Arbitrary<T> randomValue(Function<Random, T> generator) {
public static <T> Arbitrary<T> randomValue(Function<JqwikRandom, T> generator) {
return fromGenerator(random -> Shrinkable.unshrinkable(generator.apply(random)));
}

Expand All @@ -120,8 +120,8 @@ public static <T> Arbitrary<T> randomValue(Function<Random, T> generator) {
*
* @return a new arbitrary instance
*/
public static Arbitrary<Random> randoms() {
return randomValue(random -> new Random(random.nextLong()));
public static Arbitrary<JqwikRandom> randoms() {
return randomValue(JqwikRandom::split);
}

/**
Expand Down
37 changes: 37 additions & 0 deletions api/src/main/java/net/jqwik/api/JqwikRandom.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.jqwik.api;

import net.jqwik.api.random.*;

import org.apache.commons.rng.*;

import java.util.*;

public interface JqwikRandom extends UniformRandomProvider {
JqwikRandom jump();

default JqwikRandom split() {
return split(this);
}

JqwikRandom split(UniformRandomProvider source);

JqwikRandomState saveState();

void restoreState(JqwikRandomState state);

default Random asJdkRandom() {
return new Random() {
@Override
protected int next(int bits) {
int next = JqwikRandom.this.nextInt();
next &= ((1L << bits) - 1);
return next;
}

@Override
public long nextLong() {
return JqwikRandom.this.nextLong();
}
};
}
}
3 changes: 1 addition & 2 deletions api/src/main/java/net/jqwik/api/RandomDistribution.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.jqwik.api;

import java.math.*;
import java.util.*;

import org.apiguardian.api.*;

Expand Down Expand Up @@ -61,7 +60,7 @@ interface RandomNumericGenerator {
*
* @return an instance of BigInteger. Never {@code null}.
*/
BigInteger next(Random random);
BigInteger next(JqwikRandom random);
}

/**
Expand Down
14 changes: 8 additions & 6 deletions api/src/main/java/net/jqwik/api/RandomGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.util.function.*;
import java.util.stream.*;

import net.jqwik.api.random.*;

import org.apiguardian.api.*;

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

public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, RandomGenerator<U>> mapper, long nextLong);
public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, RandomGenerator<U>> mapper, JqwikRandomState nextLong);

public abstract <T, U> Shrinkable<U> flatMap(
Shrinkable<T> wrappedShrinkable,
Function<T, Arbitrary<U>> mapper,
int genSize,
long nextLong,
JqwikRandomState nextLong,
boolean withEmbeddedEdgeCases
);

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

@API(status = INTERNAL)
default <U> RandomGenerator<U> map(Function<T, U> mapper) {
Expand All @@ -63,7 +65,7 @@ default <U> RandomGenerator<U> mapShrinkable(Function<Shrinkable<T>, Shrinkable<
default <U> RandomGenerator<U> flatMap(Function<T, RandomGenerator<U>> mapper) {
return random -> {
Shrinkable<T> wrappedShrinkable = RandomGenerator.this.next(random);
return RandomGeneratorFacade.implementation.flatMap(wrappedShrinkable, mapper, random.nextLong());
return RandomGeneratorFacade.implementation.flatMap(wrappedShrinkable, mapper, random.split().saveState());
};
}

Expand All @@ -72,7 +74,7 @@ default <U> RandomGenerator<U> flatMap(Function<T, Arbitrary<U>> mapper, int gen
return random -> {
Shrinkable<T> wrappedShrinkable = RandomGenerator.this.next(random);
return RandomGeneratorFacade.implementation
.flatMap(wrappedShrinkable, mapper, genSize, random.nextLong(), withEmbeddedEdgeCases);
.flatMap(wrappedShrinkable, mapper, genSize, random.split().saveState(), withEmbeddedEdgeCases);
};
}

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

@API(status = INTERNAL)
default Stream<Shrinkable<T>> stream(Random random) {
default Stream<Shrinkable<T>> stream(JqwikRandom random) {
return Stream.generate(() -> this.next(random));
}

Expand Down
6 changes: 4 additions & 2 deletions api/src/main/java/net/jqwik/api/Shrinkable.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.util.function.*;
import java.util.stream.*;

import net.jqwik.api.random.*;

import org.apiguardian.api.*;

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

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

public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, Arbitrary<U>> flatMapper, int tries, long randomSeed);
public abstract <T, U> Shrinkable<U> flatMap(Shrinkable<T> self, Function<T, Arbitrary<U>> flatMapper, int tries, JqwikRandomState randomSeed);
}

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

default <U> Shrinkable<U> flatMap(Function<T, Arbitrary<U>> flatMapper, int tries, long randomSeed) {
default <U> Shrinkable<U> flatMap(Function<T, Arbitrary<U>> flatMapper, int tries, JqwikRandomState randomSeed) {
return ShrinkableFacade.implementation.flatMap(this, flatMapper, tries, randomSeed);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package net.jqwik.api.facades;

import java.util.*;

import org.apiguardian.api.*;

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

public abstract <T> T falsifyThenShrink(Arbitrary<? extends T> arbitrary, Random random, Falsifier<T> falsifier);
public abstract <T> T falsifyThenShrink(Arbitrary<? extends T> arbitrary, JqwikRandom random, Falsifier<T> falsifier);

public abstract <T> T falsifyThenShrink(RandomGenerator<? extends T> arbitrary, Random random, Falsifier<T> falsifier);
public abstract <T> T falsifyThenShrink(RandomGenerator<? extends T> arbitrary, JqwikRandom random, Falsifier<T> falsifier);

public abstract <T> T shrink(
Shrinkable<T> falsifiedShrinkable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public abstract class TestingSupportFacade {
implementation = FacadeLoader.load(TestingSupportFacade.class);
}

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

public abstract String singleLineReport(Object any);

Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/net/jqwik/api/random/JqwikRandomSeed.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package net.jqwik.api.random;

public interface JqwikRandomSeed {
}
5 changes: 5 additions & 0 deletions api/src/main/java/net/jqwik/api/random/JqwikRandomState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package net.jqwik.api.random;

public interface JqwikRandomState {
Object getAlgorithm();
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ The starting point for generation usually is a static method call on class
return Arbitraries.randomValue(random -> generatePrime(random));
}

private Integer generatePrime(Random random) {
private Integer generatePrime(JqwikRandom random) {
int candidate;
do {
candidate = random.nextInt(10000) + 2;
Expand Down Expand Up @@ -309,7 +309,7 @@ Arbitraries.strings().ofMinLength(5).ofMaxLength(25)

#### java.util.Random

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

#### Shuffling Permutations
Expand Down
4 changes: 2 additions & 2 deletions documentation/src/docs/include/lifecycle-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ and publish the result using a [`Reporter`](/docs/${docsVersion}/javadoc/net/jqw
```java
@Property(tries = 100)
@AddLifecycleHook(MeasureTime.class)
void measureTimeSpent(@ForAll Random random) throws InterruptedException {
void measureTimeSpent(@ForAll JqwikRandom random) throws InterruptedException {
Thread.sleep(random.nextInt(50));
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void countingTries(@ForAll String aString) {

@Property(tries = 100)
@AddLifecycleHook(MeasureTime.class)
void measureTimeSpent(@ForAll Random random) throws InterruptedException {
void measureTimeSpent(@ForAll JqwikRandom random) throws InterruptedException {
Thread.sleep(random.nextInt(50));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class AroundTryHookExamples {

@Property(tries = 10)
@AddLifecycleHook(FailIfTooSlow.class)
void sleepingProperty(@ForAll Random random) throws InterruptedException {
void sleepingProperty(@ForAll JqwikRandom random) throws InterruptedException {
Thread.sleep(random.nextInt(101));
}

Expand Down
2 changes: 2 additions & 0 deletions engine/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ dependencies {
api("org.opentest4j:opentest4j:${opentest4jVersion}")
api("org.junit.platform:junit-platform-commons:${junitPlatformVersion}")
implementation("org.junit.platform:junit-platform-engine:${junitPlatformVersion}")
implementation("org.apache.commons:commons-rng-core")
implementation("org.apache.commons:commons-rng-simple")

testImplementation(project(":testing"))

Expand Down
Loading