You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.4 KiB
Lua
109 lines
3.4 KiB
Lua
--- Module for generating integer values
|
|
-- @module lqc.generators.int
|
|
-- @alias new
|
|
local Gen = require 'lqc.generator'
|
|
local random = require 'lqc.random'
|
|
local abs = math.abs
|
|
|
|
--- Helper function for picking a random integer, bounded by min and max.
|
|
-- @param min minimum value
|
|
-- @param max maximum value
|
|
-- @return function that can generate an integer (min <= int <= max)
|
|
local function pick_bounded(min, max)
|
|
local function do_pick()
|
|
return random.between(min, max)
|
|
end
|
|
return do_pick
|
|
end
|
|
|
|
--- Helper function for finding number closest to 0.
|
|
-- @param a number 1
|
|
-- @param b number 2
|
|
-- @return number closest to 0
|
|
local function find_closest_to_zero(a, b)
|
|
return (abs(a) < abs(b)) and a or b
|
|
end
|
|
|
|
--- Helper function for shrinking integer, bounded by min and max. (min <= int <= max)
|
|
-- @param min minimum value
|
|
-- @param max maximum value
|
|
-- @return shrunk integer (shrinks towards 0 / closest value to 0 determined
|
|
-- by min and max)
|
|
local function shrink_bounded(min, max)
|
|
local bound_limit = find_closest_to_zero(min, max)
|
|
local function do_shrink(previous)
|
|
if previous == 0 or previous == bound_limit then
|
|
return previous
|
|
end
|
|
if previous > 0 then
|
|
return math.floor(previous / 2)
|
|
end
|
|
return math.ceil(previous / 2)
|
|
end
|
|
return do_shrink
|
|
end
|
|
|
|
--- Picks a random integer, uniformy spread between +- sample_size / 2.
|
|
-- @param sample_size Number of times this generator is used in a property;
|
|
-- used to guide the optimatization process.
|
|
-- @return random integer
|
|
local function pick_uniform(sample_size)
|
|
local value = sample_size / 2
|
|
return random.between(value - sample_size, value)
|
|
end
|
|
|
|
--- Shrinks an integer by dividing it by 2 and rounding towards 0.
|
|
-- @param previous previously generated integer value
|
|
-- @return shrunk down integer value
|
|
local function shrink(previous)
|
|
if previous == 0 then
|
|
return 0
|
|
end
|
|
if previous > 0 then
|
|
return math.floor(previous / 2)
|
|
end
|
|
return math.ceil(previous / 2)
|
|
end
|
|
|
|
--- Creates a generator for generating an integer between min and max.
|
|
-- @param min minimum value
|
|
-- @param max maximum value
|
|
-- @return generator that generates integers between min and max.
|
|
local function integer_between(min, max)
|
|
return Gen.new(pick_bounded(min, max), shrink_bounded(min, max))
|
|
end
|
|
|
|
--- Creates a generator for generating a positive integer between 0 and max.
|
|
-- @param max maximum value
|
|
-- @return generator that generates integer between 0 and max.
|
|
local function positive_integer(max)
|
|
return Gen.new(pick_bounded(0, max), shrink)
|
|
end
|
|
|
|
--- Creates a generator for generating an integer uniformly chosen
|
|
-- between +- sample_size / 2.
|
|
-- @return generator that can generate an integer
|
|
local function integer()
|
|
return Gen.new(pick_uniform, shrink)
|
|
end
|
|
|
|
--- Creates a new integer generator.
|
|
-- @param nr1 number containing first bound
|
|
-- @param nr2 number containing second bound
|
|
-- @return generator that can generate integers according to the following strategy:
|
|
-- - nr1 and nr2 provided: nr1 <= int <= nr2
|
|
-- - only nr1 provided: 0 <= int <= max
|
|
-- - no bounds provided: -numtests/2 <= int <= numtests/2
|
|
local function new(nr1, nr2)
|
|
if nr1 and nr2 then
|
|
return integer_between(nr1, nr2)
|
|
end
|
|
if nr1 then
|
|
return positive_integer(nr1)
|
|
end
|
|
return integer()
|
|
end
|
|
|
|
return new
|
|
|