-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlqc_gen.lua
More file actions
126 lines (102 loc) · 3.58 KB
/
lqc_gen.lua
File metadata and controls
126 lines (102 loc) · 3.58 KB
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
--- Helper module providing various generators for generating data.
-- @module lqc.lqc_gen
-- @alias lib
local Gen = require 'lqc.generator'
local random = require 'lqc.random'
local reduce = require 'lqc.helpers.reduce'
local lib = {}
--- Picks a number randomly between min and max.
-- @param min Minimum value to pick from
-- @param max Maximum value to pick from
-- @return a random value between min and max
local function choose_pick(min, max)
local function pick()
return random.between(min, max)
end
return pick
end
--- Shrinks a value between min and max by dividing the sum of the closest
-- number to 0 and the generated value with 2.
-- This effectively reduces it to the value closest to 0 gradually in the
-- chosen range.
-- @param min Minimum value to pick from
-- @param max Maximum value to pick from
-- @return a shrunk value between min and max
local function choose_shrink(min, max)
local shrink_to = (math.abs(min) < math.abs(max)) and min or max
local function shrink(value)
local shrunk_value = (shrink_to + value) / 2
if shrunk_value < 0 then
return math.ceil(shrunk_value)
else
return math.floor(shrunk_value)
end
end
return shrink
end
--- Creates a generator, chooses an integer between min and max (inclusive range).
-- @param min Minimum value to pick from
-- @param max Maximum value to pick from
-- @return a random value between min and max
function lib.choose(min, max)
return Gen.new(choose_pick(min, max), choose_shrink(min, max))
end
--- Select a generator from a list of generators
-- @param generators Table containing an array of generator objects.
-- @return A new generator that randomly uses 1 of the generators in the list.
function lib.oneof(generators)
local which -- shared state between pick and shrink needed to shrink correctly
local function oneof_pick(numtests)
which = random.between(1, #generators)
return generators[which]:pick(numtests)
end
local function oneof_shrink(prev)
return generators[which]:shrink(prev)
end
return Gen.new(oneof_pick, oneof_shrink)
end
--- Select a generator from a list of weighted generators ({{weight1, gen1}, ... })
-- @param generators A table containing an array of weighted generators.
-- @return A new generator that randomly uses a generator from the list, taking the
-- weights into account.
function lib.frequency(generators)
local which
local function do_sum(generator, acc) return generator[1] + acc end
local function frequency_pick(numtests)
local sum = reduce(generators, 0, do_sum)
local val = random.between(1, sum)
which = reduce(generators, { 0, 1 }, function(generator, acc)
local current_sum = acc[1] + generator[1]
if current_sum >= val then
return acc
else
return { current_sum, acc[2] + 1 }
end
end)[2]
return generators[which][2]:pick(numtests)
end
local function frequency_shrink(prev)
return generators[which][2]:shrink(prev)
end
return Gen.new(frequency_pick, frequency_shrink)
end
--- Create a generator that selects an element based on the input list.
-- @param array an array of constant values
-- @return Generator that can pick 1 of the values in the array, shrinks
-- towards beginning of the list.
function lib.elements(array)
local last_idx
local function elements_pick()
local idx = random.between(1, #array)
last_idx = idx
return array[idx]
end
local function elements_shrink(_)
if last_idx > 1 then
last_idx = last_idx - 1
end
return array[last_idx]
end
return Gen.new(elements_pick, elements_shrink)
end
return lib