Skip to content

Commit 51f5090

Browse files
committed
Merge pull request kennyledet#215 from Yonaba/master
Added Weighted random distribution in Lua
2 parents 2acf39a + e8d86b7 commit 51f5090

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- Weighted/Biased random distribution implementation
2+
-- See : http://codetheory.in/weighted-biased-random-number-generation-with-javascript-based-on-probability/
3+
4+
-- Note: The sum of weights should be 1. That is, all
5+
-- weights are decimal values lower than 1.
6+
7+
-- Note: As all the implementations given below uses
8+
-- math.random, one can call math.randomseed with a
9+
-- custom seed before using them.
10+
11+
-- items : an array-list of values
12+
-- weights : a map table holding the weight for each value in
13+
-- in the `items` list.
14+
-- returns : an iterator function
15+
local function expanding_random(items, weights)
16+
local list = {}
17+
for _, item in ipairs(items) do
18+
local n = weights[item] * 100
19+
for i = 1, n do table.insert(list, item) end
20+
end
21+
return function()
22+
return list[math.random(1, #list)]
23+
end
24+
end
25+
26+
-- items : an array-list of values
27+
-- weights : a map table holding the weight for each value in
28+
-- in the `items` list.
29+
-- returns : an iterator function
30+
local function in_place_random(items, weights)
31+
local partial_sums, partial_sum = {}, 0
32+
for _, item in ipairs(items) do
33+
partial_sum = partial_sum + weights[item]
34+
table.insert(partial_sums, partial_sum)
35+
end
36+
return function()
37+
local n, s = math.random(), 0
38+
for i, si in ipairs(partial_sums) do
39+
s = s + si
40+
if si > n then return items[i] end
41+
end
42+
end
43+
end
44+
45+
return {
46+
expanding = expanding_random,
47+
in_place = in_place_random
48+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- Tests for weighted_random.lua
2+
local rand = require 'weighted_random'
3+
4+
-- Generates n random values
5+
local function gen(f, items, weights, n)
6+
local rnd = f(items, weights)
7+
local t = {}
8+
for i = 1, n do
9+
local val = rnd()
10+
t[val] = (t[val] or 0) + 1
11+
end
12+
for k,v in pairs(t) do
13+
print((' >> %s : %d (%.2f %%)'):format(k, v, 100*v/n))
14+
end
15+
end
16+
17+
print(('-'):rep(80))
18+
local items = {'a', 'b', 'c', 'd', 'e'}
19+
local weights = {a = 0.1, b = 0.2, c = 0.3, d = 0.2, e = 0.2}
20+
print('In-place random distribution')
21+
gen(rand.in_place, items, weights, 1e6)
22+
print('\nExpanding random distribution')
23+
gen(rand.expanding, items, weights, 1e6)
24+
print(('-'):rep(80))

0 commit comments

Comments
 (0)