AbstractXoShiRo512.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 512-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 AbstractXoShiRo512 extends LongProvider implements LongJumpableUniformRandomProvider {
  30.     /** Size of the state vector. */
  31.     private static final int SEED_SIZE = 8;
  32.     /** The coefficients for the jump function. */
  33.     private static final long[] JUMP_COEFFICIENTS = {
  34.         0x33ed89b6e7a353f9L, 0x760083d7955323beL, 0x2837f2fbb5f22faeL, 0x4b8c5674d309511cL,
  35.         0xb11ac47a7ba28c25L, 0xf1be7667092bcc1cL, 0x53851efdb6df0aafL, 0x1ebbc8b23eaf25dbL
  36.     };
  37.     /** The coefficients for the long jump function. */
  38.     private static final long[] LONG_JUMP_COEFFICIENTS = {
  39.         0x11467fef8f921d28L, 0xa2a819f2e79c8ea8L, 0xa8299fc284b3959aL, 0xb4d347340ca63ee1L,
  40.         0x1cb0940bedbff6ceL, 0xd956c5c4fa1f8e17L, 0x915e38fd4eda93bcL, 0x5b3ccdfa5d7daca5L
  41.     };

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

  43.     /** State 0 of the generator. */
  44.     protected long state0;
  45.     /** State 1 of the generator. */
  46.     protected long state1;
  47.     /** State 2 of the generator. */
  48.     protected long state2;
  49.     /** State 3 of the generator. */
  50.     protected long state3;
  51.     /** State 4 of the generator. */
  52.     protected long state4;
  53.     /** State 5 of the generator. */
  54.     protected long state5;
  55.     /** State 6 of the generator. */
  56.     protected long state6;
  57.     /** State 7 of the generator. */
  58.     protected long state7;

  59.     /**
  60.      * Creates a new instance.
  61.      *
  62.      * @param seed Initial seed.
  63.      * If the length is larger than 8, only the first 8 elements will
  64.      * be used; if smaller, the remaining elements will be automatically
  65.      * set. A seed containing all zeros will create a non-functional generator.
  66.      */
  67.     AbstractXoShiRo512(long[] seed) {
  68.         if (seed.length < SEED_SIZE) {
  69.             final long[] state = new long[SEED_SIZE];
  70.             fillState(state, seed);
  71.             setState(state);
  72.         } else {
  73.             setState(seed);
  74.         }
  75.     }

  76.     /**
  77.      * Creates a new instance using an 8 element seed.
  78.      * A seed containing all zeros will create a non-functional generator.
  79.      *
  80.      * @param seed0 Initial seed element 0.
  81.      * @param seed1 Initial seed element 1.
  82.      * @param seed2 Initial seed element 2.
  83.      * @param seed3 Initial seed element 3.
  84.      * @param seed4 Initial seed element 4.
  85.      * @param seed5 Initial seed element 5.
  86.      * @param seed6 Initial seed element 6.
  87.      * @param seed7 Initial seed element 7.
  88.      */
  89.     AbstractXoShiRo512(long seed0, long seed1, long seed2, long seed3,
  90.                        long seed4, long seed5, long seed6, long seed7) {
  91.         state0 = seed0;
  92.         state1 = seed1;
  93.         state2 = seed2;
  94.         state3 = seed3;
  95.         state4 = seed4;
  96.         state5 = seed5;
  97.         state6 = seed6;
  98.         state7 = seed7;
  99.     }

  100.     /**
  101.      * Creates a copy instance.
  102.      *
  103.      * @param source Source to copy.
  104.      */
  105.     protected AbstractXoShiRo512(AbstractXoShiRo512 source) {
  106.         super(source);
  107.         state0 = source.state0;
  108.         state1 = source.state1;
  109.         state2 = source.state2;
  110.         state3 = source.state3;
  111.         state4 = source.state4;
  112.         state5 = source.state5;
  113.         state6 = source.state6;
  114.         state7 = source.state7;
  115.     }

  116.     /**
  117.      * Copies the state from the array into the generator state.
  118.      *
  119.      * @param state the new state
  120.      */
  121.     private void setState(long[] state) {
  122.         state0 = state[0];
  123.         state1 = state[1];
  124.         state2 = state[2];
  125.         state3 = state[3];
  126.         state4 = state[4];
  127.         state5 = state[5];
  128.         state6 = state[6];
  129.         state7 = state[7];
  130.     }

  131.     /** {@inheritDoc} */
  132.     @Override
  133.     protected byte[] getStateInternal() {
  134.         return composeStateInternal(NumberFactory.makeByteArray(
  135.                                         new long[] {state0, state1, state2, state3,
  136.                                                     state4, state5, state6, state7}),
  137.                                     super.getStateInternal());
  138.     }

  139.     /** {@inheritDoc} */
  140.     @Override
  141.     protected void setStateInternal(byte[] s) {
  142.         final byte[][] c = splitStateInternal(s, SEED_SIZE * 8);

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

  144.         super.setStateInternal(c[1]);
  145.     }

  146.     /** {@inheritDoc} */
  147.     @Override
  148.     public long next() {
  149.         final long result = nextOutput();

  150.         final long t = state1 << 11;

  151.         state2 ^= state0;
  152.         state5 ^= state1;
  153.         state1 ^= state2;
  154.         state7 ^= state3;
  155.         state3 ^= state4;
  156.         state4 ^= state5;
  157.         state0 ^= state6;
  158.         state6 ^= state7;

  159.         state6 ^= t;

  160.         state7 = Long.rotateLeft(state7, 21);

  161.         return result;
  162.     }

  163.     /**
  164.      * Use the current state to compute the next output from the generator.
  165.      * The output function shall vary with respect to different generators.
  166.      * This method is called from {@link #next()} before the current state is updated.
  167.      *
  168.      * @return the next output
  169.      */
  170.     protected abstract long nextOutput();

  171.     /**
  172.      * {@inheritDoc}
  173.      *
  174.      * <p>The jump size is the equivalent of 2<sup>256</sup>
  175.      * calls to {@link UniformRandomProvider#nextLong() nextLong()}. It can provide
  176.      * up to 2<sup>256</sup> non-overlapping subsequences.</p>
  177.      */
  178.     @Override
  179.     public UniformRandomProvider jump() {
  180.         final UniformRandomProvider copy = copy();
  181.         performJump(JUMP_COEFFICIENTS);
  182.         return copy;
  183.     }

  184.     /**
  185.      * {@inheritDoc}
  186.      *
  187.      * <p>The jump size is the equivalent of 2<sup>384</sup> calls to
  188.      * {@link UniformRandomProvider#nextLong() nextLong()}. It can provide up to
  189.      * 2<sup>128</sup> non-overlapping subsequences of length 2<sup>384</sup>; each
  190.      * subsequence can provide up to 2<sup>128</sup> non-overlapping subsequences of
  191.      * length 2<sup>256</sup> using the {@link #jump()} method.</p>
  192.      */
  193.     @Override
  194.     public JumpableUniformRandomProvider longJump() {
  195.         final JumpableUniformRandomProvider copy = copy();
  196.         performJump(LONG_JUMP_COEFFICIENTS);
  197.         return copy;
  198.     }
  199.     /**
  200.      * Create a copy.
  201.      *
  202.      * @return the copy
  203.      */
  204.     protected abstract AbstractXoShiRo512 copy();

  205.     /**
  206.      * Perform the jump to advance the generator state. Resets the cached state of the generator.
  207.      *
  208.      * @param jumpCoefficients Jump coefficients.
  209.      */
  210.     private void performJump(long[] jumpCoefficients) {
  211.         long s0 = 0;
  212.         long s1 = 0;
  213.         long s2 = 0;
  214.         long s3 = 0;
  215.         long s4 = 0;
  216.         long s5 = 0;
  217.         long s6 = 0;
  218.         long s7 = 0;
  219.         for (final long jc : jumpCoefficients) {
  220.             for (int b = 0; b < 64; b++) {
  221.                 if ((jc & (1L << b)) != 0) {
  222.                     s0 ^= state0;
  223.                     s1 ^= state1;
  224.                     s2 ^= state2;
  225.                     s3 ^= state3;
  226.                     s4 ^= state4;
  227.                     s5 ^= state5;
  228.                     s6 ^= state6;
  229.                     s7 ^= state7;
  230.                 }
  231.                 next();
  232.             }
  233.         }
  234.         state0 = s0;
  235.         state1 = s1;
  236.         state2 = s2;
  237.         state3 = s3;
  238.         state4 = s4;
  239.         state5 = s5;
  240.         state6 = s6;
  241.         state7 = s7;
  242.         resetCachedState();
  243.     }
  244. }