PcgRxsMXs64.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.core.util.NumberFactory;

  19. /**
  20.  * A Permuted Congruential Generator (PCG) that is composed of a 64-bit Linear Congruential
  21.  * Generator (LCG) combined with the RXS-M-XS (random xorshift; multiply; xorshift) output
  22.  * transformation to create 64-bit output.
  23.  *
  24.  * <p>State size is 128 bits and the period is 2<sup>64</sup>.</p>
  25.  *
  26.  * <p><strong>Note:</strong> Although the seed size is 128 bits, only the first 64 are
  27.  * effective: in effect, two seeds that only differ by the last 64 bits may produce
  28.  * highly correlated sequences.
  29.  *
  30.  * @see <a href="http://www.pcg-random.org/">
  31.  *  PCG, A Family of Better Random Number Generators</a>
  32.  * @since 1.3
  33.  */
  34. public class PcgRxsMXs64 extends LongProvider {
  35.     /** Size of the seed array. */
  36.     private static final int SEED_SIZE = 2;
  37.     /** The default increment. */
  38.     private static final long DEFAULT_INCREMENT = 1442695040888963407L;

  39.     /** The state of the LCG. */
  40.     private long state;

  41.     /** The increment of the LCG. */
  42.     private long increment;

  43.     /**
  44.      * Creates a new instance using a default increment.
  45.      *
  46.      * @param seed Initial state.
  47.      * @since 1.4
  48.      */
  49.     public PcgRxsMXs64(Long seed) {
  50.         increment = DEFAULT_INCREMENT;
  51.         state = bump(seed + this.increment);
  52.     }

  53.     /**
  54.      * Creates a new instance.
  55.      *
  56.      * <p><strong>Note:</strong> Although the seed size is 128 bits, only the first 64 are
  57.      * effective: in effect, two seeds that only differ by the last 64 bits may produce
  58.      * highly correlated sequences.
  59.      *
  60.      * @param seed Initial seed.
  61.      * If the length is larger than 2, only the first 2 elements will
  62.      * be used; if smaller, the remaining elements will be automatically set.
  63.      *
  64.      * <p>The 1st element is used to set the LCG state. The 2nd element is used
  65.      * to set the LCG increment; the most significant bit
  66.      * is discarded by left shift and the increment is set to odd.</p>
  67.      */
  68.     public PcgRxsMXs64(long[] seed) {
  69.         if (seed.length < SEED_SIZE) {
  70.             final long[] tmp = new long[SEED_SIZE];
  71.             fillState(tmp, seed);
  72.             setSeedInternal(tmp);
  73.         } else {
  74.             setSeedInternal(seed);
  75.         }
  76.     }

  77.     /**
  78.      * Seeds the RNG.
  79.      *
  80.      * @param seed Seed.
  81.      */
  82.     private void setSeedInternal(long[] seed) {
  83.         // Ensure the increment is odd to provide a maximal period LCG.
  84.         this.increment = (seed[1] << 1) | 1;
  85.         this.state = bump(seed[0] + this.increment);
  86.     }

  87.     /**
  88.      * Provides the next state of the LCG.
  89.      *
  90.      * @param input Current state.
  91.      * @return next state
  92.      */
  93.     private long bump(long input) {
  94.         return input * 6364136223846793005L + increment;
  95.     }

  96.     /** {@inheritDoc} */
  97.     @Override
  98.     public long next() {
  99.         final long x = state;
  100.         state = bump(state);
  101.         final long word = ((x >>> ((x >>> 59) + 5)) ^ x) * -5840758589994634535L;
  102.         return (word >>> 43) ^ word;
  103.     }

  104.     /** {@inheritDoc} */
  105.     @Override
  106.     protected byte[] getStateInternal() {
  107.         // The increment is divided by 2 before saving.
  108.         // This transform is used in the reference PCG code; it prevents restoring from
  109.         // a byte state a non-odd increment that results in a sub-maximal period generator.
  110.         return composeStateInternal(NumberFactory.makeByteArray(
  111.                 new long[] {state, increment >>> 1}),
  112.                 super.getStateInternal());
  113.     }

  114.     /** {@inheritDoc} */
  115.     @Override
  116.     protected void setStateInternal(byte[] s) {
  117.         final byte[][] c = splitStateInternal(s, SEED_SIZE * 8);
  118.         final long[] tempseed = NumberFactory.makeLongArray(c[0]);
  119.         state = tempseed[0];
  120.         // Reverse the transform performed during getState to make the increment odd again.
  121.         increment = tempseed[1] << 1 | 1;
  122.         super.setStateInternal(c[1]);
  123.     }
  124. }