This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit 70548cabb9bb37df42d4fffbcfbdf5c6d448fd51 Author: Alex Herbert <[email protected]> AuthorDate: Thu Feb 12 14:03:16 2026 +0000 RNG-188: Update code layout for consistency --- .../commons/rng/core/source32/Philox4x32.java | 232 +++++++++---------- .../commons/rng/core/source64/Philox4x64.java | 249 +++++++++------------ .../commons/rng/core/source32/Philox4x32Test.java | 97 ++++---- .../commons/rng/core/source64/Philox4x64Test.java | 120 +++++----- .../rng/examples/jmh/RandomSourceValues.java | 6 +- .../rng/examples/jmh/core/BaselineSources.java | 6 +- .../rng/examples/jmh/core/JumpBenchmark.java | 4 +- .../rng/simple/internal/ProviderBuilder.java | 1 + 8 files changed, 336 insertions(+), 379 deletions(-) diff --git a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/Philox4x32.java b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/Philox4x32.java index bcfad35d..c291913a 100644 --- a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/Philox4x32.java +++ b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/Philox4x32.java @@ -26,70 +26,69 @@ import java.util.Arrays; /** * This class implements the Philox4x32 128-bit counter-based generator with 10 rounds. - * Jumping in the sequence is essentially instantaneous. This generator provides subsequences for easy parallelization. * - * @see <a href="https://www.thesalmons.org/john/random123/papers/random123sc11.pdf">Parallel Random Numbers: As Easy as 1,2,3</a> + * <p>This is a member of the Philox family of generators. Memory footprint is 192 bits + * and the period is 4*2<sup>128</sup>.</p> + * + * <p>Jumping in the sequence is essentially instantaneous. + * This generator provides subsequences for easy parallelization. + * + * <p>References: + * <ol> + * <li> + * Salmon, J.K. <i>et al</i> (2011) + * <a href="https://dl.acm.org/doi/epdf/10.1145/2063384.2063405"> + * Parallel Random Numbers: As Easy as 1,2,3</a>.</li> + * </ol> + * * @since 1.7 */ public final class Philox4x32 extends IntProvider implements LongJumpableUniformRandomProvider { - /** - * Philox 32-bit mixing constant for counter 0. - */ + /** Philox 32-bit mixing constant for counter 0. */ private static final int K_PHILOX_10_A = 0x9E3779B9; - /** - * Philox 32-bit mixing constant for counter 1. - */ + /** Philox 32-bit mixing constant for counter 1. */ private static final int K_PHILOX_10_B = 0xBB67AE85; - /** - * Philox 32-bit constant for key 0. - */ + /** Philox 32-bit constant for key 0. */ private static final int K_PHILOX_SA = 0xD2511F53; - /** - * Philox 32-bit constant for key 1. - */ + /** Philox 32-bit constant for key 1. */ private static final int K_PHILOX_SB = 0xCD9E8D57; - /** - * Internal buffer size. - */ + /** Internal buffer size. */ private static final int PHILOX_BUFFER_SIZE = 4; - /** - * number of int variables. - */ + /** Number of state variables. */ private static final int STATE_SIZE = 7; - /** - * Counter 0. - */ + /** Counter 0. */ private int counter0; - /** - * Counter 1. - */ + /** Counter 1. */ private int counter1; - /** - * Counter 2. - */ + /** Counter 2. */ private int counter2; - /** - * Counter 3. - */ + /** Counter 3. */ private int counter3; - /** - * Output point. - */ - private int[] buffer = new int[PHILOX_BUFFER_SIZE]; // UINT4 - /** - * Key low bits. - */ + /** Output buffer. */ + private final int[] buffer = new int[PHILOX_BUFFER_SIZE]; + /** Key low bits. */ private int key0; - /** - * Key high bits. - */ + /** Key high bits. */ private int key1; - /** - * State index: which output word is next (0..3). - */ + /** Output buffer index. When at the end of the buffer the counter is + * incremented and the buffer regenerated. */ private int bufferPosition; + /** + * Creates a new instance based on an array of int containing, key (first two ints) and + * the counter (next 4 ints, low bits = first int). The counter is not scrambled and may + * be used to create contiguous blocks with size a multiple of 4 ints. For example, + * setting seed[2] = 1 is equivalent to start with seed[2]=0 and calling {@link #next()} 4 times. + * + * @param seed Array of size 6 defining key0,key1,counter0,counter1,counter2,counter3. + * If the size is smaller, zero values are assumed. + */ + public Philox4x32(int[] seed) { + final int[] input = seed.length < 6 ? Arrays.copyOf(seed, 6) : seed; + setState(input); + bufferPosition = PHILOX_BUFFER_SIZE; + } /** * Copy constructor. @@ -105,7 +104,7 @@ public final class Philox4x32 extends IntProvider implements LongJumpableUniform key0 = source.key0; key1 = source.key1; bufferPosition = source.bufferPosition; - buffer = source.buffer.clone(); + System.arraycopy(source.buffer, 0, buffer, 0, PHILOX_BUFFER_SIZE); } /** @@ -128,30 +127,40 @@ public final class Philox4x32 extends IntProvider implements LongJumpableUniform } /** - * Creates a new instance based on an array of int containing, key (first two ints) and - * the counter (next 4 ints, low bits = first int). The counter is not scrambled and may - * be used to create contiguous blocks with size a multiple of 4 ints. For example, - * setting seed[2] = 1 is equivalent to start with seed[2]=0 and calling {@link #next()} 4 times. + * Copies the state from the array into the generator state. * - * @param seed an array of size 6 defining key0,key1,counter0,counter1,counter2,counter3. - * If the size is smaller, zero values are assumed. + * @param state New state. */ - public Philox4x32(int[] seed) { - final int[] input = seed.length < 6 ? Arrays.copyOf(seed, 6) : seed; - key0 = input[0]; - key1 = input[1]; - counter0 = input[2]; - counter1 = input[3]; - counter2 = input[4]; - counter3 = input[5]; - bufferPosition = PHILOX_BUFFER_SIZE; + private void setState(int[] state) { + key0 = state[0]; + key1 = state[1]; + counter0 = state[2]; + counter1 = state[3]; + counter2 = state[4]; + counter3 = state[5]; } - /** - * Fetch next integer from the buffer, or regenerate the buffer using 10 rounds. - * - * @return random integer - */ + /** {@inheritDoc} */ + @Override + protected byte[] getStateInternal() { + return composeStateInternal( + NumberFactory.makeByteArray(new int[] {key0, key1, counter0, counter1, counter2, counter3, bufferPosition}), + super.getStateInternal()); + } + + /** {@inheritDoc} */ + @Override + protected void setStateInternal(byte[] s) { + final byte[][] c = splitStateInternal(s, STATE_SIZE * Integer.BYTES); + final int[] state = NumberFactory.makeIntArray(c[0]); + setState(state); + bufferPosition = state[6]; + super.setStateInternal(c[1]); + // Regenerate the internal buffer + rand10(); + } + + /** {@inheritDoc} */ @Override public int next() { final int p = bufferPosition; @@ -166,48 +175,24 @@ public final class Philox4x32 extends IntProvider implements LongJumpableUniform } /** - * Increment by one. + * Increment the counter by one. */ private void incrementCounter() { counter0++; if (counter0 != 0) { return; } - counter1++; if (counter1 != 0) { return; } - counter2++; if (counter2 != 0) { return; } - counter3++; } - /** - * Performs a single round of philox. - * - * @param ctr local counter, which will be updated after each call. - * @param key0 key low bits - * @param key1 key high bits - */ - private static void singleRound(int[] ctr, int key0, int key1) { - long product = (K_PHILOX_SA & 0xFFFFFFFFL) * (ctr[0] & 0xFFFFFFFFL); - final int hi0 = (int) (product >>> 32); - final int lo0 = (int) product; - product = (K_PHILOX_SB & 0xFFFFFFFFL) * (ctr[2] & 0xFFFFFFFFL); - final int hi1 = (int) (product >>> 32); - final int lo1 = (int) product; - - ctr[0] = hi1 ^ ctr[1] ^ key0; - ctr[1] = lo1; - ctr[2] = hi0 ^ ctr[3] ^ key1; - ctr[3] = lo0; - } - /** * Perform 10 rounds, using counter0, counter1, counter2, counter3 as starting point. * It updates the buffer member variable, but no others. @@ -252,28 +237,33 @@ public final class Philox4x32 extends IntProvider implements LongJumpableUniform singleRound(buffer, k0, k1); } - /** - * {@inheritDoc} + * Performs a single round of philox. * - * <p>Increments the subsequence by 1.</p> - * <p>The jump size is the equivalent of 4*2<sup>96</sup> calls to - * {@link UniformRandomProvider#nextInt() nextInt()}. + * @param counter Counter, which will be updated after each call. + * @param key0 Key low bits. + * @param key1 Key high bits. */ - @Override - public JumpableUniformRandomProvider longJump() { - final Philox4x32 copy = copy(); - counter3++; - rand10(); - resetCachedState(); - return copy; + private static void singleRound(int[] counter, int key0, int key1) { + final long product0 = (K_PHILOX_SA & 0xffff_ffffL) * (counter[0] & 0xffff_ffffL); + final int hi0 = (int) (product0 >>> 32); + final int lo0 = (int) product0; + final long product1 = (K_PHILOX_SB & 0xffff_ffffL) * (counter[2] & 0xffff_ffffL); + final int hi1 = (int) (product1 >>> 32); + final int lo1 = (int) product1; + + counter[0] = hi1 ^ counter[1] ^ key0; + counter[1] = lo1; + counter[2] = hi0 ^ counter[3] ^ key1; + counter[3] = lo0; } /** * {@inheritDoc} * * <p>The jump size is the equivalent of 4*2<sup>64</sup> - * calls to {@link UniformRandomProvider#nextInt() nextInt()}. + * calls to {@link UniformRandomProvider#nextInt() nextInt()}. It can provide + * up to 2<sup>64</sup> non-overlapping subsequences.</p> */ @Override public UniformRandomProvider jump() { @@ -288,30 +278,20 @@ public final class Philox4x32 extends IntProvider implements LongJumpableUniform /** * {@inheritDoc} + * + * <p>The jump size is the equivalent of 4*2<sup>96</sup> calls to + * {@link UniformRandomProvider#nextLong() nextLong()}. It can provide up to + * 2<sup>32</sup> non-overlapping subsequences of length 4*2<sup>96</sup>; each + * subsequence can provide up to 2<sup>32</sup> non-overlapping subsequences of + * length 2<sup>64</sup> using the {@link #jump()} method.</p> */ @Override - protected byte[] getStateInternal() { - return composeStateInternal(NumberFactory.makeByteArray( - new int[]{key0, key1, counter0, counter1, counter2, counter3, bufferPosition}), - super.getStateInternal()); - } - - /** - * {@inheritDoc} - */ - @Override - protected void setStateInternal(byte[] s) { - final byte[][] c = splitStateInternal(s, STATE_SIZE * 4); - final int[] state = NumberFactory.makeIntArray(c[0]); - key0 = state[0]; - key1 = state[1]; - counter0 = state[2]; - counter1 = state[3]; - counter2 = state[4]; - counter3 = state[5]; - bufferPosition = state[6]; - super.setStateInternal(c[1]); - rand10(); //to regenerate the internal buffer + public JumpableUniformRandomProvider longJump() { + final Philox4x32 copy = copy(); + counter3++; + rand10(); + resetCachedState(); + return copy; } /** diff --git a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source64/Philox4x64.java b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source64/Philox4x64.java index 8cb15e1c..7c8b060c 100644 --- a/commons-rng-core/src/main/java/org/apache/commons/rng/core/source64/Philox4x64.java +++ b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source64/Philox4x64.java @@ -26,70 +26,76 @@ import java.util.Arrays; /** * This class implements the Philox4x64 256-bit counter-based generator with 10 rounds. - * Jumping in the sequence is essentially instantaneous. This generator provides subsequences for easy parallelization. * - * @see <a href="https://www.thesalmons.org/john/random123/papers/random123sc11.pdf">Parallel Random Numbers: As Easy as 1,2,3</a> + * <p>This is a member of the Philox family of generators. Memory footprint is 384 bits + * and the period is 4*2<sup>256</sup>.</p> + * + * <p>Jumping in the sequence is essentially instantaneous. + * This generator provides subsequences for easy parallelization. + * + * <p>References: + * <ol> + * <li> + * Salmon, J.K. <i>et al</i> (2011) + * <a href="https://dl.acm.org/doi/epdf/10.1145/2063384.2063405"> + * Parallel Random Numbers: As Easy as 1,2,3</a>.</li> + * </ol> + * * @since 1.7 */ public final class Philox4x64 extends LongProvider implements LongJumpableUniformRandomProvider { - /** - * Philox 32-bit mixing constant for counter 0. - */ + /** Philox 32-bit mixing constant for counter 0. */ private static final long PHILOX_M0 = 0xD2E7470EE14C6C93L; - /** - * Philox 32-bit mixing constant for counter 1. - */ + /** Philox 32-bit mixing constant for counter 1. */ private static final long PHILOX_M1 = 0xCA5A826395121157L; - /** - * Philox 32-bit constant for key 0. - */ + /** Philox 32-bit constant for key 0. */ private static final long PHILOX_W0 = 0x9E3779B97F4A7C15L; - /** - * Philox 32-bit constant for key 1. - */ + /** Philox 32-bit constant for key 1. */ private static final long PHILOX_W1 = 0xBB67AE8584CAA73BL; - /** - * Internal buffer size. - */ + /** Internal buffer size. */ private static final int PHILOX_BUFFER_SIZE = 4; - /** - * number of long variables. - */ + /** Number of state variables. */ private static final int STATE_SIZE = 7; - /** - * Counter 0. - */ + /** Counter 0. */ private long counter0; - /** - * Counter 1. - */ + /** Counter 1. */ private long counter1; - /** - * Counter 2. - */ + /** Counter 2. */ private long counter2; - /** - * Counter 3. - */ + /** Counter 3. */ private long counter3; - - /** - * Output point. - */ - private long[] buffer = new long[PHILOX_BUFFER_SIZE]; // UINT4 - /** - * Key low bits. - */ + /** Output buffer. */ + private final long[] buffer = new long[PHILOX_BUFFER_SIZE]; + /** Key low bits. */ private long key0; + /** Key high bits. */ + private long key1; + /** Output buffer index. When at the end of the buffer the counter is + * incremented and the buffer regenerated. */ + private int bufferPosition; + /** - * Key high bits. + * Creates a new instance with default seed. Subsequence and offset are set to zero. */ - private long key1; + public Philox4x64() { + this(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0L, 0L, 0L, 0L}); + } + /** - * State index: which output word is next (0..3). + * Creates a new instance given 6 long numbers containing, key (first two longs) and + * the counter (next 4 longs, low bits = first long). The counter is not scrambled and may + * be used to create contiguous blocks with size a multiple of 4 longs. For example, + * setting seed[2] = 1 is equivalent to start with seed[2]=0 and calling {@link #next()} 4 times. + * + * @param seed Array of size 6 defining key0,key1,counter0,counter1,counter2,counter3. + * If the size is smaller, zero values are assumed. */ - private int bufferPosition; + public Philox4x64(long[] seed) { + final long[] input = seed.length < 6 ? Arrays.copyOf(seed, 6) : seed; + setState(input); + bufferPosition = PHILOX_BUFFER_SIZE; + } /** * Copy constructor. @@ -105,43 +111,47 @@ public final class Philox4x64 extends LongProvider implements LongJumpableUnifor key0 = source.key0; key1 = source.key1; bufferPosition = source.bufferPosition; - buffer = source.buffer.clone(); + System.arraycopy(source.buffer, 0, buffer, 0, PHILOX_BUFFER_SIZE); } /** - * Creates a new instance with default seed. Subsequence and offset are set to zero. + * Copies the state from the array into the generator state. + * + * @param state New state. */ - public Philox4x64() { - this(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0L, 0L, 0L, 0L}); + private void setState(long[] state) { + key0 = state[0]; + key1 = state[1]; + counter0 = state[2]; + counter1 = state[3]; + counter2 = state[4]; + counter3 = state[5]; } + /** {@inheritDoc} */ + @Override + protected byte[] getStateInternal() { + return composeStateInternal( + NumberFactory + .makeByteArray(new long[] {key0, key1, counter0, counter1, counter2, counter3, bufferPosition}), + super.getStateInternal()); + } - /** - * Creates a new instance given 6 long numbers containing, key (first two longs) and - * the counter (next 4, starts at first). The counter is not scrambled and may - * be used to create contiguous blocks with size a multiple of 4 longs. For example, - * setting seed[2] = 1 is equivalent to start with seed[2]=0 and calling {@link #next()} 4 times. - * - * @param keyAndCounter the first two number are the key and the next 4 number are the counter. - * if size is smaller than 6, the array is padded with 0. - */ - public Philox4x64(long[] keyAndCounter) { - final long[] input = keyAndCounter.length < 6 ? Arrays.copyOf(keyAndCounter, 6) : keyAndCounter; - key0 = input[0]; - key1 = input[1]; - counter0 = input[2]; - counter1 = input[3]; - counter2 = input[4]; - counter3 = input[5]; - bufferPosition = PHILOX_BUFFER_SIZE; + /** {@inheritDoc} */ + @Override + protected void setStateInternal(byte[] s) { + final byte[][] c = splitStateInternal(s, STATE_SIZE * Long.BYTES); + final long[] state = NumberFactory.makeLongArray(c[0]); + setState(state); + bufferPosition = (int) state[6]; + super.setStateInternal(c[1]); + // Regenerate the internal buffer + rand10(); } - /** - * Fetch next long from the buffer, or regenerate the buffer using 10 rounds. - * - * @return random 64-bit integer - */ - private long next64() { + /** {@inheritDoc} */ + @Override + public long next() { final int p = bufferPosition; if (bufferPosition < PHILOX_BUFFER_SIZE) { bufferPosition = p + 1; @@ -154,49 +164,27 @@ public final class Philox4x64 extends LongProvider implements LongJumpableUnifor } /** - * Increment by one. + * Increment the counter by one. */ private void incrementCounter() { counter0++; if (counter0 != 0) { return; } - counter1++; if (counter1 != 0) { return; } - counter2++; if (counter2 != 0) { return; } - counter3++; } - /** - * Performs a single round of philox. - * - * @param counter local counter, which will be updated after each call. - * @param key0 key low bits - * @param key1 key high bits - */ - private static void singleRound(long[] counter, long key0, long key1) { - final long lo0 = PHILOX_M0 * counter[0]; - final long hi0 = LXMSupport.unsignedMultiplyHigh(PHILOX_M0, counter[0]); - final long lo1 = PHILOX_M1 * counter[2]; - final long hi1 = LXMSupport.unsignedMultiplyHigh(PHILOX_M1, counter[2]); - - counter[0] = hi1 ^ counter[1] ^ key0; - counter[1] = lo1; - counter[2] = hi0 ^ counter[3] ^ key1; - counter[3] = lo0; - } - /** * Perform 10 rounds, using counter0, counter1, counter2, counter3 as starting point. - * + * It updates the buffer member variable, but no others. */ private void rand10() { buffer[0] = counter0; @@ -239,26 +227,30 @@ public final class Philox4x64 extends LongProvider implements LongJumpableUnifor } /** - * {@inheritDoc} + * Performs a single round of philox. * - * <p>Increments the subsequence by 1.</p> - * <p>The jump size is the equivalent of 4*2<sup>192</sup> calls to - * {@link UniformRandomProvider#nextLong() nextLong()}. + * @param counter Counter, which will be updated after each call. + * @param key0 Key low bits. + * @param key1 Key high bits. */ - @Override - public JumpableUniformRandomProvider longJump() { - final Philox4x64 copy = copy(); - counter3++; - rand10(); - resetCachedState(); - return copy; + private static void singleRound(long[] counter, long key0, long key1) { + final long lo0 = PHILOX_M0 * counter[0]; + final long hi0 = LXMSupport.unsignedMultiplyHigh(PHILOX_M0, counter[0]); + final long lo1 = PHILOX_M1 * counter[2]; + final long hi1 = LXMSupport.unsignedMultiplyHigh(PHILOX_M1, counter[2]); + + counter[0] = hi1 ^ counter[1] ^ key0; + counter[1] = lo1; + counter[2] = hi0 ^ counter[3] ^ key1; + counter[3] = lo0; } /** * {@inheritDoc} * * <p>The jump size is the equivalent of 4*2<sup>128</sup> - * calls to {@link UniformRandomProvider#nextLong() nextLong()}. + * calls to {@link UniformRandomProvider#nextLong() nextLong()}. It can provide + * up to 2<sup>128</sup> non-overlapping subsequences.</p> */ @Override public UniformRandomProvider jump() { @@ -273,39 +265,20 @@ public final class Philox4x64 extends LongProvider implements LongJumpableUnifor /** * {@inheritDoc} + * + * <p>The jump size is the equivalent of 4*2<sup>192</sup> calls to + * {@link UniformRandomProvider#nextLong() nextLong()}. It can provide up to + * 2<sup>64</sup> non-overlapping subsequences of length 2<sup>192</sup>; each + * subsequence can provide up to 2<sup>64</sup> non-overlapping subsequences of + * length 2<sup>128</sup> using the {@link #jump()} method.</p> */ @Override - public long next() { - return next64(); - } - - /** - * {@inheritDoc} - */ - @Override - protected byte[] getStateInternal() { - return composeStateInternal(NumberFactory.makeByteArray( - new long[]{key0, key1, counter0, counter1, counter2, counter3, bufferPosition}), - super.getStateInternal()); - } - - /** - * {@inheritDoc} - */ - @Override - protected void setStateInternal(byte[] s) { - final byte[][] c = splitStateInternal(s, STATE_SIZE * 8); - - final long[] state = NumberFactory.makeLongArray(c[0]); - key0 = state[0]; - key1 = state[1]; - counter0 = state[2]; - counter1 = state[3]; - counter2 = state[4]; - counter3 = state[5]; - bufferPosition = (int) state[6]; - super.setStateInternal(c[1]); + public JumpableUniformRandomProvider longJump() { + final Philox4x64 copy = copy(); + counter3++; rand10(); + resetCachedState(); + return copy; } /** diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/Philox4x32Test.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/Philox4x32Test.java index 1f19c78b..1e934746 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/Philox4x32Test.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/Philox4x32Test.java @@ -16,24 +16,17 @@ */ package org.apache.commons.rng.core.source32; +import java.util.stream.Stream; import org.apache.commons.rng.core.RandomAssert; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Philox4x32Test { - - /* - * Data from python randomgen.philox.Philox(key=1234,number=4,width=32) random_raw() - * https://bashtage.github.io/randomgen/bit_generators/philox.html - */ + // Data from python randomgen.philox.Philox(key=1234,number=4,width=32) random_raw() + // https://bashtage.github.io/randomgen/bit_generators/philox.html private static final int[] EXPECTED_SEQUENCE_1234 = { -1628512715, 482218876, -98078573, 343858512, 1070188760, @@ -85,7 +78,7 @@ public class Philox4x32Test { * * @return the reference data */ - Stream<Arguments> getReferenceData() { + static Stream<Arguments> getReferenceData() { return Stream.of( Arguments.of(1234L, EXPECTED_SEQUENCE_1234), Arguments.of(67280421310721L, EXPECTED_SEQUENCE_DEFAULT) @@ -107,82 +100,92 @@ public class Philox4x32Test { int refValue = rngs[0].next(); for (int i = 1; i < rngs.length; i++) { int value = rngs[i].next(); - assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); + Assertions.assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); } rngs = new Philox4x32[]{ - new Philox4x32(new int[]{1234, 0, 1}), - new Philox4x32(new int[]{1234, 0, 1, 0, 0, 0}), + new Philox4x32(new int[] {1234, 0, 1}), + new Philox4x32(new int[] {1234, 0, 1, 0, 0, 0}), }; refValue = rngs[0].next(); for (int i = 1; i < rngs.length; i++) { int value = rngs[i].next(); - assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); + Assertions.assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); } rngs = new Philox4x32[]{ - new Philox4x32(new int[]{1234}), - new Philox4x32(new int[]{1234, 0}), - new Philox4x32(new int[]{1234, 0, 0}), - new Philox4x32(new int[]{1234, 0, 0, 0}), - new Philox4x32(new int[]{1234, 0, 0, 0, 0}), - new Philox4x32(new int[]{1234, 0, 0, 0, 0, 0}), - new Philox4x32(new int[]{1234, 0, 0, 0, 0, 0, 0}), + new Philox4x32(new int[] {1234}), + new Philox4x32(new int[] {1234, 0}), + new Philox4x32(new int[] {1234, 0, 0}), + new Philox4x32(new int[] {1234, 0, 0, 0}), + new Philox4x32(new int[] {1234, 0, 0, 0, 0}), + new Philox4x32(new int[] {1234, 0, 0, 0, 0, 0}), + new Philox4x32(new int[] {1234, 0, 0, 0, 0, 0, 0}), }; refValue = rngs[0].next(); for (int i = 1; i < rngs.length; i++) { int value = rngs[i].next(); - assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); + Assertions.assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); } } @Test void testJump() { - RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_JUMP, new Philox4x32()); + RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_JUMP, + new Philox4x32()); } @Test void testLongJump() { - RandomAssert.assertLongJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_LONG_JUMP, new Philox4x32()); + RandomAssert.assertLongJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_LONG_JUMP, + new Philox4x32()); } @Test void testInternalCounter() { - //test of incrementCounter - Philox4x32 rng = new Philox4x32(new int[]{(int) 67280421310721L, (int) (67280421310721L >>> 32), 0xffffffff, 0, 0, 0}); + // Test of counter increment. Note that the value of -1 is all bits set and incrementing + // will carry a 1-bit to the next counter up. + final int key0 = (int) 67280421310721L; + final int key1 = (int) (67280421310721L >>> 32); + + Philox4x32 rng = new Philox4x32(new int[] {key0, key1, -1, 0, 0, 0}); for (int i = 0; i < 4; i++) { rng.next(); } - Philox4x32 rng2 = new Philox4x32(new int[]{(int) 67280421310721L, (int) (67280421310721L >>> 32), 0, 1, 0, 0}); - RandomAssert.assertNextIntEquals(1, rng, rng2); + Philox4x32 rng2 = new Philox4x32(new int[] {key0, key1, 0, 1, 0, 0}); + RandomAssert.assertNextIntEquals(10, rng, rng2); - rng = new Philox4x32(new int[]{(int) 67280421310721L, (int) (67280421310721L >>> 32), 0xffffffff, 0xffffffff, 0, 0}); + rng = new Philox4x32(new int[] {key0, key1, -1, -1, 0, 0}); for (int i = 0; i < 4; i++) { rng.next(); } - rng2 = new Philox4x32(new int[]{(int) 67280421310721L, (int) (67280421310721L >>> 32), 0, 0, 1, 0}); - RandomAssert.assertNextIntEquals(1, rng, rng2); + rng2 = new Philox4x32(new int[] {key0, key1, 0, 0, 1, 0}); + RandomAssert.assertNextIntEquals(10, rng, rng2); - rng = new Philox4x32(new int[]{(int) 67280421310721L, (int) (67280421310721L >>> 32), 0xffffffff, 0xffffffff, 0xffffffff, 0}); + rng = new Philox4x32(new int[] {key0, key1, -1, -1, -1, 0}); for (int i = 0; i < 4; i++) { rng.next(); } - rng2 = new Philox4x32(new int[]{(int) 67280421310721L, (int) (67280421310721L >>> 32), 0, 0, 0, 1}); - RandomAssert.assertNextIntEquals(1, rng, rng2); - } - - @Test - void testLongJumpCounter() { - Philox4x32 rng = new Philox4x32(new int[]{1234, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0}); - rng.longJump(); - Philox4x32 rng2 = new Philox4x32(new int[]{1234, 0, 0xffffffff, 0xffffffff, 0xffffffff, 1}); - RandomAssert.assertNextIntEquals(1, rng, rng2); + rng2 = new Philox4x32(new int[] {key0, key1, 0, 0, 0, 1}); + RandomAssert.assertNextIntEquals(10, rng, rng2); } @Test void testJumpCounter() { - Philox4x32 rng = new Philox4x32(new int[]{1234, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0}); + Philox4x32 rng = new Philox4x32(new int[] {1234, 0, -1, 0, -1, 0}); + rng.jump(); + Philox4x32 rng2 = new Philox4x32(new int[] {1234, 0, -1, 0, 0, 1}); + RandomAssert.assertNextIntEquals(10, rng, rng2); + + rng = new Philox4x32(new int[] {1234, 0, -1, -1, -1, 0}); rng.jump(); - Philox4x32 rng2 = new Philox4x32(new int[]{1234, 0, 0xffffffff, 0xffffffff, 0, 1}); - RandomAssert.assertNextIntEquals(1, rng, rng2); + rng2 = new Philox4x32(new int[] {1234, 0, -1, -1, 0, 1}); + RandomAssert.assertNextLongEquals(10, rng, rng2); } + @Test + void testLongJumpCounter() { + Philox4x32 rng = new Philox4x32(new int[] {1234, 0, -1, -1, -1, 0}); + rng.longJump(); + Philox4x32 rng2 = new Philox4x32(new int[] {1234, 0, -1, -1, -1, 1}); + RandomAssert.assertNextIntEquals(10, rng, rng2); + } } diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/Philox4x64Test.java b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/Philox4x64Test.java index 40523bbc..8fc91957 100644 --- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/Philox4x64Test.java +++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/Philox4x64Test.java @@ -16,23 +16,17 @@ */ package org.apache.commons.rng.core.source64; +import java.util.stream.Stream; import org.apache.commons.rng.core.RandomAssert; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Philox4x64Test { - /* - * Data from python randomgen.philox.Philox(key=1234,number=4,width=32) random_raw() - * https://bashtage.github.io/randomgen/bit_generators/philox.html - */ + // Data from python randomgen.philox.Philox(key=1234,number=4,width=64) random_raw() + // https://bashtage.github.io/randomgen/bit_generators/philox.html private static final long[] EXPECTED_SEQUENCE_1234 = { 6174562084317992592L, -7568142518571726206L, -5685918792241859306L, @@ -108,7 +102,7 @@ public class Philox4x64Test { * * @return the reference data */ - Stream<Arguments> getReferenceData() { + static Stream<Arguments> getReferenceData() { return Stream.of( Arguments.of(new long[]{1234L, 0}, EXPECTED_SEQUENCE_1234), Arguments.of(new long[]{67280421310721L, 0x9E3779B97F4A7C15L}, EXPECTED_SEQUENCE_DEFAULT) @@ -121,6 +115,34 @@ public class Philox4x64Test { RandomAssert.assertEquals(expected, new Philox4x64(seed)); } + @Test + void testConstructors() { + Philox4x64[] rngs = new Philox4x64[]{ + new Philox4x64(), + new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0, 0, 0, 0}), + new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L}), + new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0, 0, 0}), + new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0, 0}), + new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0}) + }; + long refValue = rngs[0].next(); + for (int i = 1; i < rngs.length; i++) { + long value = rngs[i].next(); + Assertions.assertEquals(refValue, value, "Philox4x64 initialization for i=" + i); + } + + rngs = new Philox4x64[]{ + new Philox4x64(new long[]{1234L, 0, 1, 0}), + new Philox4x64(new long[]{1234, 0, 1}), + new Philox4x64(new long[]{1234, 0, 1, 0, 0, 0}), + }; + refValue = rngs[0].next(); + for (int i = 1; i < rngs.length; i++) { + long value = rngs[i].next(); + Assertions.assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); + } + } + @Test void testJump() { RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_JUMP, @@ -129,77 +151,57 @@ public class Philox4x64Test { @Test void testLongJump() { - RandomAssert.assertLongJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_LONG_JUMP, new Philox4x64()); + RandomAssert.assertLongJumpEquals(EXPECTED_SEQUENCE_DEFAULT, EXPECTED_SEQUENCE_AFTER_LONG_JUMP, + new Philox4x64()); } @Test void testInternalCounter() { - //test of incrementCounter - Philox4x64 rng = new Philox4x64(new long[]{67280421310721L, 1234L, 0xffffffffffffffffL, 0, 0, 0}); + // Test of counter increment. Note that the value of -1 is all bits set and incrementing + // will carry a 1-bit to the next counter up. + final long key0 = 67280421310721L; + final long key1 = 1234L; + + Philox4x64 rng = new Philox4x64(new long[] {key0, key1, -1, 0, 0, 0}); for (int i = 0; i < 4; i++) { rng.next(); } - Philox4x64 rng2 = new Philox4x64(new long[]{67280421310721L, 1234L, 0, 1, 0, 0}); - RandomAssert.assertNextLongEquals(1, rng, rng2); + Philox4x64 rng2 = new Philox4x64(new long[] {key0, key1, 0, 1, 0, 0}); + RandomAssert.assertNextLongEquals(10, rng, rng2); - rng = new Philox4x64(new long[]{67280421310721L, 1234L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0, 0}); + rng = new Philox4x64(new long[] {key0, key1, -1, -1, 0, 0}); for (int i = 0; i < 4; i++) { rng.next(); } - rng2 = new Philox4x64(new long[]{67280421310721L, 1234L, 0, 0, 1, 0}); - RandomAssert.assertNextLongEquals(1, rng, rng2); + rng2 = new Philox4x64(new long[] {key0, key1, 0, 0, 1, 0}); + RandomAssert.assertNextLongEquals(10, rng, rng2); - rng = new Philox4x64(new long[]{67280421310721L, 1234L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0}); + rng = new Philox4x64(new long[] {key0, key1, -1, -1, -1, 0}); for (int i = 0; i < 4; i++) { rng.next(); } - rng2 = new Philox4x64(new long[]{67280421310721L, 1234L, 0, 0, 0, 1}); - RandomAssert.assertNextLongEquals(1, rng, rng2); + rng2 = new Philox4x64(new long[] {key0, key1, 0, 0, 0, 1}); + RandomAssert.assertNextLongEquals(10, rng, rng2); } @Test - void testLongJumpCounter() { - Philox4x64 rng = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL, 0, 0xffffffffffffffffL, 0}); + void testJumpCounter() { + Philox4x64 rng = new Philox4x64(new long[] {1234L, 0, -1, 0, -1, 0}); rng.jump(); - Philox4x64 rng2 = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL, 0, 0, 1}); - RandomAssert.assertNextLongEquals(1, rng, rng2); + Philox4x64 rng2 = new Philox4x64(new long[] {1234L, 0, -1, 0, 0, 1}); + RandomAssert.assertNextLongEquals(10, rng, rng2); - rng = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0}); + rng = new Philox4x64(new long[] {1234L, 0, -1, -1, -1, 0}); rng.jump(); - rng2 = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL, 0xffffffffffffffffL, 0, 1}); - RandomAssert.assertNextLongEquals(1, rng, rng2); - - rng = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0}); - rng.longJump(); - rng2 = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 1}); - RandomAssert.assertNextLongEquals(1, rng, rng2); + rng2 = new Philox4x64(new long[] {1234L, 0, -1, -1, 0, 1}); + RandomAssert.assertNextLongEquals(10, rng, rng2); } @Test - void testConstructors() { - Philox4x64[] rngs = new Philox4x64[]{ - new Philox4x64(), - new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0, 0, 0, 0}), - new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L}), - new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0, 0, 0}), - new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0, 0}), - new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0}) - }; - long refValue = rngs[0].next(); - for (int i = 1; i < rngs.length; i++) { - long value = rngs[i].next(); - assertEquals(refValue, value, "Philox4x64 initialization for i=" + i); - } - - rngs = new Philox4x64[]{ - new Philox4x64(new long[]{1234L, 0, 1, 0}), - new Philox4x64(new long[]{1234, 0, 1}), - new Philox4x64(new long[]{1234, 0, 1, 0, 0, 0}), - }; - refValue = rngs[0].next(); - for (int i = 1; i < rngs.length; i++) { - long value = rngs[i].next(); - assertEquals(refValue, value, "Philox4x32 initialization for i=" + i); - } + void testLongJumpCounter() { + Philox4x64 rng = new Philox4x64(new long[] {1234L, 0, -1, -1, -1, 0}); + rng.longJump(); + Philox4x64 rng2 = new Philox4x64(new long[] {1234L, 0, -1, -1, -1, 1}); + RandomAssert.assertNextLongEquals(10, rng, rng2); } } diff --git a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/RandomSourceValues.java b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/RandomSourceValues.java index 0d475d76..6793a048 100644 --- a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/RandomSourceValues.java +++ b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/RandomSourceValues.java @@ -70,8 +70,6 @@ public class RandomSourceValues { "PCG_RXS_M_XS_64", "PCG_MCG_XSH_RR_32", "PCG_MCG_XSH_RS_32", - "PHILOX_4X32", - "PHILOX_4X64", "MSWS", "SFC_32", "SFC_64", @@ -94,7 +92,9 @@ public class RandomSourceValues { "L128_X128_MIX", "L128_X256_MIX", "L128_X1024_MIX", - "L32_X64_MIX"}) + "L32_X64_MIX", + "PHILOX_4X32", + "PHILOX_4X64"}) private String randomSourceName; /** The RandomSource. */ diff --git a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/BaselineSources.java b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/BaselineSources.java index 23b850cb..b7e4648f 100644 --- a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/BaselineSources.java +++ b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/BaselineSources.java @@ -62,8 +62,6 @@ public abstract class BaselineSources { */ @Param({BASELINE, "JDK", - "PHILOX_4X32", - "PHILOX_4X64", "WELL_512_A", "WELL_1024_A", "WELL_19937_A", @@ -116,7 +114,9 @@ public abstract class BaselineSources { "L128_X128_MIX", "L128_X256_MIX", "L128_X1024_MIX", - "L32_X64_MIX"}) + "L32_X64_MIX", + "PHILOX_4X32", + "PHILOX_4X64"}) private String randomSourceName; /** RNG. */ diff --git a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java index 2d005f7d..0576b89d 100644 --- a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java +++ b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java @@ -165,9 +165,7 @@ public class JumpBenchmark { "L128_X1024_MIX", // Requires the LCG to be advanced 2^16 rather than 1 cycle which // can use precomputed coefficients. - "L32_X64_MIX", - "PHILOX_4X32", - "PHILOX_4X64"}) + "L32_X64_MIX"}) private String randomSourceName; diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java index a1845061..f02bf812 100644 --- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java +++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/ProviderBuilder.java @@ -449,6 +449,7 @@ public final class ProviderBuilder { /** Source of randomness is {@link Philox4x64}. */ PHILOX_4X64(Philox4x64 .class, 6, 0, 2, NativeSeedType.LONG_ARRAY); + /** Source type. */ private final Class<? extends UniformRandomProvider> rng; /** Native seed size. Used for array seeds. */
