Module:Harmonic entropy: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
Plumtree (talk | contribs)
mNo edit summary
ArrowHead294 (talk | contribs)
Remove already finished Todo
 
(12 intermediate revisions by 3 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 l = require('Module:Limits')
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)
local args = getArgs(frame)
return p._to_cents(args[1], args[2])
end
 
function p._to_cents(ratio, prec)
-- ratio defaults to 1
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
 
-- compute harmonic Shannon entropy for an interval of `c` cents
-- `c`, `deviation`: in cents
-- `c`, `deviation`: in cents
-- `ratios`: an array of rational numbers
-- `ratios`: an array of rational numbers
Line 32: Line 11:
return math.sqrt(rat.benedetti_height(ratio))
return math.sqrt(rat.benedetti_height(ratio))
end
end
deviation = deviation or 17
deviation = deviation or 1200 * math.log(1.01, 2)
ratios = ratios or l.integer_limit(
ratios = ratios
200,
or limits.integer_limit(200, function(ratio)
function(ratio)
if math.abs(rat.cents(ratio) - c) > 3 * deviation then
if math.abs(rat.cents(ratio) - c) > 3 * deviation then
return 1/0
return 1 / 0
end
end
return norm(ratio)
return norm(ratio)
end,
end, 100)
100
 
)
local function gaussian(x)
return math.exp(-x * x / (2 * deviation * deviation)) / (deviation * math.sqrt(2 * math.pi))
local function S(x)
return math.exp(-x*x / (2*deviation*deviation)) / (deviation * math.sqrt(2*math.pi))
end
end
local function Q(ratio)
 
return S(rat.cents(ratio) - c) / norm(ratio)
local function weighted_gaussian(ratio)
return gaussian(rat.cents(ratio) - c) / norm(ratio)
end
end
 
local Q_norm = 0
local q_norm = 0
for i, ratio in pairs(ratios) do
for _, ratio in pairs(ratios) do
Q_norm = Q_norm + Q(ratio)
q_norm = q_norm + weighted_gaussian(ratio)
end
end
 
local function P(ratio)
local function probability(ratio)
return Q(ratio) / Q_norm
return weighted_gaussian(ratio) / q_norm
end
end
 
local entropy = 0
local entropy = 0
for i, ratio in pairs(ratios) do
for _, ratio in pairs(ratios) do
local P_i = P(ratio)
local p_i = probability(ratio)
if P_i > 1e-5 then
if p_i > 1e-5 then
entropy = entropy - P_i * math.log(P_i)
entropy = entropy - p_i * math.log(p_i)
end
end
end
end

Latest revision as of 13:53, 13 June 2024

Module documentation[view] [edit] [history] [purge]
This module primarily serves as a library for other modules and has no corresponding template.

This module provides a means to calculate harmonic Shannon entropy of a particular interval.


Introspection summary for Module:Harmonic entropy 
Functions provided (1)
Line Function Params Description
9 harmonic_entropy (c, ratios, deviation, norm) Computes harmonic Shannon entropy of an interval of c cents across ratios with a Gaussian with standard deviation (also in cents) and a norm associated with the ratios.
Lua modules required (2)
Variable Module Functions used
limits Module:Limits integer_limit
rat Module:Rational benedetti_height
cents

local limits = require("Module:Limits")
local rat = require("Module:Rational")
local p = {}

-- Compute Harmonic Shannon entropy for an interval of `c` cents
-- `c`, `deviation`: in cents
-- `ratios`: an array of rational numbers
-- `norm`: a function of rational numbers
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)

	local function gaussian(x)
		return math.exp(-x * x / (2 * deviation * deviation)) / (deviation * math.sqrt(2 * math.pi))
	end

	local function weighted_gaussian(ratio)
		return gaussian(rat.cents(ratio) - c) / norm(ratio)
	end

	local q_norm = 0
	for _, ratio in pairs(ratios) do
		q_norm = q_norm + weighted_gaussian(ratio)
	end

	local function probability(ratio)
		return weighted_gaussian(ratio) / q_norm
	end

	local entropy = 0
	for _, ratio in pairs(ratios) do
		local p_i = probability(ratio)
		if p_i > 1e-5 then
			entropy = entropy - p_i * math.log(p_i)
		end
	end
	return entropy
end

return p