jherekhealy commented on code in PR #191:
URL: https://github.com/apache/commons-rng/pull/191#discussion_r2788442502


##########
commons-rng-core/src/main/java/org/apache/commons/rng/core/source32/Philox4x32.java:
##########
@@ -0,0 +1,431 @@
+/*
+ * 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;
+
+/**
+ * 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>
+ * for details regarding the engine.
+ * @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 are 
set to zero.
+     */
+    public Philox4x32() {
+        this(67280421310721L, 0L, 0L);
+    }
+
+    /**
+     * Creates a new instance with given seed. Subsequence and offset are set 
to zero.
+     *
+     * @param seed Initial seed.
+     */
+    public Philox4x32(long seed) {
+        this(seed, 0L, 0L);
+    }
+
+    /**
+     * Creates a new instance. Offset and subsequence determine the internal 
counter of Philox.
+     *
+     * @param seed        Initial seed.
+     * @param subsequence a subsequence index
+     * @param offset      an offset, zero for the first number.
+     */
+    public Philox4x32(long seed, long subsequence, long offset) {
+        resetState(seed, subsequence);
+        incrementCounter(offset);
+    }
+
+    /**
+     * Creates a new instance based on an array of int containing, seed, 
subsequence and offset.
+     *
+     * @param seed key0,key1,counter0,counter1,counter2,counter3.
+     */
+    @SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
+    public Philox4x32(int... seed) {
+        key0 = seed[0];
+        if (seed.length > 1) {
+            key1 = seed[1];
+        } else {
+            key1 = 0;
+        }
+        if (seed.length > 2) {
+            counter0 = seed[2];
+        } else {
+            counter0 = 0;
+        }
+        if (seed.length > 3) {
+            counter1 = seed[3];
+        } else {
+            counter1 = 0;
+        }
+        if (seed.length > 4) {
+            counter2 = seed[4];
+        } else {
+            counter2 = 0;
+        }
+        if (seed.length > 5) {
+            counter3 = seed[5];
+        } else {
+            counter3 = 0;
+        }
+        bufferPosition = PHILOX_BUFFER_SIZE;
+    }
+
+    /**
+     * Resets the key, counter and state index.
+     *
+     * @param seed        key for Philox
+     * @param subsequence counter third and fourth ints.
+     */
+    public void resetState(long seed, long subsequence) {
+        key0 = (int) seed;
+        key1 = (int) (seed >>> 32);
+
+        counter0 = 0;
+        counter1 = 0;
+        counter2 = (int) subsequence;
+        counter3 = (int) (subsequence >>> 32);
+
+        bufferPosition = PHILOX_BUFFER_SIZE;
+    }
+
+    /**
+     * Set the first two ints of the internal counter of Philox.
+     *
+     * @param offset an offet. An offet of 1 corresponds to the 4th number of 
the sequence.
+     */
+    public void setOffset(long offset) {
+        counter0 = (int) offset;
+        counter1 = (int) (offset >>> 32);
+        bufferPosition = PHILOX_BUFFER_SIZE;
+    }
+
+    /**
+     * Returns the offset, that is the first two ints of the internal counter 
as a long.
+     *
+     * @return the first two ints of the internal counter of Philox as long.
+     */
+    public long getOffset() {
+        final long lo = counter0 & 0xFFFFFFFFL;
+        final long hi = (counter1 & 0xFFFFFFFFL) << 32;
+        return lo | hi;
+    }
+
+    /**
+     * Fetch next integer from the buffer, or regenerate the buffer using 10 
rounds.
+     *
+     * @return random integer
+     */
+    @Override
+    public int next() {
+        if (bufferPosition < PHILOX_BUFFER_SIZE) {
+            return buffer[bufferPosition++];
+        }
+        incrementCounter();
+        rand10();
+        bufferPosition = 1;
+        return buffer[0];
+    }
+
+    /**
+     * Counter increment.
+     *
+     * @param n how many steps to increment
+     */
+    private void incrementCounter(long n) {
+        final int nlo = (int) n;
+        int nhi = (int) (n >>> 32);
+
+        int old = counter0;
+        counter0 += nlo;
+        if (Integer.compareUnsigned(counter0, old) < 0) {
+            nhi++;
+        }
+
+        old = counter1;
+        counter1 += nhi;
+        if (Integer.compareUnsigned(counter1, old) < 0 && ++counter2 == 0) {
+            counter3++;
+        }
+    }
+
+    /**
+     * 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.
+     *
+     */
+    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>64</sup> calls to
+     * {@link UniformRandomProvider#nextInt() nextInt()}.
+     */
+    @Override
+    public JumpableUniformRandomProvider longJump() {
+        final Philox4x32 copy = copy();
+        if (++counter2 == 0) {
+            counter3++;
+        }
+        rand10();
+        return copy;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The jump size is the equivalent of 4*2<sup>32</sup>
+     * calls to {@link UniformRandomProvider#nextInt() nextInt()}.
+     */
+    @Override
+    public UniformRandomProvider jump() {
+        final Philox4x32 copy = copy();
+        incrementCounter(1L << 32);
+        rand10();
+        resetCachedState();

Review Comment:
   it should indeed be called in both places.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to