Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
-- beta_math.lua: Beta distribution math helpers (companion data file)
-- Provides regularized incomplete beta function and its inverse (ppf).
-- Ported from engine/src/schedulers/scheduler-implementations.h
local M = {}
-- Log-gamma (uses Lua's built-in math library)
local function lgamma(x)
-- Lanczos approximation for log-gamma
if x <= 0 then return 0 end
local g = 7
local c = {
0.99999999999980993,
676.5203681218851,
-1259.1392167224028,
771.32342877765313,
-176.61502916214059,
12.507343278686905,
-0.13857109526572012,
9.9843695780195716e-6,
1.5056327351493116e-7
}
if x < 0.5 then
return math.log(math.pi / math.sin(math.pi * x)) - lgamma(1 - x)
end
x = x - 1
local a = c[1]
local t = x + g + 0.5
for i = 2, #c do
a = a + c[i] / (x + i - 1)
end
return 0.5 * math.log(2 * math.pi) + (x + 0.5) * math.log(t) - t + math.log(a)
end
-- Log of beta function: B(a,b) = Gamma(a)*Gamma(b)/Gamma(a+b)
local function lbeta(a, b)
return lgamma(a) + lgamma(b) - lgamma(a + b)
end
-- Regularized incomplete beta function via continued fraction (Lentz's method)
local function betainc(a, b, x)
if x <= 0 then return 0 end
if x >= 1 then return 1 end
-- Use symmetry for convergence
if x > (a + 1) / (a + b + 2) then
return 1 - betainc(b, a, 1 - x)
end
local ln_pre = a * math.log(x) + b * math.log(1 - x) - lbeta(a, b)
local qab = a + b
local qap = a + 1
local qam = a - 1
local c = 1
local d = 1 - qab * x / qap
if math.abs(d) < 1e-30 then d = 1e-30 end
d = 1 / d
local h = d
for m = 1, 200 do
local m2 = 2 * m
-- Even numerator
local aa = m * (b - m) * x / ((qam + m2) * (a + m2))
d = 1 + aa * d; if math.abs(d) < 1e-30 then d = 1e-30 end
c = 1 + aa / c; if math.abs(c) < 1e-30 then c = 1e-30 end
d = 1 / d; h = h * d * c
-- Odd numerator
aa = -((a + m) * (qab + m) * x) / ((a + m2) * (qap + m2))
d = 1 + aa * d; if math.abs(d) < 1e-30 then d = 1e-30 end
c = 1 + aa / c; if math.abs(c) < 1e-30 then c = 1e-30 end
d = 1 / d
local del = d * c; h = h * del
if math.abs(del - 1) < 3e-14 then break end
end
return math.exp(ln_pre) * h / a
end
-- Beta PDF
local function beta_pdf(x, a, b)
if x <= 0 or x >= 1 then return 0 end
return math.exp((a - 1) * math.log(x) + (b - 1) * math.log(1 - x) - lbeta(a, b))
end
-- Inverse CDF (ppf) via Newton's method
function M.ppf(p, a, b)
if p <= 0 then return 0 end
if p >= 1 then return 1 end
-- Initial guess
local mu = a / (a + b)
local var = a * b / ((a + b)^2 * (a + b + 1))
local sigma = math.sqrt(var)
local x = mu + sigma * (2 * p - 1)
if x < 0.001 then x = 0.001 end
if x > 0.999 then x = 0.999 end
-- Newton-Raphson
for _ = 1, 50 do
local F = betainc(a, b, x) - p
local f = beta_pdf(x, a, b)
if math.abs(f) < 1e-30 then break end
local dx = -F / f
x = x + dx
if x < 1e-10 then x = 1e-10 end
if x > 1 - 1e-10 then x = 1 - 1e-10 end
if math.abs(dx) < 1e-12 then break end
end
return x
end
return M