AbstractXoShiRo256.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 org.apache.commons.rng.JumpableUniformRandomProvider;
  19. import org.apache.commons.rng.LongJumpableUniformRandomProvider;
  20. import org.apache.commons.rng.UniformRandomProvider;
  21. import org.apache.commons.rng.core.util.NumberFactory;

  22. /**
  23.  * This abstract class is a base for algorithms from the Xor-Shift-Rotate family of 64-bit
  24.  * generators with 256-bits of state.
  25.  *
  26.  * @see <a href="http://xoshiro.di.unimi.it/">xorshiro / xoroshiro generators</a>
  27.  * @since 1.3
  28.  */
  29. abstract class AbstractXoShiRo256 extends LongProvider implements LongJumpableUniformRandomProvider {
  30.     /** Size of the state vector. */
  31.     private static final int SEED_SIZE = 4;
  32.     /** The coefficients for the jump function. */
  33.     private static final long[] JUMP_COEFFICIENTS = {
  34.         0x180ec6d33cfd0abaL, 0xd5a61266f0c9392cL, 0xa9582618e03fc9aaL, 0x39abdc4529b1661cL
  35.     };
  36.     /** The coefficients for the long jump function. */
  37.     private static final long[] LONG_JUMP_COEFFICIENTS = {
  38.         0x76e15d3efefdcbbfL, 0xc5004e441c522fb3L, 0x77710069854ee241L, 0x39109bb02acbe635L
  39.     };

  40.     // State is maintained using variables rather than an array for performance

  41.     /** State 0 of the generator. */
  42.     protected long state0;
  43.     /** State 1 of the generator. */
  44.     protected long state1;
  45.     /** State 2 of the generator. */
  46.     protected long state2;
  47.     /** State 3 of the generator. */
  48.     protected long state3;

  49.     /**
  50.      * Creates a new instance.
  51.      *
  52.      * @param seed Initial seed.
  53.      * If the length is larger than 4, only the first 4 elements will
  54.      * be used; if smaller, the remaining elements will be automatically
  55.      * set. A seed containing all zeros will create a non-functional generator.
  56.      */
  57.     AbstractXoShiRo256(long[] seed) {
  58.         if (seed.length < SEED_SIZE) {
  59.             final long[] state = new long[SEED_SIZE];
  60.             fillState(state, seed);
  61.             setState(state);
  62.         } else {
  63.             setState(seed);
  64.         }
  65.     }

  66.     /**
  67.      * Creates a new instance using a 4 element seed.
  68.      * A seed containing all zeros will create a non-functional generator.
  69.      *
  70.      * @param seed0 Initial seed element 0.
  71.      * @param seed1 Initial seed element 1.
  72.      * @param seed2 Initial seed element 2.
  73.      * @param seed3 Initial seed element 3.
  74.      */
  75.     AbstractXoShiRo256(long seed0, long seed1, long seed2, long seed3) {
  76.         state0 = seed0;
  77.         state1 = seed1;
  78.         state2 = seed2;
  79.         state3 = seed3;
  80.     }

  81.     /**
  82.      * Creates a copy instance.
  83.      *
  84.      * @param source Source to copy.
  85.      */
  86.     protected AbstractXoShiRo256(AbstractXoShiRo256 source) {
  87.         super(source);
  88.         state0 = source.state0;
  89.         state1 = source.state1;
  90.         state2 = source.state2;
  91.         state3 = source.state3;
  92.     }

  93.     /**
  94.      * Copies the state from the array into the generator state.
  95.      *
  96.      * @param state the new state
  97.      */
  98.     private void setState(long[] state) {
  99.         state0 = state[0];
  100.         state1 = state[1];
  101.         state2 = state[2];
  102.         state3 = state[3];
  103.     }

  104.     /** {@inheritDoc} */
  105.     @Override
  106.     protected byte[] getStateInternal() {
  107.         return composeStateInternal(NumberFactory.makeByteArray(
  108.                                         new long[] {state0, state1, state2, state3}),
  109.                                     super.getStateInternal());
  110.     }

  111.     /** {@inheritDoc} */
  112.     @Override
  113.     protected void setStateInternal(byte[] s) {
  114.         final byte[][] c = splitStateInternal(s, SEED_SIZE * 8);

  115.         setState(NumberFactory.makeLongArray(c[0]));

  116.         super.setStateInternal(c[1]);
  117.     }

  118.     /** {@inheritDoc} */
  119.     @Override
  120.     public long next() {
  121.         final long result = nextOutput();

  122.         final long t = state1 << 17;

  123.         state2 ^= state0;
  124.         state3 ^= state1;
  125.         state1 ^= state2;
  126.         state0 ^= state3;

  127.         state2 ^= t;

  128.         state3 = Long.rotateLeft(state3, 45);

  129.         return result;
  130.     }

  131.     /**
  132.      * Use the current state to compute the next output from the generator.
  133.      * The output function shall vary with respect to different generators.
  134.      * This method is called from {@link #next()} before the current state is updated.
  135.      *
  136.      * @return the next output
  137.      */
  138.     protected abstract long nextOutput();

  139.     /**
  140.      * {@inheritDoc}
  141.      *
  142.      * <p>The jump size is the equivalent of 2<sup>128</sup>
  143.      * calls to {@link UniformRandomProvider#nextLong() nextLong()}. It can provide
  144.      * up to 2<sup>128</sup> non-overlapping subsequences.</p>
  145.      */
  146.     @Override
  147.     public UniformRandomProvider jump() {
  148.         final UniformRandomProvider copy = copy();
  149.         performJump(JUMP_COEFFICIENTS);
  150.         return copy;
  151.     }

  152.     /**
  153.      * {@inheritDoc}
  154.      *
  155.      * <p>The jump size is the equivalent of 2<sup>192</sup> calls to
  156.      * {@link UniformRandomProvider#nextLong() nextLong()}. It can provide up to
  157.      * 2<sup>64</sup> non-overlapping subsequences of length 2<sup>192</sup>; each
  158.      * subsequence can provide up to 2<sup>64</sup> non-overlapping subsequences of
  159.      * length 2<sup>128</sup> using the {@link #jump()} method.</p>
  160.      */
  161.     @Override
  162.     public JumpableUniformRandomProvider longJump() {
  163.         final JumpableUniformRandomProvider copy = copy();
  164.         performJump(LONG_JUMP_COEFFICIENTS);
  165.         return copy;
  166.     }

  167.     /**
  168.      * Create a copy.
  169.      *
  170.      * @return the copy
  171.      */
  172.     protected abstract AbstractXoShiRo256 copy();

  173.     /**
  174.      * Perform the jump to advance the generator state. Resets the cached state of the generator.
  175.      *
  176.      * @param jumpCoefficients Jump coefficients.
  177.      */
  178.     private void performJump(long[] jumpCoefficients) {
  179.         long s0 = 0;
  180.         long s1 = 0;
  181.         long s2 = 0;
  182.         long s3 = 0;
  183.         for (final long jc : jumpCoefficients) {
  184.             for (int b = 0; b < 64; b++) {
  185.                 if ((jc & (1L << b)) != 0) {
  186.                     s0 ^= state0;
  187.                     s1 ^= state1;
  188.                     s2 ^= state2;
  189.                     s3 ^= state3;
  190.                 }
  191.                 next();
  192.             }
  193.         }
  194.         state0 = s0;
  195.         state1 = s1;
  196.         state2 = s2;
  197.         state3 = s3;
  198.         resetCachedState();
  199.     }
  200. }