001/*  Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
002
003To the extent possible under law, the author has dedicated all copyright
004and related and neighboring rights to this software to the public domain
005worldwide. This software is distributed without any warranty.
006
007See <http://creativecommons.org/publicdomain/zero/1.0/>. */
008package squidpony.squidmath;
009
010import squidpony.StringKit;
011
012import java.io.Serializable;
013
014/**
015 * A modification of Blackman and Vigna's xoshiro128 generator with a different "scrambler" than the default; this
016 * generator has four 32-bit states and passes at least 32TB of PractRand (with one "unusual" anomaly at 4TB). It is
017 * four-dimensionally equidistributed, which is an uncommon feature of a PRNG, and means every output is equally likely
018 * not just when one value is generated with {@link #nextInt()}, but also that when up to four 32-bit values are
019 * generated and treated as up to a 128-bit output, then all possible 128-bit outputs are equally likely (with the
020 * exception of the 128-bit value 0x9E3779BD9E3779BD9E3779BD9E3779BD, which won't ever be generated as a group even
021 * though 0x9E3779BD can occur up to three times in four results). The scrambler simply multiplies a state variable by
022 * 31, rotates that value left by 23, and adds a number obtained from the golden ratio, phi (0x9E3779BD). It may have
023 * all sorts of issues since this scrambler hasn't been analyzed much, but 128 bits of state help make most issues less
024 * severe, and the same scrambler works well for xoroshiro with 32-bit states (used in {@link Starfish32RNG}). A
025 * clear known flaw is that if you subtract the same golden-ratio-based number from each result, the resulting modified 
026 * generator will quickly fail binary matrix rank tests. This could be ameliorated by employing a fifth state variable
027 * that increments in a Weyl sequence, which is what {@link Oriole32RNG} does, and adding that instead of the golden
028 * ratio, though this would eliminate the 4-dimensional equidistribution. XoshiroStarPhi32RNG is  optimized for GWT,
029 * like {@link Lathe32RNG} and {@link Starfish32RNG}, which means any non-bitwise math in the source is followed
030 * by bitwise math later, and this sometimes can result in obtuse-looking code along the lines of
031 * {@code int foo = bar + 0x9E3779BD | 0;}.
032 * <br>
033 * This generator seems to be a little faster than xoshiro with the StarStar scrambler, while offering the same period
034 * and distribution. It does not have one group of vulnerabilities held by the "StarStar" scrambler, where multiplying
035 * the result by numbers even somewhat similar to the modulus-2-to-the-32 multiplicative inverse of the last multiplier
036 * used in the StarStar scrambler usually results in a binary rank failure in as little as 512MB of PractRand testing.
037 * As far as I can tell, that failure occurs in the StarStar version whenever the output is reliably multiplied by an
038 * integer where the last byte is 0x39 (or 57 in decimal), additionally affects at least some multipliers that have
039 * their last 7 bits equal to 0b0111001 (the same as in 0x39 before, but requiring only 7 bits to be equivalent), and
040 * this seems to be related to the choice of rotation amount (the StarStar scrambler rotates by 7 places). This
041 * generator does have a different vulnerability when a specific number is subtracted from the output each time (for the
042 * purpose of transparency, 0x9E3779BD). This flaw may occur with similar subtracted numbers as well, probably affecting
043 * any subtrahends with a low Hamming distance from 0x9E3779BD, considering less-significant bits as more relevant to
044 * the distance than more-significant bits.
045 * <br>
046 * <a href="http://xoshiro.di.unimi.it/xoshiro128starstar.c">Original version here for xoshiro128**</a>, by Sebastiano
047 * Vigna and David Blackman.
048 * <br>
049 * Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
050 * StarPhi scrambler written in 2018 by Tommy Ettinger
051 * @author Sebastiano Vigna
052 * @author David Blackman
053 * @author Tommy Ettinger (if there's a flaw, use SquidLib's or Sarong's issues and don't bother Vigna or Blackman, it's probably a mistake in SquidLib's implementation)
054 */
055public final class XoshiroStarPhi32RNG implements RandomnessSource, Serializable {
056
057    private static final long serialVersionUID = 1L;
058
059    private int stateA, stateB, stateC, stateD;
060
061    /**
062     * Creates a new generator seeded using four calls to Math.random().
063     */
064    public XoshiroStarPhi32RNG() {
065        setState((int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000),
066                (int)((Math.random() * 2.0 - 1.0) * 0x80000000), (int)((Math.random() * 2.0 - 1.0) * 0x80000000));
067    }
068    /**
069     * Constructs this XoshiroStarPhi32RNG by dispersing the bits of seed using {@link #setSeed(int)} across the four
070     * parts of state this has.
071     * @param seed an int that won't be used exactly, but will affect all components of state
072     */
073    public XoshiroStarPhi32RNG(final int seed) {
074        setSeed(seed);
075    }
076    /**
077     * Constructs this XoshiroStarPhi32RNG by dispersing the bits of seed using {@link #setSeed(long)} across the four
078     * parts of state this has.
079     * @param seed a long that will be split across all components of state
080     */
081    public XoshiroStarPhi32RNG(final long seed) {
082        setSeed(seed);
083    }
084    /**
085     * Constructs this XoshiroStarPhi32RNG by calling {@link #setState(int, int, int, int)} on stateA and stateB as
086     * given; see that method for the specific details (the states are kept as-is unless they are all 0).
087     * @param stateA the number to use as the first part of the state; this will be 1 instead if both seeds are 0
088     * @param stateB the number to use as the second part of the state
089     * @param stateC the number to use as the third part of the state
090     * @param stateD the number to use as the fourth part of the state
091     */
092    public XoshiroStarPhi32RNG(final int stateA, final int stateB, final int stateC, final int stateD) {
093        setState(stateA, stateB, stateC, stateD);
094    }
095
096    @Override
097    public final int next(int bits) {
098        final int result = stateB * 31;         
099        final int t = stateB << 9;
100        stateC ^= stateA;
101        stateD ^= stateB;
102        stateB ^= stateC;
103        stateA ^= stateD;
104        stateC ^= t;
105        stateD = (stateD << 11 | stateD >>> 21);
106        return (result << 23 | result >>> 9) + 0x9E3779BD >>> (32 - bits);
107    }
108
109    /**
110     * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer.
111     * @return any int, all 32 bits are random
112     */
113    public final int nextInt() {
114        final int result = stateB * 31;
115        final int t = stateB << 9;
116        stateC ^= stateA;
117        stateD ^= stateB;
118        stateB ^= stateC;
119        stateA ^= stateD;
120        stateC ^= t;
121        stateD = (stateD << 11 | stateD >>> 21);
122        return (result << 23 | result >>> 9) + 0x9E3779BD | 0;
123    }
124
125    @Override
126    public final long nextLong() {
127        int result = stateB * 31;
128        int t = stateB << 9;
129        stateC ^= stateA;
130        stateD ^= stateB;
131        stateB ^= stateC;
132        stateA ^= stateD;
133        stateC ^= t;
134        long high = (result << 23 | result >>> 9) + 0x9E3779BD;
135        stateD = (stateD << 11 | stateD >>> 21);
136        result = stateB * 31;
137        t = stateB << 9;
138        stateC ^= stateA;
139        stateD ^= stateB;
140        stateB ^= stateC;
141        stateA ^= stateD;
142        stateC ^= t;
143        stateD = (stateD << 11 | stateD >>> 21);
144        return high << 32 ^ ((result << 23 | result >>> 9) + 0x9E3779BD);
145    }
146
147    /**
148     * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the
149     * copy, both will generate the same sequence of random numbers from the point copy() was called. This just needs to
150     * copy the state so it isn't shared, usually, and produce a new value with the same exact state.
151     *
152     * @return a copy of this RandomnessSource
153     */
154    @Override
155    public XoshiroStarPhi32RNG copy() {
156        return new XoshiroStarPhi32RNG(stateA, stateB, stateC, stateD);
157    }
158
159    /**
160     * Sets the state of this generator using one int, running it through a GWT-compatible variant of SplitMix32 four
161     * times to get four ints of state, all guaranteed to be different.
162     * @param seed the int to use to produce this generator's states
163     */
164    public void setSeed(final int seed) {
165        int z = seed + 0xC74EAD55;
166        z = (z ^ (z >>> 16)) * 0x85A6B;
167        z = (z ^ (z >>> 13)) * 0xCAE35;
168        stateA = z ^ (z >>> 16);
169        z = seed + 0x8E9D5AAA;
170        z = (z ^ (z >>> 16)) * 0x85A6B;
171        z = (z ^ (z >>> 13)) * 0xCAE35;
172        stateB = z ^ (z >>> 16);
173        z = seed + 0x55EC07FF;
174        z = (z ^ (z >>> 16)) * 0x85A6B;
175        z = (z ^ (z >>> 13)) * 0xCAE35;
176        stateC = z ^ (z >>> 16);
177        z = seed + 0x1D3AB554;
178        z = (z ^ (z >>> 16)) * 0x85A6B;
179        z = (z ^ (z >>> 13)) * 0xCAE35;
180        stateD = z ^ (z >>> 16);
181    }
182
183    /**
184     * Sets the state of this generator using one long, running it through a GWT-compatible variant of SplitMix32 four
185     * times to get four ints of state, guaranteed to repeat a state no more than two times.
186     * @param seed the long to use to produce this generator's states
187     */
188    public void setSeed(final long seed) {
189        int z = (int)((seed & 0xFFFFFFFFL) + 0xC74EAD55);
190        z = (z ^ (z >>> 16)) * 0x85A6B;
191        z = (z ^ (z >>> 13)) * 0xCAE35;
192        stateA = z ^ (z >>> 16);
193        z = (int)((seed & 0xFFFFFFFFL) + 0x8E9D5AAA);
194        z = (z ^ (z >>> 16)) * 0x85A6B;
195        z = (z ^ (z >>> 13)) * 0xCAE35;
196        stateB = z ^ (z >>> 16);
197        z = (int)((seed >>> 32) + 0xC74EAD55);
198        z = (z ^ (z >>> 16)) * 0x85A6B;
199        z = (z ^ (z >>> 13)) * 0xCAE35;
200        stateC = z ^ (z >>> 16);
201        z = (int)((seed >>> 32) + 0x8E9D5AAA);
202        z = (z ^ (z >>> 16)) * 0x85A6B;
203        z = (z ^ (z >>> 13)) * 0xCAE35;
204        stateD = z ^ (z >>> 16);
205    }
206
207    public int getStateA()
208    {
209        return stateA;
210    }
211    /**
212     * Sets the first part of the state to the given int. As a special case, if the parameter is 0 and this would set
213     * all states to be 0, this will set stateA to 1 instead. Usually, you should use
214     * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set
215     * the four states individually.
216     * @param stateA any int
217     */
218    public void setStateA(int stateA)
219    {
220        this.stateA = (stateA | stateB | stateC | stateD) == 0 ? 1 : stateA;
221    }
222    public int getStateB()
223    {
224        return stateB;
225    }
226
227    /**
228     * Sets the second part of the state to the given int. As a special case, if the parameter is 0 and this would set
229     * all states to be 0, this will set stateA to 1 in addition to setting stateB to 0. Usually, you should use
230     * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set
231     * the four states individually.
232     * @param stateB any int
233     */
234    public void setStateB(int stateB)
235    {
236        this.stateB = stateB;
237        if((stateA | stateB | stateC | stateD) == 0) stateA = 1;
238    }
239    public int getStateC()
240    {
241        return stateC;
242    }
243
244    /**
245     * Sets the third part of the state to the given int. As a special case, if the parameter is 0 and this would set
246     * all states to be 0, this will set stateA to 1 in addition to setting stateC to 0. Usually, you should use
247     * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set
248     * the four states individually.
249     * @param stateC any int
250     */
251    public void setStateC(int stateC)
252    {
253        this.stateC = stateC;
254        if((stateA | stateB | stateC | stateD) == 0) stateA = 1;
255    }
256    
257    public int getStateD()
258    {
259        return stateD;
260    }
261
262    /**
263     * Sets the second part of the state to the given int. As a special case, if the parameter is 0 and this would set
264     * all states to be 0, this will set stateA to 1 in addition to setting stateD to 0. Usually, you should use
265     * {@link #setState(int, int, int, int)} to set all four states at once, but the result will be the same if you set
266     * the four states individually.
267     * @param stateD any int
268     */
269    public void setStateD(int stateD)
270    {
271        this.stateD = stateD;
272        if((stateA | stateB | stateC | stateD) == 0) stateA = 1;
273    }
274
275    /**
276     * Sets the current internal state of this XoshiroStarPhi32RNG with four ints, where each can be any int unless
277     * they are all 0 (which will be treated as if stateA is 1 and the rest are 0).
278     * @param stateA any int (if all parameters are both 0, this will be treated as 1)
279     * @param stateB any int
280     * @param stateC any int
281     * @param stateD any int
282     */
283    public void setState(final int stateA, final int stateB, final int stateC, final int stateD)
284    {
285        this.stateA = (stateA | stateB | stateC | stateD) == 0 ? 1 : stateA;
286        this.stateB = stateB;
287        this.stateC = stateC;
288        this.stateD = stateD;
289    }
290    
291    @Override
292    public String toString() {
293        return "XoshiroStarPhi32RNG with stateA 0x" + StringKit.hex(stateA) + ", stateB 0x" + StringKit.hex(stateB)
294                + ", stateC 0x" + StringKit.hex(stateC) + ", and stateD 0x" + StringKit.hex(stateD);
295    }
296
297    @Override
298    public boolean equals(Object o) {
299        if (this == o) return true;
300        if (o == null || getClass() != o.getClass()) return false;
301
302        XoshiroStarPhi32RNG xoshiroStarPhi32RNG = (XoshiroStarPhi32RNG) o;
303
304        return stateA == xoshiroStarPhi32RNG.stateA && stateB == xoshiroStarPhi32RNG.stateB &&
305                stateC == xoshiroStarPhi32RNG.stateC && stateD == xoshiroStarPhi32RNG.stateD;
306    }
307
308    @Override
309    public int hashCode() {
310        return 31 * (31 * (31 * stateA + stateB) + stateC) + stateD | 0;
311    }
312}