BaseProvider.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;

  18. import java.util.Arrays;
  19. import org.apache.commons.rng.RestorableUniformRandomProvider;
  20. import org.apache.commons.rng.RandomProviderState;

  21. /**
  22.  * Base class with default implementation for common methods.
  23.  */
  24. public abstract class BaseProvider
  25.     implements RestorableUniformRandomProvider {
  26.     /**
  27.      * The fractional part of the golden ratio, phi, scaled to 64-bits and rounded to odd.
  28.      * <pre>
  29.      * phi = (sqrt(5) - 1) / 2) * 2^64
  30.      * </pre>
  31.      * @see <a href="https://en.wikipedia.org/wiki/Golden_ratio">Golden ratio</a>
  32.      */
  33.     private static final long GOLDEN_RATIO_64 = 0x9e3779b97f4a7c15L;
  34.     /** The fractional part of the golden ratio, phi, scaled to 32-bits and rounded to odd. */
  35.     private static final int GOLDEN_RATIO_32 = 0x9e3779b9;

  36.     /** Create an instance. */
  37.     public BaseProvider() {}

  38.     /** {@inheritDoc} */
  39.     @Override
  40.     public RandomProviderState saveState() {
  41.         return new RandomProviderDefaultState(getStateInternal());
  42.     }

  43.     /** {@inheritDoc} */
  44.     @Override
  45.     public void restoreState(RandomProviderState state) {
  46.         if (state instanceof RandomProviderDefaultState) {
  47.             setStateInternal(((RandomProviderDefaultState) state).getState());
  48.         } else {
  49.             throw new IllegalArgumentException("Foreign instance");
  50.         }
  51.     }

  52.     /** {@inheritDoc} */
  53.     @Override
  54.     public String toString() {
  55.         return getClass().getName();
  56.     }

  57.     /**
  58.      * Combine parent and subclass states.
  59.      * This method must be called by all subclasses in order to ensure
  60.      * that state can be restored in case some of it is stored higher
  61.      * up in the class hierarchy.
  62.      *
  63.      * I.e. the body of the overridden {@link #getStateInternal()},
  64.      * will end with a statement like the following:
  65.      * <pre>
  66.      *  <code>
  67.      *    return composeStateInternal(state,
  68.      *                                super.getStateInternal());
  69.      *  </code>
  70.      * </pre>
  71.      * where {@code state} is the state needed and defined by the class
  72.      * where the method is overridden.
  73.      *
  74.      * @param state State of the calling class.
  75.      * @param parentState State of the calling class' parent.
  76.      * @return the combined state.
  77.      * Bytes that belong to the local state will be stored at the
  78.      * beginning of the resulting array.
  79.      */
  80.     protected byte[] composeStateInternal(byte[] state,
  81.                                           byte[] parentState) {
  82.         final int len = parentState.length + state.length;
  83.         final byte[] c = new byte[len];
  84.         System.arraycopy(state, 0, c, 0, state.length);
  85.         System.arraycopy(parentState, 0, c, state.length, parentState.length);
  86.         return c;
  87.     }

  88.     /**
  89.      * Splits the given {@code state} into a part to be consumed by the caller
  90.      * in order to restore its local state, while the reminder is passed to
  91.      * the parent class.
  92.      *
  93.      * I.e. the body of the overridden {@link #setStateInternal(byte[])},
  94.      * will contain statements like the following:
  95.      * <pre>
  96.      *  <code>
  97.      *    final byte[][] s = splitState(state, localStateLength);
  98.      *    // Use "s[0]" to recover the local state.
  99.      *    super.setStateInternal(s[1]);
  100.      *  </code>
  101.      * </pre>
  102.      * where {@code state} is the combined state of the calling class and of
  103.      * all its parents.
  104.      *
  105.      * @param state State.
  106.      * The local state must be stored at the beginning of the array.
  107.      * @param localStateLength Number of elements that will be consumed by the
  108.      * locally defined state.
  109.      * @return the local state (in slot 0) and the parent state (in slot 1).
  110.      * @throws IllegalStateException if {@code state.length < localStateLength}.
  111.      */
  112.     protected byte[][] splitStateInternal(byte[] state,
  113.                                           int localStateLength) {
  114.         checkStateSize(state, localStateLength);

  115.         final byte[] local = new byte[localStateLength];
  116.         System.arraycopy(state, 0, local, 0, localStateLength);
  117.         final int parentLength = state.length - localStateLength;
  118.         final byte[] parent = new byte[parentLength];
  119.         System.arraycopy(state, localStateLength, parent, 0, parentLength);

  120.         return new byte[][] {local, parent};
  121.     }

  122.     /**
  123.      * Creates a snapshot of the RNG state.
  124.      *
  125.      * @return the internal state.
  126.      */
  127.     protected byte[] getStateInternal() {
  128.         // This class has no state (and is the top-level class that
  129.         // declares this method).
  130.         return new byte[0];
  131.     }

  132.     /**
  133.      * Resets the RNG to the given {@code state}.
  134.      *
  135.      * @param state State (previously obtained by a call to
  136.      * {@link #getStateInternal()}).
  137.      * @throws IllegalStateException if the size of the given array is
  138.      * not consistent with the state defined by this class.
  139.      *
  140.      * @see #checkStateSize(byte[],int)
  141.      */
  142.     protected void setStateInternal(byte[] state) {
  143.         if (state.length != 0) {
  144.             // This class has no state.
  145.             throw new IllegalStateException("State not fully recovered by subclasses");
  146.         }
  147.     }

  148.     /**
  149.      * Simple filling procedure.
  150.      * It will
  151.      * <ol>
  152.      *  <li>
  153.      *   fill the beginning of {@code state} by copying
  154.      *   {@code min(seed.length, state.length)} elements from
  155.      *   {@code seed},
  156.      *  </li>
  157.      *  <li>
  158.      *   set all remaining elements of {@code state} with non-zero
  159.      *   values (even if {@code seed.length < state.length}).
  160.      *  </li>
  161.      * </ol>
  162.      *
  163.      * @param state State. Must be allocated.
  164.      * @param seed Seed. Cannot be null.
  165.      */
  166.     protected void fillState(int[] state,
  167.                              int[] seed) {
  168.         final int stateSize = state.length;
  169.         final int seedSize = seed.length;
  170.         System.arraycopy(seed, 0, state, 0, Math.min(seedSize, stateSize));

  171.         if (seedSize < stateSize) {
  172.             for (int i = seedSize; i < stateSize; i++) {
  173.                 state[i] = (int) (scrambleWell(state[i - seed.length], i) & 0xffffffffL);
  174.             }
  175.         }
  176.     }

  177.     /**
  178.      * Simple filling procedure.
  179.      * It will
  180.      * <ol>
  181.      *  <li>
  182.      *   fill the beginning of {@code state} by copying
  183.      *   {@code min(seed.length, state.length)} elements from
  184.      *   {@code seed},
  185.      *  </li>
  186.      *  <li>
  187.      *   set all remaining elements of {@code state} with non-zero
  188.      *   values (even if {@code seed.length < state.length}).
  189.      *  </li>
  190.      * </ol>
  191.      *
  192.      * @param state State. Must be allocated.
  193.      * @param seed Seed. Cannot be null.
  194.      */
  195.     protected void fillState(long[] state,
  196.                              long[] seed) {
  197.         final int stateSize = state.length;
  198.         final int seedSize = seed.length;
  199.         System.arraycopy(seed, 0, state, 0, Math.min(seedSize, stateSize));

  200.         if (seedSize < stateSize) {
  201.             for (int i = seedSize; i < stateSize; i++) {
  202.                 state[i] = scrambleWell(state[i - seed.length], i);
  203.             }
  204.         }
  205.     }

  206.     /**
  207.      * Checks that the {@code state} has the {@code expected} size.
  208.      *
  209.      * @param state State.
  210.      * @param expected Expected length of {@code state} array.
  211.      * @throws IllegalStateException if {@code state.length < expected}.
  212.      * @deprecated Method is used internally and should be made private in
  213.      * some future release.
  214.      */
  215.     @Deprecated
  216.     protected void checkStateSize(byte[] state,
  217.                                   int expected) {
  218.         if (state.length < expected) {
  219.             throw new IllegalStateException("State size must be larger than " +
  220.                                             expected + " but was " + state.length);
  221.         }
  222.     }

  223.     /**
  224.      * Checks whether {@code index} is in the range {@code [min, max]}.
  225.      *
  226.      * @param min Lower bound.
  227.      * @param max Upper bound.
  228.      * @param index Value that must lie within the {@code [min, max]} interval.
  229.      * @throws IndexOutOfBoundsException if {@code index} is not within the
  230.      * {@code [min, max]} interval.
  231.      */
  232.     protected void checkIndex(int min,
  233.                               int max,
  234.                               int index) {
  235.         if (index < min ||
  236.             index > max) {
  237.             throw new IndexOutOfBoundsException(index + " is out of interval [" +
  238.                                                 min + ", " +
  239.                                                 max + "]");
  240.         }
  241.     }

  242.     /**
  243.      * Transformation used to scramble the initial state of
  244.      * a generator.
  245.      *
  246.      * @param n Seed element.
  247.      * @param mult Multiplier.
  248.      * @param shift Shift.
  249.      * @param add Offset.
  250.      * @return the transformed seed element.
  251.      */
  252.     private static long scramble(long n,
  253.                                  long mult,
  254.                                  int shift,
  255.                                  int add) {
  256.         // Code inspired from "AbstractWell" class.
  257.         return mult * (n ^ (n >> shift)) + add;
  258.     }

  259.     /**
  260.      * Transformation used to scramble the initial state of
  261.      * a generator.
  262.      *
  263.      * @param n Seed element.
  264.      * @param add Offset.
  265.      * @return the transformed seed element.
  266.      * @see #scramble(long,long,int,int)
  267.      */
  268.     private static long scrambleWell(long n,
  269.                                      int add) {
  270.         // Code inspired from "AbstractWell" class.
  271.         return scramble(n, 1812433253L, 30, add);
  272.     }

  273.     /**
  274.      * Extend the seed to the specified minimum length. If the seed is equal or greater than the
  275.      * minimum length, return the same seed unchanged. Otherwise:
  276.      * <ol>
  277.      *  <li>Create a new array of the specified length
  278.      *  <li>Copy all elements of the seed into the array
  279.      *  <li>Fill the remaining values. The additional values will have at most one occurrence
  280.      *   of zero. If the original seed is all zero, the first extended value will be non-zero.
  281.      *  </li>
  282.      * </ol>
  283.      *
  284.      * <p>This method can be used in constructors that must pass their seed to the super class
  285.      * to avoid a duplication of seed expansion to the minimum length required by the super class
  286.      * and the class:
  287.      * <pre>
  288.      * public RNG extends AnotherRNG {
  289.      *     public RNG(long[] seed) {
  290.      *         super(seed = extendSeed(seed, SEED_SIZE));
  291.      *         // Use seed for additional state ...
  292.      *     }
  293.      * }
  294.      * </pre>
  295.      *
  296.      * <p>Note using the state filling procedure provided in {@link #fillState(long[], long[])}
  297.      * is not possible as it is an instance method. Calling a seed extension routine must use a
  298.      * static method.
  299.      *
  300.      * <p>This method functions as if the seed has been extended using a
  301.      * {@link org.apache.commons.rng.core.source64.SplitMix64 SplitMix64}
  302.      * generator seeded with {@code seed[0]}, or zero if the input seed length is zero.
  303.      * <pre>
  304.      * if (seed.length &lt; length) {
  305.      *     final long[] s = Arrays.copyOf(seed, length);
  306.      *     final SplitMix64 rng = new SplitMix64(s[0]);
  307.      *     for (int i = seed.length; i &lt; length; i++) {
  308.      *         s[i] = rng.nextLong();
  309.      *     }
  310.      *     return s;
  311.      * }</pre>
  312.      *
  313.      * @param seed Input seed
  314.      * @param length The minimum length
  315.      * @return the seed
  316.      * @since 1.5
  317.      */
  318.     protected static long[] extendSeed(long[] seed, int length) {
  319.         if (seed.length < length) {
  320.             final long[] s = Arrays.copyOf(seed, length);
  321.             // Fill the rest as if using a SplitMix64 RNG
  322.             long x = s[0];
  323.             for (int i = seed.length; i < length; i++) {
  324.                 x += GOLDEN_RATIO_64;
  325.                 s[i] = stafford13(x);
  326.             }
  327.             return s;
  328.         }
  329.         return seed;
  330.     }

  331.     /**
  332.      * Extend the seed to the specified minimum length. If the seed is equal or greater than the
  333.      * minimum length, return the same seed unchanged. Otherwise:
  334.      * <ol>
  335.      *  <li>Create a new array of the specified length
  336.      *  <li>Copy all elements of the seed into the array
  337.      *  <li>Fill the remaining values. The additional values will have at most one occurrence
  338.      *   of zero. If the original seed is all zero, the first extended value will be non-zero.
  339.      *  </li>
  340.      * </ol>
  341.      *
  342.      * <p>This method can be used in constructors that must pass their seed to the super class
  343.      * to avoid a duplication of seed expansion to the minimum length required by the super class
  344.      * and the class:
  345.      * <pre>
  346.      * public RNG extends AnotherRNG {
  347.      *     public RNG(int[] seed) {
  348.      *         super(seed = extendSeed(seed, SEED_SIZE));
  349.      *         // Use seed for additional state ...
  350.      *     }
  351.      * }
  352.      * </pre>
  353.      *
  354.      * <p>Note using the state filling procedure provided in {@link #fillState(int[], int[])}
  355.      * is not possible as it is an instance method. Calling a seed extension routine must use a
  356.      * static method.
  357.      *
  358.      * <p>This method functions as if the seed has been extended using a
  359.      * {@link org.apache.commons.rng.core.source64.SplitMix64 SplitMix64}-style 32-bit
  360.      * generator seeded with {@code seed[0]}, or zero if the input seed length is zero. The
  361.      * generator uses the 32-bit mixing function from MurmurHash3.
  362.      *
  363.      * @param seed Input seed
  364.      * @param length The minimum length
  365.      * @return the seed
  366.      * @since 1.5
  367.      */
  368.     protected static int[] extendSeed(int[] seed, int length) {
  369.         if (seed.length < length) {
  370.             final int[] s = Arrays.copyOf(seed, length);
  371.             // Fill the rest as if using a SplitMix64-style RNG for 32-bit output
  372.             int x = s[0];
  373.             for (int i = seed.length; i < length; i++) {
  374.                 x += GOLDEN_RATIO_32;
  375.                 s[i] = murmur3(x);
  376.             }
  377.             return s;
  378.         }
  379.         return seed;
  380.     }

  381.     /**
  382.      * Perform variant 13 of David Stafford's 64-bit mix function.
  383.      * This is the mix function used in the
  384.      * {@link org.apache.commons.rng.core.source64.SplitMix64 SplitMix64} RNG.
  385.      *
  386.      * <p>This is ranked first of the top 14 Stafford mixers.
  387.      *
  388.      * <p>This function can be used to mix the bits of a {@code long} value to
  389.      * obtain a better distribution and avoid collisions between similar values.
  390.      *
  391.      * @param x the input value
  392.      * @return the output value
  393.      * @see <a href="https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html">Better
  394.      *      Bit Mixing - Improving on MurmurHash3&#39;s 64-bit Finalizer.</a>
  395.      */
  396.     private static long stafford13(long x) {
  397.         x = (x ^ (x >>> 30)) * 0xbf58476d1ce4e5b9L;
  398.         x = (x ^ (x >>> 27)) * 0x94d049bb133111ebL;
  399.         return x ^ (x >>> 31);
  400.     }

  401.     /**
  402.      * Perform the finalising 32-bit mix function of Austin Appleby's MurmurHash3.
  403.      *
  404.      * <p>This function can be used to mix the bits of a {@code int} value to
  405.      * obtain a better distribution and avoid collisions between similar values.
  406.      *
  407.      * @param x the input value
  408.      * @return the output value
  409.      * @see <a href="https://github.com/aappleby/smhasher">SMHasher</a>
  410.      */
  411.     private static int murmur3(int x) {
  412.         x = (x ^ (x >>> 16)) * 0x85ebca6b;
  413.         x = (x ^ (x >>> 13)) * 0xc2b2ae35;
  414.         return x ^ (x >>> 16);
  415.     }
  416. }