1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// Note(Lokathor): We have a generic LCG type below, but for now we can hide the
// process of having to pick what multiplier and increment to use behind a
// newtype that selects some default constants.

/// A [Linear Congruential Generator][wp-lcg] with 32-bits of output.
///
/// [wp-lcg]: https://en.wikipedia.org/wiki/Linear_congruential_generator
///
/// This holds a single `u32` as the state. Advancing the generator requires
/// only a multiply and an add, so it's fairly fast as a PRNG. The output
/// quality isn't particularly great as a result, and if you need less than 32
/// bits of randomness at a time you're advised to use the *upper* bits from
/// each output of this generator, which will be the better bits. The [Gen32]
/// impl of this type will handle that for you, if you use that trait.
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
// This particular `MUL` value comes from "Tables of linear congruential
// generators of different sizes and good lattice structure" by Pierre L'Ecuyer.
// We select 1 as the `ADD` value just to have an odd increment, and because
// `ADD` values of 3 bits or less can be encoded with an immediate
// instruction in both a32 and t32 code.
pub struct Lcg32(GenericLcg32<32310901, 1>);
impl Lcg32 {
  /// Wraps the `u32` as an `Lcg32`.
  ///
  /// This doesn't do any manipulation of the input state to try and help seed
  /// the value, it just uses the value directly.
  #[inline]
  pub const fn new(state: u32) -> Self {
    Self(GenericLcg32::new(state))
  }

  /// Advances the generator one step, producing a `u32` of output.
  #[inline]
  pub fn next_u32(&mut self) -> u32 {
    self.0.next_u32()
  }

  /// Advances the generator by `delta` steps all at once.
  ///
  /// Because the generator output sequence loops, large `delta` values allow
  /// you to "reverse" the generator.
  #[inline]
  pub fn jump_state(&mut self, delta: u32) {
    self.0.jump_state(delta)
  }
}

/// A [Linear Congruential Generator][wp-lcg] with a const generic multiplier
/// and increment.
///
/// [wp-lcg]: https://en.wikipedia.org/wiki/Linear_congruential_generator
///
/// The `ADD` value can be any value at all. Different `ADD` values will reorder
/// the sequence that you get from a particular `MUL` value. For best results
/// `ADD` should be an odd value. An even `ADD` value gives a generator with a
/// significantly shorter period than an odd `ADD` value.
///
/// The `MUL` value must be carefully selected, because it has an overwhelming
/// impact on the generator's output quality. See the linked wikipedia article
/// (and its references) if you want information on what `MUL` values you might
/// want to use.
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
struct GenericLcg32<const MUL: u32, const ADD: u32>(u32);
impl<const MUL: u32, const ADD: u32> GenericLcg32<MUL, ADD> {
  /// Wraps the `u32` as a generic LCG.
  ///
  /// This doesn't do any manipulation of the input state to try and help seed
  /// the value, it just uses the value directly.
  #[inline]
  pub const fn new(state: u32) -> Self {
    Self(state)
  }

  /// Advances the generator one step, producing a `u32` of output.
  #[inline]
  pub fn next_u32(&mut self) -> u32 {
    let next_state = self.0.wrapping_mul(MUL).wrapping_add(ADD);
    next_state
  }

  /// Advances the generator by `delta` steps all at once.
  ///
  /// Because the generator output sequence loops, large `delta` values allow
  /// you to "reverse" the generator.
  #[inline]
  pub fn jump_state(&mut self, mut delta: u32) {
    let mut cur_mult: u32 = MUL;
    let mut cur_plus: u32 = ADD;
    let mut acc_mult: u32 = 1;
    let mut acc_plus: u32 = 0;
    while delta > 0 {
      if (delta & 1) > 0 {
        acc_mult = acc_mult.wrapping_mul(cur_mult);
        acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus);
      }
      cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus);
      cur_mult = cur_mult.wrapping_mul(cur_mult);
      delta /= 2;
    }
    self.0 = acc_mult.wrapping_mul(self.0).wrapping_add(acc_plus);
  }
}

/// A trait for pseudorandom number generators that have `u32`
/// output from each step of the generator.
pub trait Gen32 {
  /// Advance the generator to produce the next `u32`.
  fn next_u32(&mut self) -> u32;

  /// Produce a `u16`.
  #[inline]
  fn next_u16(&mut self) -> u16 {
    (self.next_u32() >> 16) as u16
  }

  /// Produce a `u8`.
  #[inline]
  fn next_u8(&mut self) -> u8 {
    (self.next_u32() >> 24) as u8
  }

  /// Produce a `bool`.
  #[inline]
  fn next_bool(&mut self) -> bool {
    (self.next_u16() as i32) < 0
  }

  /// Produce a value that's strictly less than `b`.
  ///
  /// ## Panics
  /// * If `b` is zero.
  #[inline]
  #[track_caller]
  fn next_bounded(&mut self, b: u16) -> u16 {
    assert!(b != 0, "Gen32::next_bounded> Bound must be non-zero.");
    let mut x: u32 = self.next_u16() as u32;
    let mut mul: u32 = (b as u32).wrapping_mul(x);
    let mut low: u16 = mul as u16;
    if low < b {
      let threshold = b.wrapping_neg() % b;
      while low < threshold {
        x = self.next_u32();
        mul = (b as u32).wrapping_mul(x);
        low = mul as u16;
      }
    }
    let high = (mul >> 16) as u16;
    high
  }

  /// Pick a random element of the slice, by value.
  ///
  /// ## Panics
  /// * If the length is 0.
  #[inline]
  fn pick<T: Copy>(&mut self, buf: &[T]) -> T {
    let len16: u16 = saturating_usize_as_u16(buf.len());
    buf[self.next_bounded(len16) as usize]
  }

  /// Pick a random element of the slice, by shared reference.
  ///
  /// ## Panics
  /// * If the length is 0.
  #[inline]
  fn pick_ref<'b, T>(&mut self, buf: &'b [T]) -> &'b T {
    let len16: u16 = saturating_usize_as_u16(buf.len());
    &buf[self.next_bounded(len16) as usize]
  }

  /// Pick a random element of the slice, by unique reference.
  ///
  /// ## Panics
  /// * If the length is 0.
  #[inline]
  fn pick_mut<'b, T>(&mut self, buf: &'b mut [T]) -> &'b mut T {
    let len16: u16 = saturating_usize_as_u16(buf.len());
    &mut buf[self.next_bounded(len16) as usize]
  }

  /// Shuffles the elements of the slice.
  ///
  /// On an empty slice this is a no-op.
  #[inline]
  fn shuffle<T>(&mut self, buf: &mut [T]) {
    if let Some(end_index) = buf.len().checked_sub(1) {
      let mut possibility_count: u16 = saturating_usize_as_u16(buf.len());
      let mut this_index: usize = 0;
      while this_index < end_index {
        let offset = self.next_bounded(possibility_count) as usize;
        buf.swap(this_index, this_index + offset);
        possibility_count -= 1;
        this_index += 1;
      }
    }
  }
}

impl Gen32 for Lcg32 {
  #[inline]
  fn next_u32(&mut self) -> u32 {
    Lcg32::next_u32(self)
  }
}

#[inline]
const fn saturating_usize_as_u16(val: usize) -> u16 {
  if val <= u16::MAX as usize {
    val as u16
  } else {
    u16::MAX
  }
}