Guest User

Untitled

a guest
Aug 20th, 2019
58
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. namespace Minotaur.Random {
  2. using System;
  3. using System.Buffers;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;
  6. using Minotaur.Collections;
  7. using Minotaur.ExtensionMethods.Float;
  8.  
  9. public static class ThreadStaticRandom {
  10. // ThreadStatic to make sure that each thread gets a Random for itself, preventing the corruption
  11. // of the Random object
  12. [ThreadStatic]
  13. private static Random _instance;
  14.  
  15. // This wraps the _random variable to make sure each thread gets a Random for itself
  16. private static Random Instance {
  17. get {
  18. if (_instance == null)
  19. _instance = new Random();
  20.  
  21. return _instance;
  22. }
  23. }
  24.  
  25. public static bool Bool() {
  26. return Instance.NextDouble() < 0.5;
  27. }
  28.  
  29. public static bool Bool(float biasForTrue) {
  30. if (float.IsNaN(biasForTrue))
  31. throw new ArgumentOutOfRangeException(nameof(biasForTrue) + " can't be NaN");
  32. if (biasForTrue < 0 || biasForTrue > 1)
  33. throw new ArgumentOutOfRangeException(nameof(biasForTrue) + " must be in [0, 1] interval");
  34.  
  35. return Uniform() < biasForTrue;
  36. }
  37.  
  38. public static double Uniform() {
  39. return Instance.NextDouble();
  40. }
  41.  
  42. public static double Uniform(float inclusiveMin, float exclusiveMax) {
  43. if (inclusiveMin.IsNanOrInfinity())
  44. throw new ArgumentOutOfRangeException(nameof(inclusiveMin) + " can't be NaN nor Infinity");
  45. if (exclusiveMax.IsNanOrInfinity())
  46. throw new ArgumentOutOfRangeException(nameof(exclusiveMax) + " can't be NaN nor Infinity");
  47. if (inclusiveMin > exclusiveMax)
  48. throw new ArgumentException(nameof(inclusiveMin) + " must be <= " + nameof(exclusiveMax));
  49.  
  50. double range = exclusiveMax - inclusiveMin;
  51. range *= Uniform();
  52.  
  53. return inclusiveMin + range;
  54. }
  55.  
  56. public static int Int(int exclusiveMax) {
  57. return Instance.Next(minValue: 0, maxValue: exclusiveMax);
  58. }
  59.  
  60. public static int Int(int inclusiveMin, int exclusiveMax) {
  61. return Instance.Next(minValue: inclusiveMin, maxValue: exclusiveMax);
  62. }
  63.  
  64. public static bool[] RandomLabels(int count) {
  65. if (count < 0)
  66. throw new ArgumentOutOfRangeException(nameof(count) + " must be > 0");
  67.  
  68. var labels = new bool[count];
  69. // Todo: if shit hits the fan (it shouldn't), check this out
  70. var bytes = MemoryMarshal.AsBytes<bool>(labels);
  71. Instance.NextBytes(bytes);
  72. for (int i = 0; i < bytes.Length; i++)
  73. bytes[i] >>= 7;
  74.  
  75. return labels;
  76. }
  77.  
  78. public static T Choice<T>(T first, T second) {
  79. if (Bool())
  80. return first;
  81. else
  82. return second;
  83. }
  84.  
  85. public static T Choice<T>(IReadOnlyList<T> values) {
  86. if (values == null)
  87. throw new ArgumentNullException(nameof(values));
  88. if (values.Count == 0)
  89. throw new ArgumentException(nameof(values) + " can't be empty");
  90.  
  91. var index = Instance.Next(minValue: 0, maxValue: values.Count);
  92. return values[index];
  93. }
  94.  
  95. public static T Choice<T>(Array<T> values) {
  96. if (values == null)
  97. throw new ArgumentNullException(nameof(values));
  98. if (values.Length == 0)
  99. throw new ArgumentException(nameof(values) + " can't be empty");
  100.  
  101. var index = Instance.Next(minValue: 0, maxValue: values.Length);
  102. return values[index];
  103. }
  104.  
  105. public static T Choice<T>(ReadOnlySpan<T> values) {
  106. if (values.Length == 0)
  107. throw new ArgumentException(nameof(values) + " can't be empty");
  108.  
  109. var index = Instance.Next(minValue: 0, maxValue: values.Length);
  110. return values[index];
  111. }
  112.  
  113. public static T Choice<T>(T[] values) {
  114. if (values.Length == 0)
  115. throw new ArgumentException(nameof(values) + " can't be empty");
  116.  
  117. var index = Instance.Next(minValue: 0, maxValue: values.Length);
  118. return values[index];
  119. }
  120.  
  121. public static void Shuffle<T>(Span<T> values) {
  122. if (values.Length == 0)
  123. throw new ArgumentException(nameof(values) + " can't be empty");
  124.  
  125. var rng = Instance;
  126. int n = values.Length;
  127. while (n > 1) {
  128. n--;
  129. int k = rng.Next(n + 1);
  130. var temp = values[k];
  131. values[k] = values[n];
  132. values[n] = temp;
  133. }
  134. }
  135.  
  136. public static void Shuffle<T>(T[] values) {
  137. if (values == null)
  138. throw new ArgumentNullException(nameof(values));
  139. if (values.Length == 0)
  140. throw new ArgumentException(nameof(values) + " can't be empty");
  141.  
  142. var rng = Instance;
  143. int n = values.Length;
  144. while (n > 1) {
  145. n--;
  146. int k = rng.Next(n + 1);
  147. var temp = values[k];
  148. values[k] = values[n];
  149. values[n] = temp;
  150. }
  151. }
  152.  
  153. public static void CopyRandomElements<T>(ReadOnlySpan<T> from, Span<T> to, int count) {
  154. if (count < 0)
  155. throw new ArgumentOutOfRangeException(nameof(count) + " must be >= 0");
  156. if (from.Length < count)
  157. throw new ArgumentException(nameof(from) + " must have at least 'count' elements");
  158. if (to.Length < count)
  159. throw new ArgumentException(nameof(to) + "must have at least 'count' elements");
  160.  
  161. var rentedBuffer = ArrayPool<int>.Shared.Rent(minimumLength: from.Length);
  162. var indexes = rentedBuffer.AsSpan().Slice(
  163. start: 0,
  164. length: from.Length);
  165.  
  166. for (int i = 0; i < indexes.Length; i++)
  167. indexes[i] = i;
  168.  
  169. Shuffle(indexes);
  170.  
  171. for (int i = 0; i < count; i++)
  172. to[i] = from[indexes[i]];
  173.  
  174. ArrayPool<int>.Shared.Return(rentedBuffer);
  175. }
  176.  
  177. public static T[] SelectRandomElements<T>(ReadOnlySpan<T> from, int count) {
  178. if (count < 0)
  179. throw new ArgumentOutOfRangeException(nameof(count) + " must be >= 0");
  180.  
  181. var randomlySelected = new T[count];
  182. CopyRandomElements(
  183. from: from,
  184. to: randomlySelected,
  185. count: count);
  186.  
  187. return randomlySelected;
  188. }
  189. }
  190. }
  191.  
  192. private static Random Instance {
  193. get {
  194. if (_instance == null)
  195. _instance = new Random();
  196.  
  197. return _instance;
  198. }
  199. }
  200.  
  201. private static Random Instance => _instance ?? (_instance = new Random());
  202.  
  203. public static double Uniform() {
  204. return Instance.NextDouble();
  205. }
  206.  
  207. public static bool Bool(float biasForTrue) {
  208. // .. arg checks
  209.  
  210. return Uniform() < biasForTrue;
  211. }
  212.  
  213. public static bool Bool() {
  214. return Instance.NextDouble() < 0.5;
  215. }
  216.  
  217. public static bool Bool() => Uniform() < 0.5;
RAW Paste Data