< Summary

Class:GDX.Mathematics.Random.WELL1024a
Assembly:GDX
File(s):D:/BuildAgent/work/GDX-Documentation/Projects/GDX_Development/Packages/com.dotbunny.gdx/GDX/Mathematics/Random/WELL1024a.cs
Covered lines:118
Uncovered lines:0
Coverable lines:118
Total lines:328
Line coverage:100% (118 of 118)
Covered branches:0
Total branches:0
Covered methods:19
Total methods:19
Method coverage:100% (19 of 19)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
WELL1024a(...)0%220100%
WELL1024a(...)0%220100%
WELL1024a(...)0%330100%
WELL1024a(...)0%220100%
GetState()0%110100%
NextBoolean(...)0%110100%
NextBytes(...)0%220100%
NextDouble(...)0%110100%
NextInteger(...)0%110100%
NextIntegerExclusive(...)0%110100%
NextSingle(...)0%110100%
NextUnsignedInteger(...)0%110100%
NextUnsignedIntegerExclusive(...)0%110100%
Sample()0%110100%
Dispose()0%110100%
Equals(...)0%330100%
Equals(...)0%330100%
Equals(...)0%220100%
GetHashCode()0%110100%

File(s)

D:/BuildAgent/work/GDX-Documentation/Projects/GDX_Development/Packages/com.dotbunny.gdx/GDX/Mathematics/Random/WELL1024a.cs

#LineLine coverage
 1// Copyright (c) 2020-2022 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System;
 6using System.Runtime.CompilerServices;
 7using Unity.Collections;
 8using Unity.Mathematics;
 9using Unity.Collections.LowLevel.Unsafe;
 10namespace GDX.Mathematics.Random
 11{
 12    // ReSharper disable CommentTypo
 13    /// <summary>
 14    ///     Generates pseudorandom values based on the WELL1024a algorithm. You must <see cref="Dispose"/> manually.
 15    /// </summary>
 16    /// <remarks>
 17    ///     Primarily based on the work of <a href="http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf">Chris Lomont</a>
 18    ///     accessed on 2021-04-23.
 19    ///     Additional understanding from
 20    ///     <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/lfsr04.pdf">Francois Panneton and Pierre L`Ecuyer
 21    ///     accessed on 2021-04-23.
 22    /// </remarks>
 23    // ReSharper restore CommentTypo
 24    [VisualScriptingCompatible(4)]
 25#pragma warning disable IDE1006
 26    // ReSharper disable once InconsistentNaming
 27    public unsafe struct WELL1024a : IRandomProvider, IEquatable<WELL1024a>, IDisposable
 28#pragma warning restore IDE1006
 29    {
 30        /// <summary>
 31        ///     The state array of the well.
 32        /// </summary>
 33        public NativeArray<uint> State;
 34
 35        /// <summary>
 36        ///     A copy of the original seed used to initialize the <see cref="WELL1024a" />.
 37        /// </summary>
 38        public readonly uint OriginalSeed;
 39
 40        /// <summary>
 41        ///     The number of times that this well has been sampled.
 42        /// </summary>
 43        public uint SampleCount;
 44
 45        /// <summary>
 46        ///     The current index of use for the well array.
 47        /// </summary>
 48        /// <remarks>CAUTION! Changing this will alter the understanding of the data.</remarks>
 49        public byte Index;
 50
 51        /// <summary>
 52        ///     Creates a new pseudorandom number generator with the given <paramref name="seed" />.
 53        /// </summary>
 54        /// <remarks>
 55        ///     The <paramref name="seed" /> will have its sign stripped and stored as such in
 56        ///     <see cref="OriginalSeed" />.
 57        /// </remarks>
 58        /// <param name="seed">A <see cref="int" /> value to use as a seed.</param>
 59        public WELL1024a(int seed)
 160        {
 161            OriginalSeed = (uint)math.abs(seed);
 62
 63            // Initialize
 164            Index = 0;
 165            SampleCount = 0;
 166            State = new NativeArray<uint>(32, Allocator.Persistent);
 167            uint* ptr = (uint*)State.GetUnsafePtr();
 168            ptr[0] = OriginalSeed & 4294967295u;
 6469            for (int i = 1; i < 32; ++i)
 3170            {
 3171                ptr[i] = (69069u * ptr[i - 1]) & 4294967295u;
 3172            }
 173        }
 74
 75        /// <summary>
 76        ///     Creates a new pseudorandom number generator with the given <paramref name="seed" />.
 77        /// </summary>
 78        /// <param name="seed">A <see cref="uint" /> value to use as a seed.</param>
 79        public WELL1024a(uint seed)
 180        {
 181            OriginalSeed = seed;
 82
 83            // Initialize
 184            Index = 0;
 185            SampleCount = 0;
 186            State = new NativeArray<uint>(32, Allocator.Persistent);
 187            uint* ptr = (uint*)State.GetUnsafePtr();
 188            ptr[0] = OriginalSeed & 4294967295u;
 6489            for (int i = 1; i < 32; ++i)
 3190            {
 3191                ptr[i] = (69069u * ptr[i - 1]) & 4294967295u;
 3192            }
 193        }
 94
 95        /// <summary>
 96        ///     Creates a new pseudorandom number generator with the given <paramref name="seed" />.
 97        /// </summary>
 98        /// <remarks>
 99        ///     The created hashcode will have its sign stripped and stored as such in
 100        ///     <see cref="OriginalSeed" />.
 101        /// </remarks>
 102        /// <param name="seed">A <see cref="string" /> to create a <see cref="uint" /> seed from.</param>
 103        /// <param name="forceUpperCase">
 104        ///     Should the generated hashcode used as the seed be generated from an uppercase version of
 105        ///     the <paramref name="seed" />.
 106        /// </param>
 107        public WELL1024a(string seed, bool forceUpperCase = true)
 28108        {
 28109            if (forceUpperCase)
 26110            {
 26111                OriginalSeed = (uint)math.abs(seed.GetStableUpperCaseHashCode());
 26112            }
 113            else
 2114            {
 2115                OriginalSeed = (uint)math.abs(seed.GetStableHashCode());
 2116            }
 117
 118            // Initialize
 28119            Index = 0;
 28120            SampleCount = 0;
 28121            State = new NativeArray<uint>(32, Allocator.Persistent);
 28122            uint* ptr = (uint*)State.GetUnsafePtr();
 28123            ptr[0] = OriginalSeed & 4294967295u;
 1792124            for (int i = 1; i < 32; ++i)
 868125            {
 868126                ptr[i] = (69069u * ptr[i - 1]) & 4294967295u;
 868127            }
 28128        }
 129
 130        /// <summary>
 131        ///     Create a pseudorandom number generator from a <paramref name="restoreState" />.
 132        /// </summary>
 133        /// <param name="restoreState">A saved <see cref="WELL1024a" /> state.</param>
 134        public WELL1024a(WellState restoreState)
 2135        {
 2136            OriginalSeed = restoreState.Seed;
 2137            Index = restoreState.Index;
 138            // Create new native array
 2139            State = new NativeArray<uint>(32, Allocator.Persistent);
 2140            uint* ptr = (uint*)State.GetUnsafePtr();
 2141            uint* restoreStatePtr = (uint*)restoreState.State.GetUnsafePtr();
 132142            for (int i = 0; i < 32; i++)
 64143            {
 64144                ptr[i] = restoreStatePtr[i];
 64145            }
 2146            SampleCount = restoreState.Count;
 2147        }
 148
 149        /// <summary>
 150        ///     Get a <see cref="WellState" /> for the <see cref="WELL1024a" />.
 151        /// </summary>
 152        /// <remarks>Useful to save and restore the state of the <see cref="WELL1024a" />.</remarks>
 153        /// <returns></returns>
 154        public WellState GetState()
 2155        {
 2156            return new WellState {Index = Index, State = State, Seed = OriginalSeed, Count = SampleCount};
 2157        }
 158
 159        /// <inheritdoc cref="IRandomProvider.NextBoolean" />
 160        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 161        public bool NextBoolean(float chance = 0.5f)
 3162        {
 3163            return Sample() <= chance;
 3164        }
 165
 166        /// <inheritdoc cref="IRandomProvider.NextBytes" />
 167        public void NextBytes(byte[] buffer)
 2168        {
 2169            int bufLen = buffer.Length;
 44170            for (int idx = 0; idx < bufLen; ++idx)
 20171            {
 20172                buffer[idx] = (byte)NextInteger(0, 256);
 20173            }
 2174        }
 175
 176        /// <inheritdoc cref="IRandomProvider.NextDouble" />
 177        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 178        public double NextDouble(double minValue = 0d, double maxValue = 1d)
 67179        {
 67180            return Range.GetDouble(Sample(), minValue, maxValue);
 67181        }
 182
 183        /// <inheritdoc cref="IRandomProvider.NextInteger" />
 184        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 185        public int NextInteger(int minValue = 0, int maxValue = int.MaxValue)
 110186        {
 110187            return Range.GetInteger(Sample(), minValue, maxValue);
 110188        }
 189
 190        /// <inheritdoc cref="IRandomProvider.NextIntegerExclusive" />
 191        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 192        public int NextIntegerExclusive(int minValue = 0, int maxValue = int.MaxValue)
 26193        {
 26194            return Range.GetInteger(Sample(), minValue + 1,  maxValue - 1);
 26195        }
 196
 197        /// <inheritdoc cref="IRandomProvider.NextSingle" />
 198        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 199        public float NextSingle(float minValue = 0f, float maxValue = 1f)
 65200        {
 65201            return Range.GetSingle(Sample(), minValue, maxValue);
 65202        }
 203
 204        /// <inheritdoc cref="IRandomProvider.NextUnsignedInteger" />
 205        public uint NextUnsignedInteger(uint minValue = uint.MinValue, uint maxValue = uint.MaxValue)
 65206        {
 65207            return Range.GetUnsignedInteger(Sample(), minValue, maxValue);
 65208        }
 209
 210        /// <inheritdoc cref="IRandomProvider.NextUnsignedIntegerExclusive" />
 211        public uint NextUnsignedIntegerExclusive(uint minValue = uint.MinValue, uint maxValue = uint.MaxValue)
 2212        {
 2213            return Range.GetUnsignedInteger(Sample(), minValue + 1, maxValue - 1);
 2214        }
 215
 216        /// <inheritdoc cref="IRandomProvider.Sample" />
 217        public double Sample()
 341218        {
 341219            SampleCount++;
 220
 341221            uint* ptr = (uint*)State.GetUnsafePtr();
 341222            uint a = ptr[(int)((Index + 3u) & 31u)];
 341223            uint z1 = ptr[Index] ^ a ^ (a >> 8);
 341224            uint b = ptr[(int)((Index + 24u) & 31u)];
 341225            uint c = ptr[(int)((Index + 10u) & 31u)];
 341226            uint z2 = b ^ (b << 19) ^ c ^ (c << 14);
 227
 341228            ptr[Index] = z1 ^ z2;
 341229            uint d = ptr[(int)((Index + 31u) & 31u)];
 341230            ptr[(int)((Index + 31u) & 31u)] = d ^ (d << 11) ^ z1 ^ (z1 << 7) ^ z2 ^ (z2 << 13);
 341231            Index = (byte)((Index + 31u) & 31u);
 232
 341233            return ptr[Index & 31u] * 2.32830643653869628906e-10d;
 341234        }
 235
 236        /// <summary>
 237        ///     A complete state of <see cref="WELL1024a" />.
 238        /// </summary>
 239        [Serializable]
 240        public struct WellState
 241        {
 242            /// <summary>
 243            ///     The internal state array.
 244            /// </summary>
 245            public NativeArray<uint> State;
 246
 247            /// <summary>
 248            ///     The seed used to originally create the <see cref="WELL1024a" />.
 249            /// </summary>
 250            public uint Seed;
 251
 252            /// <summary>
 253            ///     The internal sample count.
 254            /// </summary>
 255            public uint Count;
 256
 257            /// <summary>
 258            ///     The internal state index.
 259            /// </summary>
 260            public byte Index;
 261        }
 262
 263        /// <summary>
 264        ///     Disposes of the native allocations.
 265        /// </summary>
 266        public void Dispose()
 32267        {
 32268            State.Dispose();
 32269        }
 270
 271        /// <summary>
 272        ///     Is one <see cref="WELL1024a" /> the same as the <paramref name="other" />.
 273        /// </summary>
 274        /// <param name="other">The <see cref="WELL1024a" /> to compare with.</param>
 275        /// <returns>true/false if they are fundamentally the same.</returns>
 276        public bool Equals(ref WELL1024a other)
 1277        {
 1278            return OriginalSeed == other.OriginalSeed &&
 279                   Index == other.Index &&
 280                   SampleCount == other.SampleCount;
 1281        }
 282
 283        /// <summary>
 284        ///     Is one <see cref="WELL1024a" /> the same as the <paramref name="other" />.
 285        /// </summary>
 286        /// <remarks>
 287        ///     Avoid using this format for comparison as it copies the data, where as
 288        ///     <see cref="Equals(ref GDX.Mathematics.Random.WELL1024a)" /> does not.
 289        /// </remarks>
 290        /// <param name="other">The <see cref="WELL1024a" /> to compare with.</param>
 291        /// <returns>true/false if they are fundamentally the same.</returns>
 292        public bool Equals(WELL1024a other)
 1293        {
 1294            return OriginalSeed == other.OriginalSeed &&
 295                   Index == other.Index &&
 296                   SampleCount == other.SampleCount;
 1297        }
 298
 299        /// <summary>
 300        ///     Determines if the provided <paramref name="obj" />'s hash code is equal to this <see cref="WELL1024a" />
 301        ///     <see cref="GetHashCode" />.
 302        /// </summary>
 303        /// <remarks>
 304        ///     This doesnt preclude other objects of different types from having the same hashcode.
 305        /// </remarks>
 306        /// <param name="obj">The <see cref="object" /> to compare hash codes with.</param>
 307        /// <returns>true/false if the hash codes match.</returns>
 308        public override bool Equals(object obj)
 1309        {
 1310            return obj != null && GetHashCode() == obj.GetHashCode();
 1311        }
 312
 313        /// <summary>
 314        ///     Generate a hash code value for the given <see cref="WELL1024a" /> at its current state.
 315        /// </summary>
 316        /// <returns>The hash code value.</returns>
 317        public override int GetHashCode()
 2318        {
 319            unchecked
 2320            {
 2321                int hashCode = (int)OriginalSeed;
 2322                hashCode = (hashCode * 397) ^ Index;
 2323                hashCode = (hashCode * 397) ^ (int)SampleCount;
 2324                return hashCode;
 325            }
 2326        }
 327    }
 328}