001package squidpony.squidmath;
002
003import squidpony.StringKit;
004
005import java.io.Serializable;
006
007/**
008 * An IStatefulRNG implementation that is meant to provide random numbers very quickly when targeting GWT but also to
009 * produce the same numbers when used on desktop, Android, or other platforms, and that can have its state read as a
010 * StatefulRandomness; it is thus like {@link GWTRNG} but should perform better on recent desktop JVMs. This uses a
011 * related algorithm to {@link OrbitRNG}, modified to use 32-bit math and more stringently randomize output. It has two
012 * 32-bit ints for state and a period of 0x10000000000000000 (2 to the 64), while passing 32TB of PractRand tests
013 * without any failures or anomalies (so its quality is very good). It is extremely fast when run on Java 13, at least
014 * using OpenJ9 as the compiler; it can produce a billion ints a second on moderately-recent laptop hardware. A nice
015 * quality of the implementation is that it allows any int for both of its states, so you don't need to check and avoid
016 * setting both states to 0 (which GWTRNG has to do in its internals).
017 * <br>
018 * Internally, this uses two Weyl sequences (counters with different large increments), and rarely but at specific
019 * intervals (when stateA is 0) introduces a lag into one sequence (making stateB keep its value instead of incrementing
020 * for one generated number). A multiplier is taken from the upper bits of stateB and multiplied with a xorshifted
021 * stateA, then part of a unary hash in the style of SplitMix64 is used to improve quality. A particularly devious piece
022 * of bitwise hackery allows this to avoid branching as it decides whether to add the lag or not, and is responsible for
023 * this implementation's high speed.
024 * <br>
025 * The name comes from spider silk, used in a web, and how this is optimized for Google Web Toolkit.
026 * <br>
027 * This was changed on February 29, 2020 to reduce correlation between very similar generators with the same stateA but
028 * different stateB; it still passes 32TB of PractRand without anomalies, but may be slightly slower. The reasoning here
029 * is that users may want to initialize their RNGs in varied ways, and none of those ways should be unexpectedly flawed.
030 * A similar change was applied to TangleRNG, which is much like a 64-bit simplified version of SilkRNG, 4 days later. 
031 * <br>
032 * Written in 2019 by Tommy Ettinger.
033 * @author Tommy Ettinger
034 */
035public final class SilkRNG extends AbstractRNG implements IStatefulRNG, Serializable {
036    private static final long serialVersionUID = 5L;
037
038    public int stateA, stateB;
039
040    /**
041     * Creates a new generator seeded using two calls to Math.random().
042     */
043    public SilkRNG()
044    {
045        setState((int)((Math.random() - 0.5) * 0x1p32), (int)((Math.random() - 0.5) * 0x1p32));
046    }
047    /**
048     * Constructs this SilkRNG by dispersing the bits of seed using {@link #setSeed(int)} across the two parts of state
049     * this has.
050     * @param seed an int that won't be used exactly, but will affect both components of state
051     */
052    public SilkRNG(final int seed) {
053        setSeed(seed);
054    }
055    /**
056     * Constructs this SilkRNG by splitting the given seed across the two parts of state this has with
057     * {@link #setState(long)}.
058     * @param seed a long that will be split across both components of state
059     */
060    public SilkRNG(final long seed) {
061        setState(seed);
062    }
063    /**
064     * Constructs this SilkRNG by calling {@link #setState(int, int)} on stateA and stateB as given; see that method
065     * for the specific details (stateA and stateB are kept as-is).
066     * @param stateA the number to use as the first part of the state
067     * @param stateB the number to use as the second part of the state
068     */
069    public SilkRNG(final int stateA, final int stateB) {
070        setState(stateA, stateB);
071    }
072
073    /**
074     * Hashes {@code seed} using both {@link CrossHash#hash(CharSequence)} and {@link String#hashCode()} and uses those
075     * two results as the two states with {@link #setState(int, int)}. If seed is null, this won't call
076     * String.hashCode() on it and will instead use 0 as that state.
077     * @param seed any String; may be null
078     */
079    public SilkRNG(final String seed) {
080        setState(CrossHash.hash(seed), seed == null ? 0 : seed.hashCode());
081    }
082
083    /**
084     * Get up to 32 bits (inclusive) of random output; the int this produces
085     * will not require more than {@code bits} bits to represent.
086     *
087     * @param bits an int between 1 and 32, both inclusive
088     * @return a random number that fits in the specified number of bits
089     */
090    @Override
091    public final int next(int bits) {
092        final int s = (stateA += 0xC1C64E6D);
093        final int t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
094        int x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
095        x = (x ^ x >>> 16) * 0xAC451;
096        return (x ^ x >>> 15) >>> (32 - bits);
097    }
098
099    /**
100     * Get a random integer between Integer.MIN_VALUE to Integer.MAX_VALUE (both inclusive).
101     *
102     * @return a 32-bit random int.
103     */
104    @Override
105    public final int nextInt() {
106        final int s = (stateA += 0xC1C64E6D); // Weyl sequence, period is 2 to the 32
107        final int t = (stateB += (s | -s) >> 31 & 0x9E3779BB); // updates stateB only when s != 0
108        int x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE); // mix s and t; (xorshifted s) gets multiplied by a negative odd number
109        x = (x ^ x >>> 16) * 0xAC451; // extra strengthening step; multiplier needs to be small for GWT
110        return (x ^ x >>> 15); // closing xorshift to bring the randomizing effect from multiplication to lower bits
111    }
112    /**
113     * Returns a random non-negative integer below the given bound, or 0 if the bound is 0 or
114     * negative.
115     *
116     * @param bound the upper bound (exclusive)
117     * @return the found number
118     */
119    @Override
120    public final int nextInt(final int bound) {
121        final int s = (stateA += 0xC1C64E6D);
122        final int t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
123        int x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
124        x = (x ^ x >>> 16) * 0xAC451;
125        return (int) ((bound * ((x ^ x >>> 15) & 0xFFFFFFFFL)) >>> 32) & ~(bound >> 31);
126    }
127
128    /**
129     * Get a random long between Long.MIN_VALUE to Long.MAX_VALUE (both inclusive).
130     *
131     * @return a 64-bit random long.
132     */
133    @Override
134    public final long nextLong() {
135        int s = (stateA + 0xC1C64E6D);
136        int t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
137        int x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
138        x = (x ^ x >>> 16) * 0xAC451;
139        final long high = (x ^ x >>> 15);
140        s = (stateA += 0x838C9CDA);
141        t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
142        x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
143        x = (x ^ x >>> 16) * 0xAC451;
144        return (high << 32) | ((x ^ x >>> 15) & 0xFFFFFFFFL);
145    }
146
147    /**
148     * Get a random bit of state, interpreted as true or false with approximately equal likelihood.
149     * This implementation uses a sign check as an optimization.
150     *
151     * @return a random boolean.
152     */
153    @Override
154    public final boolean nextBoolean() {
155        final int s = (stateA += 0xC1C64E6D);
156        final int t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
157        return (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE) < 0;
158    }
159
160    /**
161     * Gets a random double between 0.0 inclusive and 1.0 exclusive.
162     * This returns a maximum of 0.9999999999999999 because that is the largest double value that is less than 1.0 .
163     *
164     * @return a double between 0.0 (inclusive) and 0.9999999999999999 (inclusive)
165     */
166    @Override
167    public final double nextDouble() {
168        int s = (stateA + 0xC1C64E6D);
169        int t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
170        int x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
171        x = (x ^ x >>> 16) * 0xAC451;
172        final long high = (x ^ x >>> 15);
173        s = (stateA += 0x838C9CDA);
174        t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
175        x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
176        x = (x ^ x >>> 16) * 0xAC451;
177        return  (((high << 32) | ((x ^ x >>> 15) & 0xFFFFFFFFL))
178                & 0x1FFFFFFFFFFFFFL) * 0x1p-53;
179    }
180
181    /**
182     * Gets a random float between 0.0f inclusive and 1.0f exclusive.
183     * This returns a maximum of 0.99999994 because that is the largest float value that is less than 1.0f .
184     *
185     * @return a float between 0f (inclusive) and 0.99999994f (inclusive)
186     */
187    @Override
188    public final float nextFloat() {
189        final int s = (stateA += 0xC1C64E6D);
190        final int t = (stateB += (s | -s) >> 31 & 0x9E3779BB);
191        int x = (s ^ s >>> 17) * ~((t ^ t >>> 12) & 0x1FFFFE);
192        x = (x ^ x >>> 16) * 0xAC451;
193        return ((x ^ x >>> 15) & 0xffffff) * 0x1p-24f;
194    }
195
196    /**
197     * Creates a copy of this SilkRNG; it will generate the same random numbers, given the same calls in order, as this
198     * SilkRNG at the point copy() is called. The copy will not share references with this SilkRNG.
199     * 
200     * @return a copy of this SilkRNG
201     */
202    @Override
203    public SilkRNG copy() {
204        return new SilkRNG(stateA, stateB);
205    }
206
207    /**
208     * Gets a view of this IRNG in a way that implements {@link Serializable}, which is simply this IRNG.
209     * @return a {@link Serializable} view of this IRNG or a similar one; always {@code this}
210     */
211    @Override
212    public Serializable toSerializable() {
213        return this;
214    }
215    /**
216     * Sets the state of this generator using one int, running it through Zog32RNG's algorithm two times to get 
217     * two ints. If the states would both be 0, state A is assigned 1 instead.
218     * @param seed the int to use to produce this generator's state
219     */
220    public void setSeed(final int seed) {
221        int z = seed + 0xC74EAD55, a = seed ^ z;
222        a ^= a >>> 14;
223        z = (z ^ z >>> 10) * 0xA5CB3;
224        a ^= a >>> 15;
225        stateA = (z ^ z >>> 20) + (a ^= a << 13);
226        z = seed + 0x8E9D5AAA;
227        a ^= a >>> 14;
228        z = (z ^ z >>> 10) * 0xA5CB3;
229        a ^= a >>> 15;
230        stateB = (z ^ z >>> 20) + (a ^ a << 13);
231    }
232
233    public int getStateA()
234    {
235        return stateA;
236    }
237    /**
238     * Sets the first part of the state to the given int.
239     * @param stateA any int
240     */
241
242    public void setStateA(int stateA)
243    {
244        this.stateA = stateA;
245    }
246    public int getStateB()
247    {
248        return stateB;
249    }
250
251    /**
252     * Sets the second part of the state to the given int.
253     * @param stateB any int
254     */
255    public void setStateB(int stateB)
256    {
257        this.stateB = stateB;
258    }
259
260    /**
261     * Sets the current internal state of this SilkRNG with two ints, where stateA and stateB can each be any int.
262     * @param stateA any int
263     * @param stateB any int
264     */
265    public void setState(int stateA, int stateB)
266    {
267        this.stateA = stateA;
268        this.stateB = stateB;
269    }
270
271    /**
272     * Get the current internal state of the StatefulRandomness as a long.
273     *
274     * @return the current internal state of this object.
275     */
276    @Override
277    public long getState() {
278        return stateA & 0xFFFFFFFFL | ((long)stateB) << 32;
279    }
280
281    /**
282     * Set the current internal state of this StatefulRandomness with a long.
283     *
284     * @param state a 64-bit long. You should avoid passing 0; this implementation will treat it as 1.
285     */
286    @Override
287    public void setState(final long state) {
288        stateA = (int)(state & 0xFFFFFFFFL);
289        stateB = (int)(state >>> 32);
290    }
291
292    @Override
293    public boolean equals(Object o) {
294        if (this == o) return true;
295        if (o == null || getClass() != o.getClass()) return false;
296
297        SilkRNG silkRNG = (SilkRNG) o;
298
299        if (stateA != silkRNG.stateA) return false;
300        return stateB == silkRNG.stateB;
301    }
302
303    @Override
304    public int hashCode() {
305        return 31 * stateA + stateB;
306    }
307    
308    @Override
309    public String toString() {
310        return "SilkRNG with stateA 0x" + StringKit.hex(stateA) + " and stateB 0x" + StringKit.hex(stateB);
311    }
312
313    /**
314     * A deterministic random int generator that, given one int {@code state} as input, irreversibly returns an 
315     * almost-always-different int as a result. Unlike the rest of SilkRNG, this will not produce all possible ints given
316     * all ints as inputs, and probably a third of all possible ints cannot be returned. You should call this with
317     * {@code SilkRNG.determineInt(state = state + 1 | 0)} (you can subtract 1 to go backwards instead of forwards),
318     * which will allow overflow in the incremented state to be handled the same on GWT as on desktop.
319     * @param state an int that should go up or down by 1 each call, as with {@code SilkRNG.determineInt(state = state + 1 | 0)} to handle overflow 
320     * @return a not-necessarily-unique int that is usually very different from {@code state}
321     */
322    public static int determineInt(int state) {
323        return (state = ((state = (state ^ 0xD1B54A35) * 0x102473) ^ state >>> 11 ^ state >>> 21) * (state | 0xFFE00001)) ^ state >>> 13 ^ state >>> 19;
324    }
325    
326    /**
327     * A deterministic random int generator that, given one int {@code state} and an outer int {@code bound} as input,
328     * returns an int between 0 (inclusive) and {@code bound} (exclusive) as a result, which should have no noticeable
329     * correlation between {@code state} and the result. You should call this with
330     * {@code SilkRNG.determineBound(state = state + 1 | 0, bound)} (you can subtract 1 to go backwards instead of
331     * forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop.
332     * Like most bounded int generation in SquidLib, this uses some long math, but most of the function uses ints.
333     * @param state an int that should go up or down by 1 each call, as with {@code SilkRNG.determineBounded(state = state + 1 | 0, bound)} to handle overflow
334     * @param bound the outer exclusive bound, as an int; may be positive or negative
335     * @return an int between 0 (inclusive) and {@code bound} (exclusive)
336     */
337    public static int determineBounded(int state, final int bound)
338    {
339        return (int) ((((state = ((state = (state ^ 0xD1B54A35) * 0x102473) ^ state >>> 11 ^ state >>> 21) * (state | 0xFFE00001)) ^ state >>> 13 ^ state >>> 19) & 0xFFFFFFFFL) * bound >> 32);
340    }
341    /**
342     * A deterministic random long generator that, given one int {@code state} as input, returns an 
343     * almost-always-different long as a result. This can only return a tiny fraction of all possible longs, since there
344     * are at most 2 to the 32 possible ints and this doesn't even return different values for each of those. You should
345     * call this with {@code SilkRNG.determine(state = state + 1 | 0)} (you can subtract 1 to go backwards instead of
346     * forwards), which will allow overflow in the incremented state to be handled the same on GWT as on desktop.
347     * @param state an int that should go up or down by 1 each call, as with {@code SilkRNG.determine(state = state + 1 | 0)} to handle overflow 
348     * @return a not-necessarily-unique long that is usually very different from {@code state}
349     */
350    public static long determine(int state)
351    {
352        int r = (state ^ 0xD1B54A35) * 0x102473;
353        return ((long) ((r = (r ^ r >>> 11 ^ r >>> 21) * (r | 0xFFE00001)) ^ r >>> 13 ^ r >>> 19) << 32)
354                | (((state = ((state = (r ^ 0xD1B54A35) * 0x102473) ^ state >>> 11 ^ state >>> 21) * (state | 0xFFE00001)) ^ state >>> 13 ^ state >>> 19) & 0xFFFFFFFFL);
355    }
356    /**
357     * A deterministic random float generator that, given one int {@code state} as input, returns an 
358     * almost-always-different float between 0.0f and 1.0f as a result. Unlike the rest of SilkRNG, this might not
359     * produce all possible floats given all ints as inputs, and some fraction of possible floats cannot be returned.
360     * You should call this with {@code SilkRNG.determineFloat(state = state + 1 | 0)} (you can subtract 1 to go
361     * backwards instead of forwards), which will allow overflow in the incremented state to be handled the same on GWT
362     * as on desktop.
363     * @param state an int that should go up or down by 1 each call, as with {@code SilkRNG.determineFloat(state = state + 1 | 0)} to handle overflow 
364     * @return a not-necessarily-unique float from 0.0f to 1.0f that is usually very different from {@code state}
365     */
366    public static float determineFloat(int state) {
367        return (((state = ((state = (state ^ 0xD1B54A35) * 0x102473) ^ state >>> 11 ^ state >>> 21) * (state | 0xFFE00001)) ^ state >>> 13 ^ state >>> 19) & 0xFFFFFF) * 0x1p-24f;
368    }
369    /**
370     * A deterministic random double generator that, given one int {@code state} as input, returns an 
371     * almost-always-different double between 0.0 and 1.0 as a result. This cannot produce more than a tiny fraction of
372     * all possible doubles because the input is 32 bits and at least 53 bits are needed to represent most doubles from
373     * 0.0 to 1.0. You should call this with {@code SilkRNG.determineDouble(state = state + 1 | 0)} (you can subtract 1
374     * to go backwards instead of forwards), which will allow overflow in the incremented state to be handled the same
375     * on GWT as on desktop.
376     * @param state an int that should go up or down by 1 each call, as with {@code SilkRNG.determineDouble(state = state + 1 | 0)} to handle overflow 
377     * @return a not-necessarily-unique double from 0.0 to 1.0 that is usually very different from {@code state}
378     */
379    public static double determineDouble(int state)
380    {
381        return ((state = ((state = (state ^ 0xD1B54A35) * 0x102473) ^ state >>> 11 ^ state >>> 21) * (state | 0xFFE00001)) ^ state >>> 13 ^ state >>> 19) * 0x1p-32 + 0.5;
382    }
383}