Module:Harmonic entropy: Difference between revisions

Updated to_cents: doesn't round by default now
ArrowHead294 (talk | contribs)
Remove already finished Todo
 
(29 intermediate revisions by 5 users not shown)
Line 1: Line 1:
local getArgs = require('Module:Arguments').getArgs
local limits = require("Module:Limits")
local u = require('Module:Utils')
local rat = require("Module:Rational")
local p = {}
local p = {}


-- return measure in cents of an interval ratio, rounded to prec decimal places
-- Compute Harmonic Shannon entropy for an interval of `c` cents
function p.to_cents(frame)
-- `c`, `deviation`: in cents
local args = getArgs(frame)
-- `ratios`: an array of rational numbers
return p._to_cents(args[1], args[2])
-- `norm`: a function of rational numbers
end
function p.harmonic_entropy(c, ratios, deviation, norm)
norm = norm or function(ratio)
return math.sqrt(rat.benedetti_height(ratio))
end
deviation = deviation or 1200 * math.log(1.01, 2)
ratios = ratios
or limits.integer_limit(200, function(ratio)
if math.abs(rat.cents(ratio) - c) > 3 * deviation then
return 1 / 0
end
return norm(ratio)
end, 100)


function p._to_cents(ratio, prec)
local function gaussian(x)
-- ratio defaults to 1
return math.exp(-x * x / (2 * deviation * deviation)) / (deviation * math.sqrt(2 * math.pi))
ratio = u.eval_num_arg(ratio, 1)
-- prec defaults to nil
prec = u.eval_num_arg(prec)
local result = 1200*u._log(ratio), prec
if prec == nil then
return result
else
return u._round(result, prec)
end
end
end


-- return ratio corresponding to an interval written in backslash notation
local function weighted_gaussian(ratio)
-- edf = ed3/2, edo = ed2, edt = ed3
return gaussian(rat.cents(ratio) - c) / norm(ratio)
local equaves =
end
{
  ['f'] = 3/2,
  ['o'] = 2,
  ['t'] = 3
}


function p.backslash_ratio(frame)
local q_norm = 0
local args = getArgs(frame)
for _, ratio in pairs(ratios) do
return p._backslash_ratio(args[1])
q_norm = q_norm + weighted_gaussian(ratio)
end
end
 
local function probability(ratio)
return weighted_gaussian(ratio) / q_norm
end


function p._backslash_ratio(input)
local entropy = 0
-- result defaults to 0
for _, ratio in pairs(ratios) do
local result = 0
local p_i = probability(ratio)
-- "steps" of "size" equal divisions of "equave" (c/d), defaults to 0\12(edo)
if p_i > 1e-5 then
local steps, size, equave = 0, 12, 2
entropy = entropy - p_i * math.log(p_i)
-- edf = ed3/2, edo = ed2, edt = ed3
end
input = string.lower(input)
steps, size = input:match("^%s*([0-9]*)\\([0-9]*).-$")
if input:match("^[0-9]*\\[0-9]*[%-]?ed[fot]$") then
equave = equaves[tostring(input:match("[fot]"))]
else
equave = u.eval_num_arg(input:match("^.-ed(.-)%s*$") or 2)
end
end
result = tonumber(equave)^(tonumber(steps)/tonumber(size))
return entropy
return result
end
end


return p
return p