AbstractXoRoShiRo1024.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.rng.core.source64;

  18. import java.util.Arrays;

  19. import org.apache.commons.rng.JumpableUniformRandomProvider;
  20. import org.apache.commons.rng.LongJumpableUniformRandomProvider;
  21. import org.apache.commons.rng.UniformRandomProvider;
  22. import org.apache.commons.rng.core.util.NumberFactory;

  23. /**
  24.  * This abstract class is a base for algorithms from the Xor-Shift-Rotate family of 64-bit
  25.  * generators with 1024-bits of state.
  26.  *
  27.  * @see <a href="http://xoshiro.di.unimi.it/">xorshiro / xoroshiro generators</a>
  28.  * @since 1.3
  29.  */
  30. abstract class AbstractXoRoShiRo1024 extends LongProvider implements LongJumpableUniformRandomProvider {
  31.     /** Size of the state vector. */
  32.     private static final int SEED_SIZE = 16;
  33.     /** The coefficients for the jump function. */
  34.     private static final long[] JUMP_COEFFICIENTS = {
  35.         0x931197d8e3177f17L, 0xb59422e0b9138c5fL, 0xf06a6afb49d668bbL, 0xacb8a6412c8a1401L,
  36.         0x12304ec85f0b3468L, 0xb7dfe7079209891eL, 0x405b7eec77d9eb14L, 0x34ead68280c44e4aL,
  37.         0xe0e4ba3e0ac9e366L, 0x8f46eda8348905b7L, 0x328bf4dbad90d6ffL, 0xc8fd6fb31c9effc3L,
  38.         0xe899d452d4b67652L, 0x45f387286ade3205L, 0x03864f454a8920bdL, 0xa68fa28725b1b384L,
  39.     };
  40.     /** The coefficients for the long jump function. */
  41.     private static final long[] LONG_JUMP_COEFFICIENTS = {
  42.         0x7374156360bbf00fL, 0x4630c2efa3b3c1f6L, 0x6654183a892786b1L, 0x94f7bfcbfb0f1661L,
  43.         0x27d8243d3d13eb2dL, 0x9701730f3dfb300fL, 0x2f293baae6f604adL, 0xa661831cb60cd8b6L,
  44.         0x68280c77d9fe008cL, 0x50554160f5ba9459L, 0x2fc20b17ec7b2a9aL, 0x49189bbdc8ec9f8fL,
  45.         0x92a65bca41852cc1L, 0xf46820dd0509c12aL, 0x52b00c35fbf92185L, 0x1e5b3b7f589e03c1L,
  46.     };
  47.     /** State. */
  48.     private final long[] state = new long[SEED_SIZE];
  49.     /** Index in "state" array. */
  50.     private int index;

  51.     /**
  52.      * Creates a new instance.
  53.      *
  54.      * @param seed Initial seed.
  55.      * If the length is larger than 16, only the first 16 elements will
  56.      * be used; if smaller, the remaining elements will be automatically
  57.      * set. A seed containing all zeros will create a non-functional generator.
  58.      */
  59.     AbstractXoRoShiRo1024(long[] seed) {
  60.         setSeedInternal(seed);
  61.     }

  62.     /**
  63.      * Creates a copy instance.
  64.      *
  65.      * @param source Source to copy.
  66.      */
  67.     protected AbstractXoRoShiRo1024(AbstractXoRoShiRo1024 source) {
  68.         super(source);
  69.         System.arraycopy(source.state, 0, state, 0, SEED_SIZE);
  70.         index = source.index;
  71.     }

  72.     /** {@inheritDoc} */
  73.     @Override
  74.     protected byte[] getStateInternal() {
  75.         final long[] s = Arrays.copyOf(state, SEED_SIZE + 1);
  76.         s[SEED_SIZE] = index;

  77.         return composeStateInternal(NumberFactory.makeByteArray(s),
  78.                                     super.getStateInternal());
  79.     }

  80.     /** {@inheritDoc} */
  81.     @Override
  82.     protected void setStateInternal(byte[] s) {
  83.         final byte[][] c = splitStateInternal(s, (SEED_SIZE + 1) * 8);

  84.         final long[] tmp = NumberFactory.makeLongArray(c[0]);
  85.         System.arraycopy(tmp, 0, state, 0, SEED_SIZE);
  86.         index = (int) tmp[SEED_SIZE];

  87.         super.setStateInternal(c[1]);
  88.     }

  89.     /**
  90.      * Seeds the RNG.
  91.      *
  92.      * @param seed Seed.
  93.      */
  94.     private void setSeedInternal(long[] seed) {
  95.         // Reset the whole state of this RNG (i.e. "state" and "index").
  96.         // Filling procedure is not part of the reference code.
  97.         fillState(state, seed);
  98.         index = 0;
  99.     }

  100.     /** {@inheritDoc} */
  101.     @Override
  102.     public long next() {
  103.         final int q = index;
  104.         index = (index + 1) & 15;
  105.         final long s0 = state[index];
  106.         long s15 = state[q];
  107.         final long result = transform(s0, s15);

  108.         s15 ^= s0;
  109.         state[q] = Long.rotateLeft(s0, 25) ^ s15 ^ (s15 << 27);
  110.         state[index] = Long.rotateLeft(s15, 36);

  111.         return result;
  112.     }

  113.     /**
  114.      * Transform the two consecutive 64-bit states of the generator to a 64-bit output.
  115.      * The transformation function shall vary with respect to different generators.
  116.      *
  117.      * @param s0 The current state.
  118.      * @param s15 The previous state.
  119.      * @return the output
  120.      */
  121.     protected abstract long transform(long s0, long s15);

  122.     /**
  123.      * {@inheritDoc}
  124.      *
  125.      * <p>The jump size is the equivalent of 2<sup>512</sup>
  126.      * calls to {@link UniformRandomProvider#nextLong() nextLong()}. It can provide
  127.      * up to 2<sup>512</sup> non-overlapping subsequences.</p>
  128.      */
  129.     @Override
  130.     public UniformRandomProvider jump() {
  131.         final UniformRandomProvider copy = copy();
  132.         performJump(JUMP_COEFFICIENTS);
  133.         return copy;
  134.     }

  135.     /**
  136.      * {@inheritDoc}
  137.      *
  138.      *
  139.      * <p>The jump size is the equivalent of 2<sup>768</sup> calls to
  140.      * {@link UniformRandomProvider#nextLong() nextLong()}. It can provide up to
  141.      * 2<sup>256</sup> non-overlapping subsequences of length 2<sup>768</sup>; each
  142.      * subsequence can provide up to 2<sup>256</sup> non-overlapping subsequences of
  143.      * length 2<sup>512</sup> using the {@link #jump()} method.</p>
  144.      */
  145.     @Override
  146.     public JumpableUniformRandomProvider longJump() {
  147.         final JumpableUniformRandomProvider copy = copy();
  148.         performJump(LONG_JUMP_COEFFICIENTS);
  149.         return copy;
  150.     }

  151.     /**
  152.      * Create a copy.
  153.      *
  154.      * @return the copy
  155.      */
  156.     protected abstract AbstractXoRoShiRo1024 copy();

  157.     /**
  158.      * Perform the jump to advance the generator state. Resets the cached state of the generator.
  159.      *
  160.      * @param jumpCoefficients the jump coefficients
  161.      */
  162.     private void performJump(long[] jumpCoefficients) {
  163.         final long[] newState = new long[SEED_SIZE];
  164.         for (final long jc : jumpCoefficients) {
  165.             for (int b = 0; b < 64; b++) {
  166.                 if ((jc & (1L << b)) != 0) {
  167.                     for (int i = 0; i < SEED_SIZE; i++) {
  168.                         newState[i] ^= state[(i + index) & 15];
  169.                     }
  170.                 }
  171.                 next();
  172.             }
  173.         }
  174.         // Note: Calling the next() function updates 'index'.
  175.         // The present index effectively becomes 0.
  176.         for (int j = 0; j < 16; j++) {
  177.             state[(j + index) & 15] = newState[j];
  178.         }
  179.         resetCachedState();
  180.     }
  181. }