001package squidpony.squidmath;
002
003import squidpony.StringKit;
004
005import java.io.Serializable;
006
007/**
008 * A high-quality StatefulRandomness based on {@link LinnormRNG} but modified to allow any odd number as a stream,
009 * instead of LinnormRNG's hardcoded stream of 1. Although some streams may have quality issues, the structure is based
010 * on a linear congruential generator where the stream is the additive component, and in that context all odd numbers
011 * are usually considered equally effective. Has 64 bits of state, 64 bits used to store a stream (which cannot be
012 * changed after construction) and natively outputs 64 bits at a time. Changes its state with a basic linear
013 * congruential generator (it is simply {@code state = state * 3935559000370003845L + stream}). Starting with that LCG's
014 * output, it xorshifts that output twice, multiplies by a very large negative long, then returns another xorshift. Like
015 * LinnormRNG, the output of this simple function passes all 32TB of PractRand (for one stream, it had 3 anomalies, but
016 * another had none, and none were ever significant or persistent), meaning its statistical quality is excellent. The
017 * speed of this particular class isn't fully clear yet, but benchmarks performed under the heavy load of PractRand
018 * testing happening at the same time appeared to show no significant difference between LinnormRNG and MizuchiRNG in
019 * speed (which means it's tied for second place in its category, behind {@link DiverRNG}).
020 * <br>
021 * This generator is a StatefulRandomness but not a SkippingRandomness, so it can't (efficiently) have the skip() method
022 * that LightRNG has. A method could be written to run the generator's state backwards, though, as well as to get the
023 * state from an output of {@link #nextLong()}. {@link LinnormRNG} uses the same algorithm except for the number added
024 * in the LCG state update; there this number is always 1, but here it can be any odd long. This means that any given
025 * MizuchiRNG object has two long values stored in it instead of the one in a LinnormRNG, but it allows two MizuchiRNG
026 * objects with different streams to produce different, probably-not-correlated sequences of results, even with the same
027 * seed. This property may be useful for cases where an adversary is trying to predict results in some way, though using
028 * different streams for this purpose isn't enough and should be coupled with truncation of a large part of output (see
029 * PCG-Random's techniques for this).
030 * <br>
031 * The name comes from combining the concept of a linnorm, which is a dragon and the namesake of LinnormRNG, with
032 * streams, since Mizuchi allows many possible streams, to get the concept of a river-or-stream-dwelling dragon. The
033 * mizuchi is a (by some versions of the story) river dragon from Japanese mythology.
034 * <br>
035 * Written June 29, 2019 by Tommy Ettinger. Thanks to M.E. O'Neill for her insights into the family of generators both
036 * this and her PCG-Random fall into, and to the team that worked on SplitMix64 for SplittableRandom in JDK 8. Chris
037 * Doty-Humphrey's work on PractRand has been invaluable. The LCG state multiplier is listed in a paper by L'Ecuyer from
038 * 1999, Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure. The other
039 * multiplier is from PCG-Random, and that's both the nothing-up-my-sleeve numbers used here. Thanks also to Sebastiano
040 * Vigna and David Blackwell for creating the incredibly fast xoroshiro128+ generator and also very fast
041 * <a href="http://xoshiro.di.unimi.it/hwd.php">HWD tool</a>; the former inspired me to make my code even faster and the
042 * latter tool seems useful so far in proving the quality of the generator (LinnormRNG passes over 100TB of HWD, and
043 * probably would pass much more if I gave it more days to run).
044 * @author Tommy Ettinger
045 */
046public final class MizuchiRNG implements StatefulRandomness, Serializable {
047
048    private static final long serialVersionUID = 153186732328748834L;
049
050    private long state; /* The state can be seeded with any value. */
051    
052    private final long stream;
053
054    /**
055     * Creates a new generator seeded using Math.random.
056     */
057    public MizuchiRNG() {
058        this((long) ((Math.random() - 0.5) * 0x10000000000000L)
059                ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L),
060                (long) ((Math.random() - 0.5) * 0x10000000000000L)
061                        ^ (long) (((Math.random() - 0.5) * 2.0) * 0x8000000000000000L));
062    }
063
064    public MizuchiRNG(final long seed) {
065        state = seed;
066        this.stream = (seed
067                ^ Long.rotateLeft((seed ^ 0x369DEA0F31A53F85L) * 0x6A5D39EAE116586DL + 0x9E3779B97F4A7C15L, (int)seed)
068                ^ Long.rotateLeft((seed ^ 0x6A5D39EAE116586DL) * 0x369DEA0F31A53F85L + 0x4A7C159E3779B97FL, (int)seed * 0x41C64E6D >>> 26)) | 1L;
069    }
070
071    public MizuchiRNG(final long seed, final long stream) {
072        state = seed;
073        this.stream = (stream | 1L);
074    }
075
076    public MizuchiRNG(final String seed) {
077        state = CrossHash.Mist.predefined[32].hash64(seed);
078        stream = (CrossHash.Mist.predefined[(int) state & 31].hash64(seed) | 1L);
079    }
080
081    @Override
082    public final int next(int bits)
083    {
084        long z = (state = state * 0x369DEA0F31A53F85L + stream);
085        z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L;
086        return (int)(z ^ z >>> 25) >>> (32 - bits);
087    }
088
089    /**
090     * Can return any long, positive or negative, of any size permissible in a 64-bit signed integer.
091     *
092     * @return any long, all 64 bits are random
093     */
094    @Override
095    public final long nextLong() {
096        long z = (state = state * 0x369DEA0F31A53F85L + stream);
097        z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L;
098        return (z ^ z >>> 25);
099    }
100
101    /**
102     * Produces a copy of this RandomnessSource that, if next() and/or nextLong() are called on this object and the
103     * copy, both will generate the same sequence of random numbers from the point copy() was called. This just need to
104     * copy the state so it isn't shared, usually, and produce a new value with the same exact state.
105     *
106     * @return a copy of this RandomnessSource
107     */
108    @Override
109    public MizuchiRNG copy() {
110        return new MizuchiRNG(state);
111    }
112
113    /**
114     * Can return any int, positive or negative, of any size permissible in a 32-bit signed integer.
115     *
116     * @return any int, all 32 bits are random
117     */
118    public final int nextInt() {
119        long z = (state = state * 0x369DEA0F31A53F85L + stream);
120        z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L;
121        return (int)(z ^ z >>> 25);
122    }
123
124    /**
125     * Exclusive on the outer bound.  The inner bound is 0.
126     * The bound can be negative, which makes this produce either a negative int or 0.
127     *
128     * @param bound the upper bound; should be positive
129     * @return a random int between 0 (inclusive) and bound (exclusive)
130     */
131    public final int nextInt(final int bound) {
132        long z = (state = state * 0x369DEA0F31A53F85L + stream);
133        z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L;
134        return (int)((bound * ((z ^ z >>> 25) & 0xFFFFFFFFL)) >> 32);
135    }
136
137    /**
138     * Inclusive inner, exclusive outer.
139     *
140     * @param inner the inner bound, inclusive, can be positive or negative
141     * @param outer the outer bound, exclusive, can be positive or negative, usually greater than inner
142     * @return a random int between inner (inclusive) and outer (exclusive)
143     */
144    public final int nextInt(final int inner, final int outer) {
145        return inner + nextInt(outer - inner);
146    }
147
148    /**
149     * Exclusive on the upper bound. The lower bound is 0.
150     *
151     * @param bound the upper bound; should be positive (if negative, this returns 0)
152     * @return a random long less than n
153     */
154    public final long nextLong(long bound) {
155        long rand = nextLong();
156        if (bound <= 0) return 0;
157        final long randLow = rand & 0xFFFFFFFFL;
158        final long boundLow = bound & 0xFFFFFFFFL;
159        rand >>>= 32;
160        bound >>>= 32;
161        final long a = rand * bound;
162        final long b = randLow * boundLow;
163        return (((b >>> 32) + (rand + randLow) * (bound + boundLow) - a - b) >>> 32) + a;
164    }
165
166    /**
167     * Inclusive lower, exclusive upper.
168     *
169     * @param lower the lower bound, inclusive, can be positive or negative
170     * @param upper the upper bound, exclusive, should be positive, must be greater than lower
171     * @return a random long at least equal to lower and less than upper
172     */
173    public final long nextLong(final long lower, final long upper) {
174        if (upper - lower <= 0) throw new IllegalArgumentException("Upper bound must be greater than lower bound");
175        return lower + nextLong(upper - lower);
176    }
177
178    /**
179     * Gets a uniform random double in the range [0.0,1.0)
180     *
181     * @return a random double at least equal to 0.0 and less than 1.0
182     */
183    public final double nextDouble() {
184        long z = (state = state * 0x369DEA0F31A53F85L + stream);
185        z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L;
186        return ((z ^ z >>> 25) & 0x1FFFFFFFFFFFFFL) * 0x1p-53;
187
188    }
189
190    /**
191     * Gets a uniform random double in the range [0.0,outer) given a positive parameter outer. If outer
192     * is negative, it will be the (exclusive) lower bound and 0.0 will be the (inclusive) upper bound.
193     *
194     * @param outer the exclusive outer bound, can be negative
195     * @return a random double between 0.0 (inclusive) and outer (exclusive)
196     */
197    public final double nextDouble(final double outer) {
198        long z = (state = state * 0x369DEA0F31A53F85L + stream);
199        z = (z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L;
200        return ((z ^ z >>> 25) & 0x1FFFFFFFFFFFFFL) * 0x1p-53 * outer;
201    }
202
203    /**
204     * Gets a uniform random float in the range [0.0,1.0)
205     *
206     * @return a random float at least equal to 0.0 and less than 1.0
207     */
208    public final float nextFloat() {
209        final long z = (state = state * 0x369DEA0F31A53F85L + stream);
210        return ((z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L >>> 40) * 0x1p-24f;
211    }
212
213    /**
214     * Gets a random value, true or false.
215     * Calls nextLong() once.
216     *
217     * @return a random true or false value.
218     */
219    public final boolean nextBoolean() {
220        final long z = (state = state * 0x369DEA0F31A53F85L + stream);
221        return ((z ^ z >>> 23 ^ z >>> 47) * 0xAEF17502108EF2D9L) < 0;
222    }
223
224    /**
225     * Given a byte array as a parameter, this will fill the array with random bytes (modifying it
226     * in-place). Calls nextLong() {@code Math.ceil(bytes.length / 8.0)} times.
227     *
228     * @param bytes a byte array that will have its contents overwritten with random bytes.
229     */
230    public final void nextBytes(final byte[] bytes) {
231        int i = bytes.length, n;
232        while (i != 0) {
233            n = Math.min(i, 8);
234            for (long bits = nextLong(); n-- != 0; bits >>>= 8) bytes[--i] = (byte) bits;
235        }
236    }
237
238    /**
239     * Sets the seed (also the current state) of this generator.
240     *
241     * @param seed the seed to use for this LightRNG, as if it was constructed with this seed.
242     */
243    @Override
244    public final void setState(final long seed) {
245        state = seed;
246    }
247
248    /**
249     * Gets the current state of this generator.
250     *
251     * @return the current seed of this LightRNG, changed once per call to nextLong()
252     */
253    @Override
254    public final long getState() {
255        return state;
256    }
257
258    @Override
259    public String toString() {
260        return "MizuchiRNG with state 0x" + StringKit.hex(state) + "L on stream 0x" + StringKit.hex(stream) + 'L';
261    }
262
263    @Override
264    public boolean equals(Object o) {
265        if (this == o) return true;
266        if (o == null || getClass() != o.getClass()) return false;
267        MizuchiRNG mizuchiRNG = ((MizuchiRNG) o);
268        return state == mizuchiRNG.state && stream == mizuchiRNG.stream;
269    }
270
271    @Override
272    public int hashCode() {
273        return (int) ((state ^ (state >>> 32)) * 0xDB4F0B9175AE2165L + (stream ^ (stream >>> 32)));
274    }
275
276//    public static void main(String[] args)
277//    {
278//        /*
279//        cd target/classes
280//        java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly sarong/DervishRNG > Dervish_asm.txt
281//         */
282//        long longState = 1L;
283//        int intState = 1;
284//        float floatState = 0f;
285//        double doubleState = 0.0;
286//        MizuchiRNG rng = new MizuchiRNG(1L, 123456789L);
287//        //longState += determine(i);
288//        //longState = longState + 0x9E3779B97F4A7C15L;
289//        //seed += determine(longState++);
290//        for (int r = 0; r < 10; r++) {
291//            for (int i = 0; i < 10000007; i++) {
292//                longState += rng.nextLong();
293//            }
294//        }
295//        System.out.println(longState);
296//
297//        for (int r = 0; r < 10; r++) {
298//            for (int i = 0; i < 10000007; i++) {
299//                intState += rng.next(16);
300//            }
301//        }
302//        System.out.println(intState);
303//
304//        for (int r = 0; r < 10; r++) {
305//            for (int i = 0; i < 10000007; i++) {
306//                floatState += rng.nextFloat();
307//            }
308//        }
309//        System.out.println(floatState);
310//
311//        for (int r = 0; r < 10; r++) {
312//            for (int i = 0; i < 10000007; i++) {
313//                doubleState += rng.nextDouble();
314//            }
315//        }
316//        System.out.println(doubleState);
317//
318//    }
319
320}