001package squidpony.squidmath;
002
003import squidpony.StringKit;
004
005import java.io.Serializable;
006
007
008/**
009 * A random number generator that is extremely fast but can't return all possible results. ThrustAltRNG passes TestU01's
010 * BigCrush, which is a difficult statistical quality test. On <a href="http://gjrand.sourceforge.net/">gjrand</a>'s
011 * "testunif" checks, this does very well on 100GB of tested data, with the "Overall summary one sided P-value P =
012 * 0.981", where 1 is perfect and 0.1 or less is a failure. On <a href="http://pracrand.sourceforge.net/">PractRand</a>,
013 * this passes all 32TB of generated numbers without finding any failures (and very rarely finding anomalies). Like
014 * {@link LightRNG}, this changes its state with a steady fixed increment, and does hash-like adjustments to the
015 * current state to randomize it (the change is not a cipher because it is not reversible; this may be an advantage
016 * for some usage). The period on ThrustAltRNG is 2 to the 64. ThrustAltRNG is very strong on speed, outpacing the
017 * default generator for {@link RNG}, {@link DiverRNG}, by a small margin, and most other RandomnessSources in
018 * SquidLib by a larger margin (it is slower than {@link MiniMover64RNG}, but this has a better period). Similarly to
019 * other hash-like PRNGs such as {@link LightRNG}, ThrustAltRNG has a {@link #determine(long)} method that takes a state
020 * as a long and returns a deterministic random number (each input has one output, though in this case the reverse isn't
021 * true and some outputs will be returned by multiple inputs). Like LightRNG, but unlike an LCG such as
022 * {@link java.util.Random}, changing the seed even slightly generally produces completely different results, which
023 * applies primarily to determine() but also the first number generated in a series of nextLong() calls. This generator
024 * is GWT-safe but will be much slower on GWT than generators designed for usage there, such as {@link GWTRNG} or
025 * {@link Lathe32RNG}.
026 * <br>
027 * Because this generator can't produce all longs (it is not equidistributed), that alone is enough to discount its use
028 * in some (mainly scientific) scenarios, although it passes all major testing suites (TestU01's BigCrush, PractRand
029 * over the full 32TB of tests, and gjrand to some degree, at least better than most). DiverRNG is the default
030 * generator after ThrustAltRNG was used extensively for some time, since DiverRNG passes the same tests, is almost as
031 * fast, and is known to produce all longs over the course of its period. One small change was required to pass a test
032 * added in PractRand version 0.94, going from a shift of 22 to a shift of 23 at the end of the generation. Without this
033 * change, ThrustAltRNG will eventually fail PractRand (failing "TMFn" tests, which check for patterns like those in a
034 * linear congruential generator such as {@link java.util.Random}), but only after 16TB of data has been analyzed. Even
035 * if using a version before the shift was changed on June 8, 2019, the quality is probably fine.
036 * <br>
037 * There was a ThrustRNG in SquidLib, but it failed statistical tests badly in roughly a minute of testing, so even
038 * though it was faster it probably wasn't a good idea to use it. ThrustAltRNG modifies ThrustRNG's algorithm very
039 * heavily, and isn't especially similar, but the name stuck, I guess. The idea behind the name is that the generator is
040 * acting like a thrust in fencing, pushing quickly but leaving a hole (not in the quality, but in the distribution).
041 * <br>
042 * Created by Tommy Ettinger on 10/18/2017.
043 */
044public final class ThrustAltRNG implements StatefulRandomness, SkippingRandomness, Serializable {
045    private static final long serialVersionUID = 3L;
046    /**
047     * Can be any long value.
048     */
049    public long state;
050
051    /**
052     * Creates a new generator seeded using Math.random.
053     */
054    public ThrustAltRNG() {
055        this((long) ((Math.random() - 0.5) * 0x10000000000000L)
056                ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
057    }
058
059    public ThrustAltRNG(final long seed) {
060        state = seed;
061    }
062
063    /**
064     * Get the current internal state of the StatefulRandomness as a long.
065     *
066     * @return the current internal state of this object.
067     */
068    @Override
069    public long getState() {
070        return state;
071    }
072
073    /**
074     * Set the current internal state of this StatefulRandomness with a long.
075     *
076     * @param state a 64-bit long
077     */
078    @Override
079    public void setState(long state) {
080        this.state = state;
081    }
082
083    /**
084     * Using this method, any algorithm that might use the built-in Java Random
085     * can interface with this randomness source.
086     *
087     * @param bits the number of bits to be returned
088     * @return the integer containing the appropriate number of bits
089     */
090    @Override
091    public final int next(final int bits) {
092        final long s = (state += 0x6C8E9CF570932BD5L);
093        final long z = (s ^ (s >>> 25)) * (s | 0xA529L);
094        return (int)(z ^ (z >>> 23)) >>> (32 - bits);
095    }
096    /**
097     * Using this method, any algorithm that needs to efficiently generate more
098     * than 32 bits of random data can interface with this randomness source.
099     * <p>
100     * Get a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive).
101     *
102     * @return a random long between Long.MIN_VALUE and Long.MAX_VALUE (both inclusive)
103     */
104    @Override
105    public final long nextLong() {
106        final long s = (state += 0x6C8E9CF570932BD5L);
107        final long z = (s ^ (s >>> 25)) * (s | 0xA529L);
108        return z ^ (z >>> 23);
109    }
110
111    /**
112     * Advances or rolls back the ThrustAltRNG's state without actually generating each number. Skips forward
113     * or backward a number of steps specified by advance, where a step is equal to one call to nextLong(),
114     * and returns the random number produced at that step (you can get the state with {@link #getState()}).
115     *
116     * @param advance Number of future generations to skip over; can be negative to backtrack, 0 gets the most-recently-generated number
117     * @return the random long generated after skipping forward or backwards by {@code advance} numbers
118     */
119    @Override
120    public final long skip(long advance) {
121        final long s = (state += 0x6C8E9CF570932BD5L * advance);
122        final long z = (s ^ (s >>> 25)) * (s | 0xA529L);
123        return z ^ (z >>> 23);
124    }
125
126
127    /**
128     * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the
129     * copy, both will generate the same sequence of random numbers from the point copy() was called. This just need to
130     * copy the state so it isn't shared, usually, and produce a new value with the same exact state.
131     *
132     * @return a copy of this RandomnessSource
133     */
134    @Override
135    public ThrustAltRNG copy() {
136        return new ThrustAltRNG(state);
137    }
138    @Override
139    public String toString() {
140        return "ThrustAltRNG with state 0x" + StringKit.hex(state) + 'L';
141    }
142
143    @Override
144    public boolean equals(Object o) {
145        if (this == o) return true;
146        if (o == null || getClass() != o.getClass()) return false;
147
148        ThrustAltRNG thrustAltRNG = (ThrustAltRNG) o;
149
150        return state == thrustAltRNG.state;
151    }
152
153    @Override
154    public int hashCode() {
155        return (int) (state ^ (state >>> 32));
156    }
157
158    /**
159     * Returns a random permutation of state; if state is the same on two calls to this, this will return the same
160     * number. This is expected to be called with some changing variable, e.g. {@code determine(++state)}, where
161     * the increment for state should be odd but otherwise doesn't really matter. This multiplies state by
162     * {@code 0x6C8E9CF570932BD5L} within this method, so using a small increment won't be much different from using a
163     * very large one, as long as it is odd. The period is 2 to the 64 if you increment or decrement by 1.
164     * @param state a variable that should be different every time you want a different random result;
165     *              using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to
166     *              generate numbers in reverse order
167     * @return a pseudo-random permutation of state
168     */
169    public static long determine(long state) {
170        return (state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23);
171    }
172    //for quick one-line pastes of how the algo can be used with "randomize(++state)"
173    //public static long randomize(long state) { return (state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23); }
174
175    /**
176     * Returns a random float that is deterministic based on state; if state is the same on two calls to this, this will
177     * return the same float. This is expected to be called with a changing variable, e.g. {@code determine(++state)},
178     * where the increment for state should be odd but otherwise doesn't really matter. This multiplies state by
179     * {@code 0x6C8E9CF570932BD5L} within this method, so using a small increment won't be much different from using a
180     * very large one, as long as it is odd. The period is 2 to the 64 if you increment or decrement by 1, but there are
181     * only 2 to the 30 possible floats between 0 and 1.
182     * @param state a variable that should be different every time you want a different random result;
183     *              using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to
184     *              generate numbers in reverse order
185     * @return a pseudo-random float between 0f (inclusive) and 1f (exclusive), determined by {@code state}
186     */
187    public static float determineFloat(long state) { return (((state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23)) & 0xFFFFFF) * 0x1p-24f; }
188
189
190    /**
191     * Returns a random double that is deterministic based on state; if state is the same on two calls to this, this
192     * will return the same float. This is expected to be called with a changing variable, e.g.
193     * {@code determine(++state)}, where the increment for state should be odd but otherwise doesn't really matter. This
194     * multiplies state by {@code 0x6C8E9CF570932BD5L} within this method, so using a small increment won't be much
195     * different from using a very large one, as long as it is odd. The period is 2 to the 64 if you increment or
196     * decrement by 1, but there are only 2 to the 62 possible doubles between 0 and 1.
197     * @param state a variable that should be different every time you want a different random result;
198     *              using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to
199     *              generate numbers in reverse order
200     * @return a pseudo-random double between 0.0 (inclusive) and 1.0 (exclusive), determined by {@code state}
201     */
202    public static double determineDouble(long state) { return (((state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23)) & 0x1FFFFFFFFFFFFFL) * 0x1p-53; }
203
204    /**
205     * Given a state that should usually change each time this is called, and a bound that limits the result to some
206     * (typically fairly small) int, produces a pseudo-random int between 0 and bound (exclusive). The bound can be
207     * negative, which will cause this to produce 0 or a negative int; otherwise this produces 0 or a positive int.
208     * The state should change each time this is called, generally by incrementing by an odd number (not an even number,
209     * especially not 0). It's fine to use {@code determineBounded(++state, bound)} to get a different int each time.
210     * The period is usually 2 to the 64 when you increment or decrement by 1, but some bounds may reduce the period (in
211     * the extreme case, a bound of 1 would force only 0 to be generated, so that would make the period 1).
212     * @param state a variable that should be different every time you want a different random result;
213     *              using {@code determineBounded(++state, bound)} is recommended to go forwards or
214     *              {@code determineBounded(--state, bound)} to generate numbers in reverse order
215     * @param bound the outer exclusive bound for the int this produces; can be negative or positive
216     * @return a pseudo-random int between 0 (inclusive) and bound (exclusive)
217     */
218    public static int determineBounded(long state, final int bound)
219    {
220        return (int)((bound * (
221                ((state = ((state *= 0x6C8E9CF570932BD5L) ^ (state >>> 25)) * (state | 0xA529L)) ^ (state >>> 23))
222                        & 0xFFFFFFFFL)) >> 32);
223    }
224
225    /**
226     * Returns a random permutation of state; if state is the same on two calls to this, this will return the same
227     * number. This is expected to be called with some changing variable, e.g. {@code determine(state = state + 1 | 0)},
228     * where the increment for state should be odd but otherwise doesn't really matter (the {@code | 0} is needed to
229     * force overflow to occur correctly on GWT; if you know you won't target GWT you can use {@code determine(++state)}
230     * instead). This multiplies state by {@code 0x62BD5} within this method, so using a small increment won't be
231     * much different from using a very large one, as long as it is odd. The period is 2 to the 32 if you increment or
232     * decrement by 1 (and perform any bitwise operation, such as {@code | 0}, if you might target GWT). If you use this
233     * on GWT and don't perform a bitwise operation on the new value for state, then the period will gradually shrink as
234     * precision is lost by the JavaScript double that GWT will use for state as a Java int. If you know that state will
235     * start at 0 and you call with {@code determine(++state)}, then on GWT you may not have to worry at all until 2 to
236     * the 34 calls have been made, after which state may cease to have the precision to represent an increase by 1 when
237     * the math inside this method is considered. The period will have been exhausted by that point anyway (4 times), so
238     * it's more of a concern if state may start at a much higher int.
239     * <br>
240     * This only uses int math, and should be fast on GWT.
241     * @param state a variable that should be different every time you want a different random result;
242     *              using {@code determine(state = state + 1 | 0)} is recommended to go forwards or
243     *              {@code determine(state = state - 1 | 0)} to generate numbers in reverse order
244     * @return a pseudo-random permutation of state
245     */
246    public static int determineInt(int state) {
247        state = ((state *= 0x62BD5) ^ state >>> 13) * ((state & 0xFFFF8) ^ 0xCD7B5);
248        return ((state << 21) | (state >>> 11)) ^ (((state << 7) | (state >>> 25)) * 0x62BD5);
249    }
250    /**
251     * Given an int state that should usually change each time this is called, and a bound that limits the result to
252     * some (typically fairly small) int, produces a pseudo-random int between 0 and bound (exclusive). The bound should
253     * be between -65536 and 65535, that is, the range of a short. It can be negative, which will cause this to produce
254     * 0 or a negative int; otherwise this produces 0 or a positive int. The state should change each time this is
255     * called, generally by incrementing by an odd number (not an even number, especially not 0). It's fine to use
256     * {@code determineBounded(++state, bound)} to get a different int each time. The period is usually 2 to the 64 when
257     * you increment or decrement by 1, but some bounds may reduce the period (in the extreme case, a bound of 1 would
258     * force only 0 to be generated, so that would make the period 1).
259     * <br>
260     * This only uses int math, unlike other bounded determine() methods, but this requires the bound to be small. It
261     * should be very fast on GWT.
262     * @param state an int variable that should be different every time you want a different random result;
263     *              using {@code determineBounded(++state, bound)} is recommended to go forwards or
264     *              {@code determineBounded(--state, bound)} to generate numbers in reverse order
265     * @param bound the outer exclusive bound for the int this produces; should be between -65536 and 65535, inclusive
266     * @return a pseudo-random int between 0 (inclusive) and bound (exclusive)
267     */
268    public static int determineBoundedShort(int state, final int bound)
269    {
270        state = ((state *= 0x62BD5) ^ state >>> 13) * ((state & 0xFFFF8) ^ 0xCD7B5);
271        return (((((state << 21) | (state >>> 11)) ^ (((state << 7) | (state >>> 25)) * 0x62BD5)) & 0xFFFF) * bound) >> 16;
272    }
273    /**
274     * Returns a random float that is deterministic based on an int state; if state is the same on two calls to this,
275     * this will return the same float. This is expected to be called with a changing variable, e.g.
276     * {@code determine(++state)}, where the increment for state should be odd but otherwise doesn't really matter. This
277     * multiplies state by {@code 0x62BD5} within this method, so using a small increment won't be much different from
278     * using a very large one, as long as it is odd. The period is 2 to the 32 if you increment or decrement by 1, but
279     * there are only 2 to the 30 possible floats between 0 and 1, and this can generate less than 2 to the 24 of them.
280     * <br>
281     * Except for the final conversion to float, this only uses int math, and should be fast on GWT.
282     * @param state an int variable that should be different every time you want a different random result;
283     *              using {@code determine(++state)} is recommended to go forwards or {@code determine(--state)} to
284     *              generate numbers in reverse order
285     * @return a pseudo-random float between 0f (inclusive) and 1f (exclusive), determined by {@code state}
286     */
287    public static float determineFloatFromInt(int state) {
288        state = ((state *= 0x62BD5) ^ state >>> 13) * ((state & 0xFFFF8) ^ 0xCD7B5);
289        return (((state << 21) | (state >>> 11)) ^ (((state << 7) | (state >>> 25)) * 0x62BD5) & 0xFFFFFF) * 0x1p-24f;
290    }
291
292}
293