supp-ran.lua /size: 4332 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['supp-ran'] = {
2    version   = 1.001,
3    comment   = "companion to supp-ran.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9-- We cannot ask for the current seed, so we need some messy hack here.
10
11local report_system = logs.reporter("system","randomizer")
12
13local trace_random  = false  trackers.register("system.randomizer",         function(v) trace_random  = v end)
14local trace_details = false  trackers.register("system.randomizer.details", function(v) trace_details = v end)
15
16local insert, remove = table.insert, table.remove
17
18local math       = math
19local context    = context
20local implement  = interfaces.implement
21
22local random     = math.random
23local randomseed = math.randomseed
24local round      = math.round
25local stack      = { }
26local last       = 1
27local maxcount   = 0x3FFFFFFF -- 2^30-1
28
29math.random = function(...)
30    local n = random(...)
31    if trace_details then
32        report_system("math %s",n)
33    end
34    return n
35end
36
37local function setrandomseedi(n)
38    if n <= 1 then
39        n = n * maxcount
40    elseif n < 1000 then
41        n = n * 1000
42    end
43    n = round(n)
44    randomseed(n)
45    last = random(0,maxcount) -- we need an initial value
46    if trace_details then
47        report_system("seed %s from %s",last,n)
48    elseif trace_random then
49        report_system("setting seed %s",n)
50    end
51end
52
53math.setrandomseedi = setrandomseedi
54
55local function getrandomnumber(min,max)
56    if min > max then
57        min, max = max, min
58    end
59    last = random(min,max)
60    if trace_details then
61        report_system("number %s",last)
62    end
63    return last
64end
65
66local function setrandomseed(n)
67    last = n
68    setrandomseedi(n)
69end
70
71local function getrandomseed()
72    return last
73end
74
75-- local function getmprandomnumber()
76--     last = random(0,4095)
77--     if trace_details then
78--         report_system("mp number %s",last)
79--     end
80--     return last
81-- end
82
83-- maybe stack
84
85local function pushrandomseed()
86 -- insert(stack,last) -- doesn't work okay
87    insert(stack,randomseed(last) or last)
88    if trace_random or trace_details then
89        report_system("pushing seed %s",last)
90    end
91end
92
93local function reuserandomseed(n)
94    local seed = stack[#stack]
95    if seed then
96        if trace_random or trace_details then
97            report_system("reusing seed %s",last)
98        end
99        randomseed(seed)
100    end
101end
102
103local function poprandomseed()
104    local seed = remove(stack)
105    if seed then
106        if trace_random or trace_details then
107            report_system("popping seed %s",seed)
108        end
109        randomseed(seed)
110    end
111end
112
113local function getrandom(where,...)
114    if type(where) == "string" then
115        local n = random(...)
116        if trace_details then
117            report_system("%s %s",where,n)
118        end
119        return n
120    else
121        local n = random(where,...)
122        if trace_details then
123            report_system("utilities %s",n)
124        end
125        return n
126    end
127end
128
129utilities.randomizer = {
130    setseedi    = setrandomseedi,
131    getnumber   = getrandomnumber,
132    setseed     = setrandomseed,
133    getseed     = getrandomseed,
134 -- getmpnumber = getmprandomnumber,
135    pushseed    = pushrandomseed,
136    reuseseed   = reuserandomseed,
137    popseed     = poprandomseed,
138    get         = getrandom,
139    -- the original, only for testing
140 -- mathrandom  = random,
141}
142
143-- todo: also open up in utilities.randomizer.*
144
145implement { name = "getrandomnumber",   actions = { getrandomnumber, context }, arguments = { "integer", "integer" } }
146implement { name = "getrandomdimen",    actions = { getrandomnumber, context }, arguments = { "dimen", "dimen" } }
147implement { name = "getrandomfloat",    actions = { getrandomnumber, context }, arguments = { "number", "number" } }
148implement { name = "getrandomseed",     actions = { getrandomseed,   context } }
149implement { name = "setrandomseed",     actions = setrandomseed, arguments = "integer" }
150implement { name = "pushrandomseed",    actions = pushrandomseed, public = true, }
151implement { name = "poprandomseed",     actions = poprandomseed, public = true, }
152implement { name = "reuserandomseed",   actions = reuserandomseed, public = true, }
153
154