001package squidpony.squidmath;
002
003import squidpony.StringKit;
004
005import java.io.Serializable;
006
007/**
008 * A RandomnessSource based on PCG-Random that has a single int of state. Its period is extremely short at 2 to the 32,
009 * but its quality over that period is high even though its speed is not especially noteworthy. This generator is not
010 * suitable for GWT; for that you should use {@link Starfish32RNG} or its wrapper {@link GWTRNG} if you need a
011 * StatefulRandomness, {@link Lathe32RNG} if you want optimal speed and don't mind distribution flaws when producing
012 * longs, or {@link Oriole32RNG} or {@link XoshiroStarPhi32RNG} if you need a higher period but don't need
013 * StatefulRandomness' state adjustment methods.
014 * <br>
015 * Quality should be excellent in this version (at least for a generator with so little state) since it's based directly
016 * on PCG-Random's choices of numerical constants. Visual tests, at least, appear indistinguishable from other PRNGs.
017 * Period is very low, at 2 to the 32, but all seeds should be valid, including 0. Generating 64 bits of random data
018 * takes a little less than twice as much time as generating 32 bits, since this can avoid some overhead via inlining.
019 * <br>
020 * The name can be construed as Pint-Size, since this has a small period and uses a smaller amount of space, or as
021 * Permuted Int, since this is based on PermutedRNG, changed to use 32-bit operations on ints.
022 * <br>
023 * Based on work by Melissa E. O'Neill for PCG-Random; some code has been ported more-directly than other sections, but
024 * the foundation for this class would not be possible without O'Neill's work.
025 * <br>
026 * Created by Tommy Ettinger on 11/15/2016.
027 */
028public final class PintRNG implements RandomnessSource, StatefulRandomness, Serializable {
029
030    /** 2 raised to the 53, - 1. */
031    private static final long DOUBLE_MASK = ( 1L << 53 ) - 1;
032    /** 2 raised to the -53. */
033    private static final double NORM_53 = 1. / ( 1L << 53 );
034    /** 2 raised to the 24, -1. */
035    private static final long FLOAT_MASK = ( 1L << 24 ) - 1;
036    /** 2 raised to the -24. */
037    private static final double NORM_24 = 1. / ( 1L << 24 );
038
039    private static final long serialVersionUID = -374415589203474497L;
040
041    public int state; /* The state can be seeded with any value. */
042
043    /** Creates a new generator seeded using Math.random. */
044    public PintRNG() {
045        this((int)((Math.random() - 0.5) * 4.294967296E9));
046    }
047
048    public PintRNG( final long seed ) {
049        setState(seed);
050    }
051
052    public PintRNG(final int a)
053    {
054        state = a;
055    }
056
057    @Override
058    public int next( int bits )
059    {
060        int p = (state = state * 0x2C9277B5 + 0xAC564B05);
061        p ^= p >>> (4 + (p >>> 28));
062        return (((p *= 0x108EF2D9) >>> 22) ^ p) >>> (32 - bits);
063    }
064
065    /**
066     * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer.
067     * @return any int, all 32 bits are random
068     */
069    public int nextInt() {
070        // increment  = 2891336453;
071        // multiplier = 747796405;
072
073//        int p = state;
074//        p ^= p >>> (4 + (p >>> 28));
075//        state = state * 0x2C9277B5 + 0xAC564B05;
076        int p = (state = state * 0x2C9277B5 + 0xAC564B05);
077        p ^= p >>> (4 + (p >>> 28));
078        return ((p *= 0x108EF2D9) >>> 22) ^ p;
079    }
080
081    /**
082     * Can return any long, positive or negative, of any size permissible in a 64-bit signed integer.
083     * Internally, generates two random 32-bit values and combines them into one random long.
084     * @return any long, all 64 bits are random
085     */
086    @Override
087    public long nextLong() {
088        int p = (state = state * 0x2C9277B5 + 0xAC564B05);
089        p ^= p >>> (4 + (p >>> 28));
090        int q = (state = state * 0x2C9277B5 + 0xAC564B05);
091        q ^= q >>> (4 + (q >>> 28));
092        return (((p *= 0x108EF2D9) >>> 22) ^ p) | ((((q *= 0x108EF2D9) >>> 22) ^ q) & 0xffffffffL) << 32;
093    }
094
095    /**
096     * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the
097     * copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to
098     * copy the state so it isn't shared, usually, and produce a new value with the same exact state.
099     *
100     * @return a copy of this RandomnessSource
101     */
102    @Override
103    public PintRNG copy() {
104        return new PintRNG(state);
105    }
106
107    /**
108     * Exclusive on the upper bound.  The lower bound is 0.
109     * <br>
110     * Credit goes to Daniel Lemire, http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
111     * @param bound the upper bound; should be positive
112     * @return a random int less than n and at least equal to 0
113     */
114    public int nextInt( final int bound ) {
115        return (bound <= 0) ? 0 : (int)((bound * (nextInt() & 0x7FFFFFFFL)) >> 31);
116    }
117    /**
118     * Inclusive lower, exclusive upper.
119     * @param lower the lower bound, inclusive, can be positive or negative
120     * @param upper the upper bound, exclusive, should be positive, must be greater than lower
121     * @return a random int at least equal to lower and less than upper
122     */
123    public int nextInt( final int lower, final int upper ) {
124        if ( upper - lower <= 0 ) throw new IllegalArgumentException("Upper bound must be greater than lower bound");
125        return lower + nextInt(upper - lower);
126    }
127
128    /**
129     * Gets a uniform random double in the range [0.0,1.0)
130     * @return a random double at least equal to 0.0 and less than 1.0
131     */
132    public double nextDouble() {
133        return ( nextLong() & DOUBLE_MASK ) * NORM_53;
134    }
135
136    /**
137     * Gets a uniform random double in the range [0.0,outer) given a positive parameter outer. If outer
138     * is negative, it will be the (exclusive) lower bound and 0.0 will be the (inclusive) upper bound.
139     * @param outer the exclusive outer bound, can be negative
140     * @return a random double between 0.0 (inclusive) and outer (exclusive)
141     */
142    public double nextDouble(final double outer) {
143        return nextDouble() * outer;
144    }
145
146    /**
147     * Gets a uniform random float in the range [0.0,1.0)
148     * @return a random float at least equal to 0.0 and less than 1.0
149     */
150    public float nextFloat() {
151        return (float)( ( nextInt() & FLOAT_MASK ) * NORM_24 );
152    }
153
154    /**
155     * Gets a random value, true or false.
156     * Calls nextInt() once.
157     * @return a random true or false value.
158     */
159    public boolean nextBoolean() {
160        return nextInt() > 0;
161    }
162
163    /**
164     * Given a byte array as a parameter, this will fill the array with random bytes (modifying it
165     * in-place). Calls nextInt() {@code Math.ceil(bytes.length / 4.0)} times.
166     * @param bytes a byte array that will have its contents overwritten with random bytes.
167     */
168    public void nextBytes( final byte[] bytes ) {
169        int i = bytes.length, n;
170        while( i != 0 ) {
171            n = Math.min( i, 4 );
172            for ( int bits = nextInt(); n-- != 0; bits >>>= 8 ) bytes[ --i ] = (byte)bits;
173        }
174    }
175
176
177
178    /**
179     * Sets the current state of this generator (an int) using only the least-significant 32 bits of seed (by casting
180     * a mask of those bits in seed to int, which helps ensure that a full 32 bits of state are possible). Giving
181     * int seeds should set the seed to an identical int; long seeds will lose any information in higher bits (including
182     * the sign, so 0xFFFFFFFF00000000L, which is a negative long, would be treated as 0 since only the 0x00000000 part
183     * at the end is actually used).
184     * @param seed the seed to use for this PintRNG, as if it was constructed with this seed.
185     */
186    @Override
187    public void setState( final long seed ) {
188        state = (int)(seed & 0xFFFFFFFFL);
189    }
190    /**
191     * Gets the current state of this generator.
192     * @return the current seed of this PintRNG, changed once per call to nextInt()
193     */
194    @Override
195    public long getState() {
196        return state;
197    }
198
199    @Override
200    public String toString() {
201        return "PintRNG with state 0x" + StringKit.hex(state);
202    }
203
204    @Override
205    public boolean equals(Object o) {
206        if (this == o) return true;
207        if (o == null || getClass() != o.getClass()) return false;
208
209        PintRNG pintRNG = (PintRNG) o;
210
211        return state == pintRNG.state;
212
213    }
214
215    @Override
216    public int hashCode() {
217        return state;
218    }
219    /**
220     * Advances or rolls back the PintRNG's state without actually generating each number. Skip forward
221     * or backward a number of steps specified by advance, where a step is equal to one call to nextInt(),
222     * and returns the random number produced at that step (you can get the state with {@link #getState()}).
223     * <br>
224     * The method used here is based on Brown, "Random Number Generation with Arbitrary Stride,", Transactions of the
225     * American Nuclear Society (Nov. 1994). The code is mostly the same as in PCG-Random's C port by M.E. O'Neill,
226     * specifically <a href="https://github.com/imneme/pcg-c/blob/master/src/pcg-advance-32.c">this file</a>. Skipping
227     * ahead or behind takes more than constant time, unlike with {@link LightRNG}, but less time than calling nextInt()
228     * {@code advance} times. Skipping backwards by one step is the worst case for this.
229     * @param advance Number of future generations to skip past. Can be negative to backtrack.
230     * @return the int that would be generated after generating advance random numbers.
231     */
232    public int skip(int advance)
233    {
234        int acc_mult = 1;
235        int acc_plus = 0;
236        int cur_mult = 0x2C9277B5;
237        int cur_plus = 0xAC564B05;
238        while (advance != 0) {
239            if ((advance & 1) == 1) {
240                acc_mult *= cur_mult;
241                acc_plus = acc_plus * cur_mult + cur_plus;
242            }
243            cur_plus *= (cur_mult + 1);
244            cur_mult *= cur_mult;
245            advance >>>= 1;
246        }
247        int p = (state = acc_mult * state + acc_plus);
248        p ^= p >>> (4 + (p >>> 28));
249        return ((p *= 0x108EF2D9) >>> 22) ^ p;
250    }
251
252    /**
253     * Gets a pseudo-random int that is a permutation of {@code state}, which is an int.
254     * This should normally be called with a technique like
255     * {@code PintRNG.determine(state = state * 0x2C9277B5 + 0xAC564B05)}, where 0xAC564B05 can be changed to any odd
256     * constant as long as it is the same across calls to this. You can effectively produce multiple uncorrelated
257     * streams by adding different constants in place of 0xAC564B05, applied to different states.
258     * @param state any int, but should be updated like {@code state = state * 0x2C9277B5 + 0xAC564B05}, where 0xAC564B05 can be any odd-number constant
259     * @return any int, pseudo-randomly obtained from state
260     */
261    public static int determine(int state)
262    {
263        state ^= state >>> (4 + (state >>> 28));
264        return ((state *= 0x108EF2D9) >>> 22) ^ state;
265    }
266    /**
267     * Like {@link #determine(int)}, gets a pseudo-random int that is a permutation of {@code state}, which is an int.
268     * Unlike determine(), this static method performs an extra step to avoid correlation between similar inputs, such
269     * as 4, 5, and 6, and their outputs. If you already give very distant numbers as subsequent inputs to determine(),
270     * then you should continue to use that method unless you discover issues with correlation; otherwise it's not a bad
271     * idea to default to this method, though it is somewhat slower than determine(). This method is safe to use with
272     * sequential ints, so you can call it with the technique {@code PintRNG.disperse(++state)}, or just use it on int
273     * data as you obtain it to randomize its values.
274     * @param state any int
275     * @return any int, pseudo-randomly obtained from state
276     */
277    public static int disperse(int state)
278    {
279        state = ((state >>> 19 | state << 13) ^ 0x13A5BA1D);
280        state ^= state >>> (4 + (state >>> 28));
281        return ((state *= 0x108EF2D9) >>> 22) ^ state;
282    }
283    public static int determine(final int a, final int b)
284    {
285        int state = a * 0x9E3779B9 + b * 0x85157AF5;
286        state ^= state >>> (4 + (state >>> 28));
287        return ((state *= 0x108EF2D9) >>> 22) ^ state;
288    }
289
290    public static int determineBounded(int state, final int bound)
291    {
292        state ^= state >>> (4 + (state >>> 28));
293        return (int)((bound * ((((state *= 0x108EF2D9) >>> 22) ^ state) & 0x7FFFFFFFL)) >>> 31);
294    }
295    public static int disperseBounded(int state, final int bound)
296    {
297        state = ((state >>> 19 | state << 13) ^ 0x13A5BA1D);
298        state ^= state >>> (4 + (state >>> 28));
299        return (int)((bound * ((((state *= 0x108EF2D9) >>> 22) ^ state) & 0x7FFFFFFFL)) >>> 31);
300    }
301
302}