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
The following commit(s) were added to refs/heads/master by this push:
new e30ab4b9 RNG-188: Add Philox4x32 and Philox4x64 random number
generators (#191)
e30ab4b9 is described below
commit e30ab4b9a618733bdf008cd884e80f665f386673
Author: Jherek Healy <[email protected]>
AuthorDate: Thu Feb 12 13:49:32 2026 +0100
RNG-188: Add Philox4x32 and Philox4x64 random number generators (#191)
Add Philox4x32 and Philox4x64 random number generators.
---
.../commons/rng/core/source32/Philox4x32.java | 325 +++++++++++++++++++++
.../commons/rng/core/source64/Philox4x64.java | 319 ++++++++++++++++++++
.../org/apache/commons/rng/core/ProvidersList.java | 4 +
.../commons/rng/core/source32/Philox4x32Test.java | 188 ++++++++++++
.../commons/rng/core/source64/Philox4x64Test.java | 205 +++++++++++++
.../rng/examples/jmh/RandomSourceValues.java | 2 +
.../rng/examples/jmh/core/BaselineSources.java | 2 +
.../rng/examples/jmh/core/JumpBenchmark.java | 8 +-
.../jmh/core/NextDoubleGenerationPerformance.java | 1 -
.../jmh/simple/ConstructionPerformance.java | 31 ++
.../apache/commons/rng/simple/RandomSource.java | 21 +-
.../rng/simple/internal/ProviderBuilder.java | 12 +-
.../RandomSourceInternalParametricTest.java | 2 +
13 files changed, 1114 insertions(+), 6 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
new file mode 100644
index 00000000..bcfad35d
--- /dev/null
+++
b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/Philox4x32.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rng.core.source32;
+
+import org.apache.commons.rng.JumpableUniformRandomProvider;
+import org.apache.commons.rng.LongJumpableUniformRandomProvider;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.core.util.NumberFactory;
+
+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>
+ * @since 1.7
+ */
+public final class Philox4x32 extends IntProvider implements
LongJumpableUniformRandomProvider {
+ /**
+ * 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.
+ */
+ private static final int K_PHILOX_10_B = 0xBB67AE85;
+ /**
+ * Philox 32-bit constant for key 0.
+ */
+ private static final int K_PHILOX_SA = 0xD2511F53;
+ /**
+ * Philox 32-bit constant for key 1.
+ */
+ private static final int K_PHILOX_SB = 0xCD9E8D57;
+ /**
+ * Internal buffer size.
+ */
+ private static final int PHILOX_BUFFER_SIZE = 4;
+ /**
+ * number of int variables.
+ */
+ private static final int STATE_SIZE = 7;
+
+ /**
+ * Counter 0.
+ */
+ private int counter0;
+ /**
+ * Counter 1.
+ */
+ private int counter1;
+ /**
+ * Counter 2.
+ */
+ private int counter2;
+ /**
+ * Counter 3.
+ */
+ private int counter3;
+ /**
+ * Output point.
+ */
+ private int[] buffer = new int[PHILOX_BUFFER_SIZE]; // UINT4
+ /**
+ * Key low bits.
+ */
+ private int key0;
+ /**
+ * Key high bits.
+ */
+ private int key1;
+ /**
+ * State index: which output word is next (0..3).
+ */
+ private int bufferPosition;
+
+
+ /**
+ * Copy constructor.
+ *
+ * @param source Source to copy.
+ */
+ private Philox4x32(Philox4x32 source) {
+ super(source);
+ counter0 = source.counter0;
+ counter1 = source.counter1;
+ counter2 = source.counter2;
+ counter3 = source.counter3;
+ key0 = source.key0;
+ key1 = source.key1;
+ bufferPosition = source.bufferPosition;
+ buffer = source.buffer.clone();
+ }
+
+ /**
+ * Creates a new instance with default seed. Subsequence and offset (or
equivalently, the internal counter)
+ * are set to zero.
+ */
+ public Philox4x32() {
+ this(67280421310721L);
+ }
+
+ /**
+ * Creates a new instance with a given seed. Subsequence and offset (or
equivalently, the internal counter)
+ * are set to zero.
+ *
+ * @param key the low 32 bits constitute the first int key of Philox,
+ * and the high 32 bits constitute the second int key of Philox
+ */
+ private Philox4x32(long key) {
+ this(new int[]{(int) key, (int) (key >>> 32)});
+ }
+
+ /**
+ * 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 an 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;
+ key0 = input[0];
+ key1 = input[1];
+ counter0 = input[2];
+ counter1 = input[3];
+ counter2 = input[4];
+ counter3 = input[5];
+ bufferPosition = PHILOX_BUFFER_SIZE;
+ }
+
+ /**
+ * Fetch next integer from the buffer, or regenerate the buffer using 10
rounds.
+ *
+ * @return random integer
+ */
+ @Override
+ public int next() {
+ final int p = bufferPosition;
+ if (p < PHILOX_BUFFER_SIZE) {
+ bufferPosition = p + 1;
+ return buffer[p];
+ }
+ incrementCounter();
+ rand10();
+ bufferPosition = 1;
+ return buffer[0];
+ }
+
+ /**
+ * Increment 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.
+ */
+ private void rand10() {
+ buffer[0] = counter0;
+ buffer[1] = counter1;
+ buffer[2] = counter2;
+ buffer[3] = counter3;
+
+ int k0 = key0;
+ int k1 = key1;
+
+ //unrolled loop for performance
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ k0 += K_PHILOX_10_A;
+ k1 += K_PHILOX_10_B;
+ singleRound(buffer, k0, k1);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ *
+ * <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()}.
+ */
+ @Override
+ public JumpableUniformRandomProvider longJump() {
+ final Philox4x32 copy = copy();
+ counter3++;
+ rand10();
+ resetCachedState();
+ return copy;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The jump size is the equivalent of 4*2<sup>64</sup>
+ * calls to {@link UniformRandomProvider#nextInt() nextInt()}.
+ */
+ @Override
+ public UniformRandomProvider jump() {
+ final Philox4x32 copy = copy();
+ if (++counter2 == 0) {
+ counter3++;
+ }
+ rand10();
+ resetCachedState();
+ return copy;
+ }
+
+ /**
+ * {@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 * 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
+ }
+
+ /**
+ * Create a copy.
+ *
+ * @return the copy
+ */
+ private Philox4x32 copy() {
+ return new Philox4x32(this);
+ }
+}
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
new file mode 100644
index 00000000..8cb15e1c
--- /dev/null
+++
b/commons-rng-core/src/main/java/org/apache/commons/rng/core/source64/Philox4x64.java
@@ -0,0 +1,319 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rng.core.source64;
+
+import org.apache.commons.rng.JumpableUniformRandomProvider;
+import org.apache.commons.rng.LongJumpableUniformRandomProvider;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.core.util.NumberFactory;
+
+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>
+ * @since 1.7
+ */
+public final class Philox4x64 extends LongProvider implements
LongJumpableUniformRandomProvider {
+ /**
+ * Philox 32-bit mixing constant for counter 0.
+ */
+ private static final long PHILOX_M0 = 0xD2E7470EE14C6C93L;
+ /**
+ * Philox 32-bit mixing constant for counter 1.
+ */
+ private static final long PHILOX_M1 = 0xCA5A826395121157L;
+ /**
+ * Philox 32-bit constant for key 0.
+ */
+ private static final long PHILOX_W0 = 0x9E3779B97F4A7C15L;
+ /**
+ * Philox 32-bit constant for key 1.
+ */
+ private static final long PHILOX_W1 = 0xBB67AE8584CAA73BL;
+ /**
+ * Internal buffer size.
+ */
+ private static final int PHILOX_BUFFER_SIZE = 4;
+ /**
+ * number of long variables.
+ */
+ private static final int STATE_SIZE = 7;
+
+ /**
+ * Counter 0.
+ */
+ private long counter0;
+ /**
+ * Counter 1.
+ */
+ private long counter1;
+ /**
+ * Counter 2.
+ */
+ private long counter2;
+ /**
+ * Counter 3.
+ */
+ private long counter3;
+
+ /**
+ * Output point.
+ */
+ private long[] buffer = new long[PHILOX_BUFFER_SIZE]; // UINT4
+ /**
+ * Key low bits.
+ */
+ private long key0;
+ /**
+ * Key high bits.
+ */
+ private long key1;
+ /**
+ * State index: which output word is next (0..3).
+ */
+ private int bufferPosition;
+
+ /**
+ * Copy constructor.
+ *
+ * @param source Source to copy.
+ */
+ private Philox4x64(Philox4x64 source) {
+ super(source);
+ counter0 = source.counter0;
+ counter1 = source.counter1;
+ counter2 = source.counter2;
+ counter3 = source.counter3;
+ key0 = source.key0;
+ key1 = source.key1;
+ bufferPosition = source.bufferPosition;
+ buffer = source.buffer.clone();
+ }
+
+ /**
+ * Creates a new instance with default seed. Subsequence and offset are
set to zero.
+ */
+ public Philox4x64() {
+ this(new long[]{67280421310721L, 0x9E3779B97F4A7C15L, 0L, 0L, 0L, 0L});
+ }
+
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Fetch next long from the buffer, or regenerate the buffer using 10
rounds.
+ *
+ * @return random 64-bit integer
+ */
+ private long next64() {
+ final int p = bufferPosition;
+ if (bufferPosition < PHILOX_BUFFER_SIZE) {
+ bufferPosition = p + 1;
+ return buffer[p];
+ }
+ incrementCounter();
+ rand10();
+ bufferPosition = 1;
+ return buffer[0];
+ }
+
+ /**
+ * Increment 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.
+ *
+ */
+ private void rand10() {
+ buffer[0] = counter0;
+ buffer[1] = counter1;
+ buffer[2] = counter2;
+ buffer[3] = counter3;
+
+ long k0 = key0;
+ long k1 = key1;
+
+ //unrolled loop for performance
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ k0 += PHILOX_W0;
+ k1 += PHILOX_W1;
+ singleRound(buffer, k0, k1);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <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()}.
+ */
+ @Override
+ public JumpableUniformRandomProvider longJump() {
+ final Philox4x64 copy = copy();
+ counter3++;
+ rand10();
+ resetCachedState();
+ return copy;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The jump size is the equivalent of 4*2<sup>128</sup>
+ * calls to {@link UniformRandomProvider#nextLong() nextLong()}.
+ */
+ @Override
+ public UniformRandomProvider jump() {
+ final Philox4x64 copy = copy();
+ if (++counter2 == 0) {
+ counter3++;
+ }
+ rand10();
+ resetCachedState();
+ return copy;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @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]);
+ rand10();
+ }
+
+ /**
+ * Create a copy.
+ *
+ * @return the copy
+ */
+ private Philox4x64 copy() {
+ return new Philox4x64(this);
+ }
+}
diff --git
a/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java
b/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java
index 04faee99..47b93928 100644
---
a/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java
+++
b/commons-rng-core/src/test/java/org/apache/commons/rng/core/ProvidersList.java
@@ -23,6 +23,7 @@ import java.security.SecureRandom;
import org.apache.commons.rng.core.source32.JDKRandom;
import org.apache.commons.rng.core.source32.JenkinsSmallFast32;
+import org.apache.commons.rng.core.source32.Philox4x32;
import org.apache.commons.rng.core.source32.Well512a;
import org.apache.commons.rng.core.source32.XoRoShiRo64Star;
import org.apache.commons.rng.core.source32.XoRoShiRo64StarStar;
@@ -45,6 +46,7 @@ import org.apache.commons.rng.core.source32.PcgXshRs32;
import org.apache.commons.rng.core.source32.DotyHumphreySmallFastCounting32;
import org.apache.commons.rng.core.source32.PcgMcgXshRr32;
import org.apache.commons.rng.core.source32.PcgMcgXshRs32;
+import org.apache.commons.rng.core.source64.Philox4x64;
import org.apache.commons.rng.core.source64.SplitMix64;
import org.apache.commons.rng.core.source64.XorShift1024Star;
import org.apache.commons.rng.core.source64.XorShift1024StarPhi;
@@ -130,6 +132,7 @@ public final class ProvidersList {
LIST32.add(new JenkinsSmallFast32(g.nextInt()));
LIST32.add(new XoShiRo128PlusPlus(new int[] {g.nextInt(),
g.nextInt(), g.nextInt()}));
LIST32.add(new L32X64Mix(new int[] {g.nextInt(), g.nextInt()}));
+ LIST32.add(new Philox4x32(new int[] {g.nextInt(), g.nextInt()}));
// ... add more here.
// "long"-based RNGs.
@@ -163,6 +166,7 @@ public final class ProvidersList {
LIST64.add(new L128X128Mix(new long[] {g.nextLong(), g.nextLong(),
g.nextLong(), g.nextLong()}));
LIST64.add(new L128X256Mix(new long[] {g.nextLong(), g.nextLong(),
g.nextLong(), g.nextLong()}));
LIST64.add(new L128X1024Mix(new long[] {g.nextLong(),
g.nextLong(), g.nextLong(), g.nextLong()}));
+ LIST64.add(new Philox4x64(new long[] {g.nextLong(),
g.nextLong()}));
// ... add more here.
// Do not modify the remaining statements.
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
new file mode 100644
index 00000000..1f19c78b
--- /dev/null
+++
b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source32/Philox4x32Test.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.core.source32;
+
+import org.apache.commons.rng.core.RandomAssert;
+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
+ */
+
+ private static final int[] EXPECTED_SEQUENCE_1234 = {
+ -1628512715, 482218876, -98078573, 343858512, 1070188760,
+ -66651592, -870905049, -1994573039, -1238984130, 599211371,
+ 1926069095, -394512546, 346514135, -352142790, 196394741,
+ -107436867, -903274039, 860026475, -1309487194, -1778049224,
+ -49503714, -1441076994, -866074276, -1339523817, -1290919251,
+ 1857369626, -1839251177, -2041498882, -1956330288, 905306810,
+ -2114083635, 200746399, 20291031, 214040874, -1628891823,
+ -1958807646, 9198301, -1607720479, -1349496224, 1418271217
+ };
+
+ private static final int[] EXPECTED_SEQUENCE_DEFAULT = {
+ 623720234, -686991347, 358698524, 234508473, 1303720625,
+ 1235930736, -75297729, 110380616, 829652807, -1101240720,
+ -1443748750, -1366075136, -1702811520, 232450464, 350957237,
+ 1425642103, 256542391, 1837662153, -448554748, 637025846,
+ -902021712, 1085962074, -1391041963, 201580325, 1416828610,
+ 599210676, -628463662, -576572235, 457140358, -1026551805,
+ -917125498, 529387774, 1254882949, 1278069784, 724938314,
+ -4044975, -1211844829, -198846304, 286548119, 2085574084
+ };
+
+ private static final int[] EXPECTED_SEQUENCE_AFTER_JUMP = {
+ -1941342745, 535234737, -1560986946, 1333403881, -467630828,
+ -1212243215, 1924495835, 1889500660, 118588722, -444471278,
+ -984974572, 2134204567, 620921081, -929199568, -44345645,
+ -346841340, -557091335, 1023562906, -1544843001, 2014718360,
+ -186712859, -874952234, -1016908504, 953606755, -1406346322,
+ -1297454974, 1426742334, 1461035068, 206733349, 1606578263,
+ -1354963004, -604654637, 782017623, 1501746828, 853947605,
+ -1380277812, 1855551741, -1023933348, -635058958, 1752530776
+ };
+
+ private static final int[] EXPECTED_SEQUENCE_AFTER_LONG_JUMP = {
+ -643973534, -1464631510, -1204127809, 380399830, 1336312468,
+ 862647039, -970571153, -1473390944, 811398823, -598244991,
+ -1474151641, -1228756553, -166611808, -231601273, -2055417682,
+ -1102476522, 1497124960, 438167652, -657449781, -404513325,
+ -621271837, -10198296, -267651022, -296539606, -1564719261,
+ -652626768, -973911394, 1388361366, 1675611708, -1270745165,
+ -620748722, -1569788343, 831908952, 1873081673, -1058521087,
+ -26171115, -1211556401, -65210719, -1194284085, 1579466740
+ };
+
+ /**
+ * Gets a stream of reference data. Each argument consists of the seed as
a long (first two ints),
+ * and the int array of the expected output from the generator.
+ *
+ * @return the reference data
+ */
+ Stream<Arguments> getReferenceData() {
+ return Stream.of(
+ Arguments.of(1234L, EXPECTED_SEQUENCE_1234),
+ Arguments.of(67280421310721L, EXPECTED_SEQUENCE_DEFAULT)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource(value = "getReferenceData")
+ void testReferenceCode(long seed, int[] expected) {
+ RandomAssert.assertEquals(expected, new Philox4x32(new int[]{(int)
seed, (int) (seed >>> 32)}));
+ }
+
+ @Test
+ void testConstructors() {
+ Philox4x32[] rngs = new Philox4x32[]{
+ new Philox4x32(),
+ new Philox4x32(new int[]{(int) 67280421310721L, (int)
(67280421310721L >>> 32), 0, 0, 0, 0})
+ };
+ 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);
+ }
+ rngs = new Philox4x32[]{
+ 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);
+ }
+ 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}),
+ };
+ 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);
+ }
+ }
+
+ @Test
+ void testJump() {
+ 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());
+ }
+
+ @Test
+ void testInternalCounter() {
+ //test of incrementCounter
+ Philox4x32 rng = new Philox4x32(new int[]{(int) 67280421310721L, (int)
(67280421310721L >>> 32), 0xffffffff, 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);
+
+ rng = new Philox4x32(new int[]{(int) 67280421310721L, (int)
(67280421310721L >>> 32), 0xffffffff, 0xffffffff, 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);
+
+ rng = new Philox4x32(new int[]{(int) 67280421310721L, (int)
(67280421310721L >>> 32), 0xffffffff, 0xffffffff, 0xffffffff, 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);
+ }
+
+ @Test
+ void testJumpCounter() {
+ Philox4x32 rng = new Philox4x32(new int[]{1234, 0, 0xffffffff,
0xffffffff, 0xffffffff, 0});
+ rng.jump();
+ Philox4x32 rng2 = new Philox4x32(new int[]{1234, 0, 0xffffffff,
0xffffffff, 0, 1});
+ RandomAssert.assertNextIntEquals(1, 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
new file mode 100644
index 00000000..40523bbc
--- /dev/null
+++
b/commons-rng-core/src/test/java/org/apache/commons/rng/core/source64/Philox4x64Test.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.core.source64;
+
+import org.apache.commons.rng.core.RandomAssert;
+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
+ */
+
+ private static final long[] EXPECTED_SEQUENCE_1234 = {
+ 6174562084317992592L, -7568142518571726206L, -5685918792241859306L,
+ 6151287208724416091L, -7525285015497232737L, -2526119061336846091L,
+ -2093373494943999176L, 2505686065164099867L, 1493954073060533072L,
+ 2386252059344830309L, -3981277096068706128L, 4825385527958964709L,
+ 5896359280427319232L, 2130638389021018825L, 1001529696243618836L,
+ 6229771985419955916L, -8030183820248387325L, 5924921954534026109L,
+ -2430661683740471500L, -7119094164204651921L, 2451935767711287279L,
+ 8424479353221384040L, -5011970289299902244L, 8792348508803652203L,
+ 9109768561113011588L, 24126314432238277L, -8946976403367747978L,
+ 6224712922535513938L, 8733921062828259483L, 3855129282970288492L,
+ -15371244630355388L, -3103082637265535013L, -5696416329331263984L,
+ -5000982493478729316L, -3077201427991874994L, 4502749081228919907L,
+ 1930363720599024367L, -7884649763770700010L, 9162677665382083018L,
+ -1491083349895074892L
+ };
+
+ private static final long[] EXPECTED_SEQUENCE_DEFAULT = {
+ 7651105821017786633L, -986727441099762072L, -1758232618730818806L,
+ -6892647654339096064L, 2003912625120555464L, 847995992558080923L,
+ 2561190448322591348L, 5089323078274549892L, -6215224099279536444L,
+ 2839273132443259286L, -1538091565590055595L, 2262400997606952131L,
+ 4794890345824897152L, 2654554423835782039L, 5232844452212050618L,
+ 4968309811735346778L, -6677562093502275256L, -2345486924693103657L,
+ 2546479265789531422L, 1397198500311783458L, -3029924206687987745L,
+ 3915450377326980183L, -1798629713529533718L, 7813856890368443409L,
+ -7530219763187390588L, 7752320264114599504L, 4497386005519180400L,
+ 8983526426341050924L, 3157770966203722859L, 6531619948763639990L,
+ -2561361262383382379L, -7341089376366770572L, 5588349311041971766L,
+ -5547961913507498237L, 557535079196835645L, -7564858493373145745L,
+ -5687482083658299050L, -6040393957990987713L, 3376696212464637986L,
+ -4460669316800568753L
+ };
+
+ private static final long[] EXPECTED_SEQUENCE_AFTER_JUMP = {
+ -8246258822028745854L, -8108712508154901372L, 2654408923912105318L,
+ -6418747939867464899L, 8695124057120477387L, -4062778777418832523L,
+ -2866609061902870832L, -1985485291750970064L, -3716513824860297891L,
+ 2708966168515282018L, -8441862438570589384L, -3332504021977608920L,
+ 8275431876927502767L, -37683753608778224L, 4850475723424833501L,
+ -2864632267522668999L, -6547048909303846355L, -6804759155034193445L,
+ -1607076952104749058L, 7993605125443204784L, 7601442483044023354L,
+ -7379694727972198096L, -1902536664833944445L, -908773878773086264L,
+ -7367142976738044337L, 2845297286559921499L, 5398165976383543580L,
+ 2574122219286874876L, 3780790808954139828L, -7038343169285503987L,
+ 1381442423564430946L, -4910467881295472851L, 839863310680617535L,
+ 3700507604505113976L, 2586645934793105407L, 1058068213122536369L,
+ -1876209807038423750L, 8994121856634859944L, 4145729862086221315L,
+ -7214331765643557828L
+ };
+
+ private static final long[] EXPECTED_SEQUENCE_AFTER_LONG_JUMP = {
+ 234199833207670492L, 4847236961490835302L, 4652995647109309910L,
+ -3737386356448340712L, -5273383760715124519L, -3647957810120825499L,
+ 5146817817305263920L, 5710973906845063179L, -1479449555641285865L,
+ 4084674574582715314L, -5547600708256898652L, -4421640461296589483L,
+ -2968992335347510287L, -4790862279320238050L, -2473190691392812606L,
+ 965983568262991078L, 601327440871821012L, 8223565539892887311L,
+ 7546441310634873026L, 2825517271552261878L, 1821450327999942380L,
+ 1829354945050293158L, -4141883204296663957L, 2272925410140103105L,
+ 6950466720264053689L, 942049061182241074L, -423320710605977014L,
+ -7153892430601162036L, -3577327671114607603L, 2251213489013696162L,
+ -869366985991136417L, 6210870867759981069L, 8104504070499194349L,
+ -5828300645374305433L, -8988635423527025878L, 2037830179166981888L,
+ 600555068878135939L, -1046966376945680441L, 9153700819137910983L,
+ 6246833740445288808L
+ };
+
+ /**
+ * Gets a stream of reference data. Each argument consists of the seed as
a long array (first two longs),
+ * and the long array of the expected output from the generator.
+ *
+ * @return the reference data
+ */
+ Stream<Arguments> getReferenceData() {
+ return Stream.of(
+ Arguments.of(new long[]{1234L, 0}, EXPECTED_SEQUENCE_1234),
+ Arguments.of(new long[]{67280421310721L, 0x9E3779B97F4A7C15L},
EXPECTED_SEQUENCE_DEFAULT)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource(value = "getReferenceData")
+ void testReferenceCode(long[] seed, long[] expected) {
+ RandomAssert.assertEquals(expected, new Philox4x64(seed));
+ }
+
+ @Test
+ void testJump() {
+ RandomAssert.assertJumpEquals(EXPECTED_SEQUENCE_DEFAULT,
EXPECTED_SEQUENCE_AFTER_JUMP,
+ new Philox4x64(new long[]{67280421310721L, 0x9E3779B97F4A7C15L}));
+ }
+
+ @Test
+ void testLongJump() {
+ 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});
+ 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);
+
+ rng = new Philox4x64(new long[]{67280421310721L, 1234L,
0xffffffffffffffffL, 0xffffffffffffffffL, 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);
+
+ rng = new Philox4x64(new long[]{67280421310721L, 1234L,
0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 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);
+ }
+
+ @Test
+ void testLongJumpCounter() {
+ Philox4x64 rng = new Philox4x64(new long[]{1234L, 0,
0xffffffffffffffffL, 0, 0xffffffffffffffffL, 0});
+ rng.jump();
+ Philox4x64 rng2 = new Philox4x64(new long[]{1234L, 0,
0xffffffffffffffffL, 0, 0, 1});
+ RandomAssert.assertNextLongEquals(1, rng, rng2);
+
+ rng = new Philox4x64(new long[]{1234L, 0, 0xffffffffffffffffL,
0xffffffffffffffffL, 0xffffffffffffffffL, 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);
+ }
+
+ @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);
+ }
+ }
+}
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 5b0bc5b0..0d475d76 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,6 +70,8 @@ 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",
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 e3b21776..23b850cb 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,6 +62,8 @@ public abstract class BaselineSources {
*/
@Param({BASELINE,
"JDK",
+ "PHILOX_4X32",
+ "PHILOX_4X64",
"WELL_512_A",
"WELL_1024_A",
"WELL_19937_A",
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 1740bd20..2d005f7d 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
@@ -116,7 +116,9 @@ public class JumpBenchmark {
"L128_X128_MIX",
"L128_X256_MIX",
"L128_X1024_MIX",
- "L32_X64_MIX"})
+ "L32_X64_MIX",
+ "PHILOX_4X32",
+ "PHILOX_4X64"})
private String randomSourceName;
/** {@inheritDoc} */
@@ -163,7 +165,9 @@ 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"})
+ "L32_X64_MIX",
+ "PHILOX_4X32",
+ "PHILOX_4X64"})
private String randomSourceName;
diff --git
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/NextDoubleGenerationPerformance.java
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/NextDoubleGenerationPerformance.java
index a474ffc2..545ae199 100644
---
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/NextDoubleGenerationPerformance.java
+++
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/NextDoubleGenerationPerformance.java
@@ -21,7 +21,6 @@ import org.apache.commons.rng.UniformRandomProvider;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
-
/**
* Executes benchmark to compare the speed of generation of random numbers
from the
* various source providers for {@link UniformRandomProvider#nextDouble()}.
diff --git
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ConstructionPerformance.java
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ConstructionPerformance.java
index ac912d85..0cdcf679 100644
---
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ConstructionPerformance.java
+++
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/simple/ConstructionPerformance.java
@@ -42,6 +42,7 @@ import org.apache.commons.rng.core.source32.JDKRandom;
import org.apache.commons.rng.core.source32.KISSRandom;
import org.apache.commons.rng.core.source32.MersenneTwister;
import org.apache.commons.rng.core.source32.MultiplyWithCarry256;
+import org.apache.commons.rng.core.source32.Philox4x32;
import org.apache.commons.rng.core.source32.Well1024a;
import org.apache.commons.rng.core.source32.Well19937a;
import org.apache.commons.rng.core.source32.Well19937c;
@@ -53,6 +54,7 @@ import
org.apache.commons.rng.core.source32.XoRoShiRo64StarStar;
import org.apache.commons.rng.core.source32.XoShiRo128Plus;
import org.apache.commons.rng.core.source32.XoShiRo128StarStar;
import org.apache.commons.rng.core.source64.MersenneTwister64;
+import org.apache.commons.rng.core.source64.Philox4x64;
import org.apache.commons.rng.core.source64.SplitMix64;
import org.apache.commons.rng.core.source64.TwoCmres;
import org.apache.commons.rng.core.source64.XoRoShiRo128Plus;
@@ -301,6 +303,7 @@ public class ConstructionPerformance {
case XO_RO_SHI_RO_64_SS:
case XO_SHI_RO_128_PLUS:
case XO_SHI_RO_128_SS:
+ case PHILOX_4X32:
return INT_ARRAY_SEEDS;
case XOR_SHIFT_1024_S:
case XOR_SHIFT_1024_S_PHI:
@@ -311,6 +314,7 @@ public class ConstructionPerformance {
case XO_SHI_RO_256_SS:
case XO_SHI_RO_512_PLUS:
case XO_SHI_RO_512_SS:
+ case PHILOX_4X64:
return LONG_ARRAY_SEEDS;
default:
throw new AssertionError("Unknown native seed");
@@ -368,6 +372,9 @@ public class ConstructionPerformance {
case XO_SHI_RO_512_PLUS:
case XO_SHI_RO_512_SS:
return 8;
+ case PHILOX_4X32:
+ case PHILOX_4X64:
+ return 6;
default:
throw new AssertionError("Unknown native seed size");
}
@@ -398,6 +405,7 @@ public class ConstructionPerformance {
case XO_RO_SHI_RO_64_SS:
case XO_SHI_RO_128_PLUS:
case XO_SHI_RO_128_SS:
+ case PHILOX_4X32:
return 4; // int
case SPLIT_MIX_64:
case XOR_SHIFT_1024_S:
@@ -409,6 +417,7 @@ public class ConstructionPerformance {
case XO_SHI_RO_256_SS:
case XO_SHI_RO_512_PLUS:
case XO_SHI_RO_512_SS:
+ case PHILOX_4X64:
return 8; // long
default:
throw new AssertionError("Unknown native seed element byte
size");
@@ -450,6 +459,8 @@ public class ConstructionPerformance {
case XO_SHI_RO_256_SS: return
RandomSourceInternal.XO_SHI_RO_256_SS;
case XO_SHI_RO_512_PLUS: return
RandomSourceInternal.XO_SHI_RO_512_PLUS;
case XO_SHI_RO_512_SS: return
RandomSourceInternal.XO_SHI_RO_512_SS;
+ case PHILOX_4X32: return RandomSourceInternal.PHILOX_4X32;
+ case PHILOX_4X64: return RandomSourceInternal.PHILOX_4X64;
default:
throw new AssertionError("Unknown random source internal");
}
@@ -793,6 +804,26 @@ public class ConstructionPerformance {
}
}
+ /**
+ * @param bh Data sink.
+ */
+ @Benchmark
+ public void newPhilox4x32(Blackhole bh) {
+ for (int i = 0; i < SEEDS; i++) {
+ bh.consume(new Philox4x32(INT_ARRAY_SEEDS[i]));
+ }
+ }
+
+ /**
+ * @param bh Data sink.
+ */
+ @Benchmark
+ public void newPhilox4x64(Blackhole bh) {
+ for (int i = 0; i < SEEDS; i++) {
+ bh.consume(new Philox4x64(LONG_ARRAY_SEEDS[i]));
+ }
+ }
+
/**
* Create a new instance using reflection with a cached constructor.
*
diff --git
a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java
b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java
index 2acd77f1..0cb2cc4f 100644
---
a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java
+++
b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/RandomSource.java
@@ -661,7 +661,26 @@ public enum RandomSource {
* </ul>
* @since 1.5
*/
- L32_X64_MIX(ProviderBuilder.RandomSourceInternal.L32_X64_MIX);
+ L32_X64_MIX(ProviderBuilder.RandomSourceInternal.L32_X64_MIX),
+ /**
+ * Source of randomness is {@link
org.apache.commons.rng.core.source32.Philox4x32}.
+ * <ul>
+ * <li>Native seed type: {@code int[]}.</li>
+ * <li>Native seed size: 6.</li>
+ * </ul>
+ * @since 1.7
+ */
+ PHILOX_4X32(ProviderBuilder.RandomSourceInternal.PHILOX_4X32),
+ /**
+ * Source of randomness is {@link
org.apache.commons.rng.core.source64.Philox4x64}.
+ * <ul>
+ * <li>Native seed type: {@code long[]}.</li>
+ * <li>Native seed size: 6.</li>
+ * </ul>
+ * @since 1.7
+ */
+ PHILOX_4X64(ProviderBuilder.RandomSourceInternal.PHILOX_4X64);
+
/** Internal identifier. */
private final ProviderBuilder.RandomSourceInternal internalIdentifier;
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 def9a36b..a1845061 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
@@ -47,6 +47,7 @@ import org.apache.commons.rng.core.source32.PcgMcgXshRs32;
import org.apache.commons.rng.core.source32.DotyHumphreySmallFastCounting32;
import org.apache.commons.rng.core.source32.JenkinsSmallFast32;
import org.apache.commons.rng.core.source32.L32X64Mix;
+import org.apache.commons.rng.core.source32.Philox4x32;
import org.apache.commons.rng.core.source64.SplitMix64;
import org.apache.commons.rng.core.source64.XorShift1024Star;
import org.apache.commons.rng.core.source64.XorShift1024StarPhi;
@@ -74,6 +75,7 @@ import org.apache.commons.rng.core.source64.L64X256Mix;
import org.apache.commons.rng.core.source64.L128X1024Mix;
import org.apache.commons.rng.core.source64.L128X128Mix;
import org.apache.commons.rng.core.source64.L128X256Mix;
+import org.apache.commons.rng.core.source64.Philox4x64;
/**
* RNG builder.
@@ -270,6 +272,7 @@ public final class ProviderBuilder {
PCG_MCG_XSH_RS_32(PcgMcgXshRs32.class,
1,
NativeSeedType.LONG),
+
/** Source of randomness is {@link MiddleSquareWeylSequence}. */
MSWS(MiddleSquareWeylSequence.class,
// Many partially zero seeds can create low quality initial
output.
@@ -439,8 +442,13 @@ public final class ProviderBuilder {
/** Source of randomness is {@link L32X64Mix}. */
L32_X64_MIX(L32X64Mix.class,
4, 2, 4,
- NativeSeedType.INT_ARRAY);
-
+ NativeSeedType.INT_ARRAY),
+ /** Source of randomness is {@link Philox4x32}. */
+ PHILOX_4X32(Philox4x32.class,
+ 6, 0, 2, NativeSeedType.INT_ARRAY),
+ /** 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. */
diff --git
a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/RandomSourceInternalParametricTest.java
b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/RandomSourceInternalParametricTest.java
index f4f5957e..ec312340 100644
---
a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/RandomSourceInternalParametricTest.java
+++
b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/RandomSourceInternalParametricTest.java
@@ -106,6 +106,8 @@ class RandomSourceInternalParametricTest {
EXPECTED_SEED_BYTES.put(RandomSourceInternal.L128_X256_MIX, longBytes
* 8);
EXPECTED_SEED_BYTES.put(RandomSourceInternal.L128_X1024_MIX, longBytes
* 20);
EXPECTED_SEED_BYTES.put(RandomSourceInternal.L32_X64_MIX, intBytes *
4);
+ EXPECTED_SEED_BYTES.put(RandomSourceInternal.PHILOX_4X32, intBytes *
6);
+ EXPECTED_SEED_BYTES.put(RandomSourceInternal.PHILOX_4X64, longBytes *
6);
// ... add more here.
// Verify the seed byte size is reflected in the enum javadoc for
RandomSource.
}