1import mt19937
2import math
3import rand.util
4
5const (
6	range_limit = 40
7	value_count = 1000
8	seeds       = [[u32(0xcafebabe), u32(0xdeadbeef)], [u32(0xc0de), u32(0xfeed)]]
9)
10
11const (
12	sample_size   = 1000
13	stats_epsilon = 0.05
14	inv_sqrt_12   = 1.0 / math.sqrt(12)
15)
16
17fn mt19937_basic_test() {
18	mut rng := mt19937.MT19937RNG{}
19	rng.seed([u32(0xdeadbeef)])
20	target := [956529277, 3842322136, 3319553134, 1843186657, 2704993644, 595827513, 938518626,
21		1676224337, 3221315650, 1819026461]
22	for i := 0; i < 10; i++ {
23		assert target[i] == rng.u32()
24	}
25}
26
27fn gen_randoms(seed_data []u32, bound int) []u64 {
28	bound_u64 := u64(bound)
29	mut randoms := []u64{len:(20)}
30	mut rnd := mt19937.MT19937RNG{}
31	rnd.seed(seed_data)
32	for i in 0 .. 20 {
33		randoms[i] = rnd.u64n(bound_u64)
34	}
35	return randoms
36}
37
38fn test_mt19937_reproducibility() {
39	seed_data := util.time_seed_array(2)
40	randoms1 := gen_randoms(seed_data, 1000)
41	randoms2 := gen_randoms(seed_data, 1000)
42	assert randoms1.len == randoms2.len
43	len := randoms1.len
44	for i in 0 .. len {
45		assert randoms1[i] == randoms2[i]
46	}
47}
48
49// TODO: use the `in` syntax and remove this function
50// after generics has been completely implemented
51fn found(value u64, arr []u64) bool {
52	for item in arr {
53		if value == item {
54			return true
55		}
56	}
57	return false
58}
59
60fn test_mt19937_variability() {
61	// If this test fails and if it is certainly not the implementation
62	// at fault, try changing the seed values. Repeated values are
63	// improbable but not impossible.
64	for seed in seeds {
65		mut rng := mt19937.MT19937RNG{}
66		rng.seed(seed)
67		mut values := []u64{cap: value_count}
68		for i in 0 .. value_count {
69			value := rng.u64()
70			assert !found(value, values)
71			assert values.len == i
72			values << value
73		}
74	}
75}
76
77fn check_uniformity_u64(mut rng mt19937.MT19937RNG, range u64) {
78	range_f64 := f64(range)
79	expected_mean := range_f64 / 2.0
80	mut variance := 0.0
81	for _ in 0 .. sample_size {
82		diff := f64(rng.u64n(range)) - expected_mean
83		variance += diff * diff
84	}
85	variance /= sample_size - 1
86	sigma := math.sqrt(variance)
87	expected_sigma := range_f64 * inv_sqrt_12
88	error := (sigma - expected_sigma) / expected_sigma
89	assert math.abs(error) < stats_epsilon
90}
91
92fn test_mt19937_uniformity_u64() {
93	ranges := [14019545, 80240, 130]
94	for seed in seeds {
95		mut rng := mt19937.MT19937RNG{}
96		rng.seed(seed)
97		for range in ranges {
98			check_uniformity_u64(mut rng, u64(range))
99		}
100	}
101}
102
103fn check_uniformity_f64(mut rng mt19937.MT19937RNG) {
104	expected_mean := 0.5
105	mut variance := 0.0
106	for _ in 0 .. sample_size {
107		diff := rng.f64() - expected_mean
108		variance += diff * diff
109	}
110	variance /= sample_size - 1
111	sigma := math.sqrt(variance)
112	expected_sigma := inv_sqrt_12
113	error := (sigma - expected_sigma) / expected_sigma
114	assert math.abs(error) < stats_epsilon
115}
116
117fn test_mt19937_uniformity_f64() {
118	// The f64 version
119	for seed in seeds {
120		mut rng := mt19937.MT19937RNG{}
121		rng.seed(seed)
122		check_uniformity_f64(mut rng)
123	}
124}
125
126fn test_mt19937_u32n() {
127	max := u32(16384)
128	for seed in seeds {
129		mut rng := mt19937.MT19937RNG{}
130		rng.seed(seed)
131		for _ in 0 .. range_limit {
132			value := rng.u32n(max)
133			assert value >= 0
134			assert value < max
135		}
136	}
137}
138
139fn test_mt19937_u64n() {
140	max := u64(379091181005)
141	for seed in seeds {
142		mut rng := mt19937.MT19937RNG{}
143		rng.seed(seed)
144		for _ in 0 .. range_limit {
145			value := rng.u64n(max)
146			assert value >= 0
147			assert value < max
148		}
149	}
150}
151
152fn test_mt19937_u32_in_range() {
153	max := u32(484468466)
154	min := u32(316846)
155	for seed in seeds {
156		mut rng := mt19937.MT19937RNG{}
157		rng.seed(seed)
158		for _ in 0 .. range_limit {
159			value := rng.u32_in_range(min, max)
160			assert value >= min
161			assert value < max
162		}
163	}
164}
165
166fn test_mt19937_u64_in_range() {
167	max := u64(216468454685163)
168	min := u64(6848646868)
169	for seed in seeds {
170		mut rng := mt19937.MT19937RNG{}
171		rng.seed(seed)
172		for _ in 0 .. range_limit {
173			value := rng.u64_in_range(min, max)
174			assert value >= min
175			assert value < max
176		}
177	}
178}
179
180fn test_mt19937_int31() {
181	max_u31 := 0x7FFFFFFF
182	sign_mask := 0x80000000
183	for seed in seeds {
184		mut rng := mt19937.MT19937RNG{}
185		rng.seed(seed)
186		for _ in 0 .. range_limit {
187			value := rng.int31()
188			assert value >= 0
189			assert value <= max_u31
190			// This statement ensures that the sign bit is zero
191			assert (value & sign_mask) == 0
192		}
193	}
194}
195
196fn test_mt19937_int63() {
197	max_u63 := i64(0x7FFFFFFFFFFFFFFF)
198	sign_mask := i64(0x8000000000000000)
199	for seed in seeds {
200		mut rng := mt19937.MT19937RNG{}
201		rng.seed(seed)
202		for _ in 0 .. range_limit {
203			value := rng.int63()
204			assert value >= 0
205			assert value <= max_u63
206			assert (value & sign_mask) == 0
207		}
208	}
209}
210
211fn test_mt19937_intn() {
212	max := 2525642
213	for seed in seeds {
214		mut rng := mt19937.MT19937RNG{}
215		rng.seed(seed)
216		for _ in 0 .. range_limit {
217			value := rng.intn(max)
218			assert value >= 0
219			assert value < max
220		}
221	}
222}
223
224fn test_mt19937_i64n() {
225	max := i64(3246727724653636)
226	for seed in seeds {
227		mut rng := mt19937.MT19937RNG{}
228		rng.seed(seed)
229		for _ in 0 .. range_limit {
230			value := rng.i64n(max)
231			assert value >= 0
232			assert value < max
233		}
234	}
235}
236
237fn test_mt19937_int_in_range() {
238	min := -4252
239	max := 1034
240	for seed in seeds {
241		mut rng := mt19937.MT19937RNG{}
242		rng.seed(seed)
243		for _ in 0 .. range_limit {
244			value := rng.int_in_range(min, max)
245			assert value >= min
246			assert value < max
247		}
248	}
249}
250
251fn test_mt19937_i64_in_range() {
252	min := i64(-24095)
253	max := i64(324058)
254	for seed in seeds {
255		mut rng := mt19937.MT19937RNG{}
256		rng.seed(seed)
257		for _ in 0 .. range_limit {
258			value := rng.i64_in_range(min, max)
259			assert value >= min
260			assert value < max
261		}
262	}
263}
264
265fn test_mt19937_f32() {
266	for seed in seeds {
267		mut rng := mt19937.MT19937RNG{}
268		rng.seed(seed)
269		for _ in 0 .. range_limit {
270			value := rng.f32()
271			assert value >= 0.0
272			assert value < 1.0
273		}
274	}
275}
276
277fn test_mt19937_f64() {
278	for seed in seeds {
279		mut rng := mt19937.MT19937RNG{}
280		rng.seed(seed)
281		for _ in 0 .. range_limit {
282			value := rng.f64()
283			assert value >= 0.0
284			assert value < 1.0
285		}
286	}
287}
288
289fn test_mt19937_f32n() {
290	max := f32(357.0)
291	for seed in seeds {
292		mut rng := mt19937.MT19937RNG{}
293		rng.seed(seed)
294		for _ in 0 .. range_limit {
295			value := rng.f32n(max)
296			assert value >= 0.0
297			assert value < max
298		}
299	}
300}
301
302fn test_mt19937_f64n() {
303	max := 1.52e6
304	for seed in seeds {
305		mut rng := mt19937.MT19937RNG{}
306		rng.seed(seed)
307		for _ in 0 .. range_limit {
308			value := rng.f64n(max)
309			assert value >= 0.0
310			assert value < max
311		}
312	}
313}
314
315fn test_mt19937_f32_in_range() {
316	min := f32(-24.0)
317	max := f32(125.0)
318	for seed in seeds {
319		mut rng := mt19937.MT19937RNG{}
320		rng.seed(seed)
321		for _ in 0 .. range_limit {
322			value := rng.f32_in_range(min, max)
323			assert value >= min
324			assert value < max
325		}
326	}
327}
328
329fn test_mt19937_f64_in_range() {
330	min := -548.7
331	max := 5015.2
332	for seed in seeds {
333		mut rng := mt19937.MT19937RNG{}
334		rng.seed(seed)
335		for _ in 0 .. range_limit {
336			value := rng.f64_in_range(min, max)
337			assert value >= min
338			assert value < max
339		}
340	}
341}
342