Module:Limits: Difference between revisions
Distinct consistency of 0edo should be 1 |
ArrowHead294 (talk | contribs) mNo edit summary |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
local p = {} | |||
local ET = require("Module:ET") | |||
local rat = require("Module:Rational") | local rat = require("Module:Rational") | ||
-- | -- returns a table of all positive q-equave-limit ratios if the equave is provided | ||
-- n/m with n and m <= q modulo powers of equave | |||
-- otherwise q-integer-limit ratios | |||
-- previous: already computed ratios for q - 1 | -- previous: already computed ratios for q - 1 | ||
function p.limit_modulo_equave(q, equave, previous) | function p.limit_modulo_equave(q, equave, previous) | ||
local ratios = {} | local ratios = {} | ||
if previous then | if previous then | ||
for n = 1, q do | for n = 1, q do | ||
local a = rat.new(n, q) | local a = rat.new(n, q) | ||
a = rat.modulo_mul(a, equave) | local b = rat.new(q, n) | ||
if equave then | |||
a = rat.modulo_mul(a, equave) | |||
b = rat.modulo_mul(b, equave) | |||
end | |||
local a_key = rat.as_ratio(a) | local a_key = rat.as_ratio(a) | ||
local b_key = rat.as_ratio(b) | local b_key = rat.as_ratio(b) | ||
Line 29: | Line 32: | ||
for m = 1, q do | for m = 1, q do | ||
local a = rat.new(n, m) | local a = rat.new(n, m) | ||
a = rat.modulo_mul(a, equave) | if equave then | ||
a = rat.modulo_mul(a, equave) | |||
end | |||
local key = rat.as_ratio(a) | local key = rat.as_ratio(a) | ||
ratios[key] = a | ratios[key] = a | ||
Line 38: | Line 43: | ||
end | end | ||
-- | -- returns a table of all q-integer-limit ratios | ||
-- if a function `norm` and a number `max_norm` are provided, the output will be additionally restricted | -- if a function `norm` and a number `max_norm` are provided, the output will be additionally restricted | ||
function p.integer_limit(q, norm, max_norm) | function p.integer_limit(q, norm, max_norm) | ||
Line 55: | Line 60: | ||
end | end | ||
-- check additive consistency for a set of ratios | -- check additive consistency for a set of ratios of an equal tuning | ||
-- approx(a*b) = approx(a) + approx(b) for all a, b: a, b, | -- approx(a*b) = approx(a) + approx(b) for all a, b: a, b, a*b in ratios | ||
-- `use_equave`: whether check consistency modulo powers of the tuning's formal equave | |||
-- - we don't allow arbitrary equaves here | |||
-- - since consistency only makes sense if the equave is pure | |||
-- `distinct`: whether distinct ratios are required to be mapped to distinct approximations | -- `distinct`: whether distinct ratios are required to be mapped to distinct approximations | ||
-- `previous`: already computed ratios for the previous iteraton | -- `previous`: already computed ratios for the previous iteraton | ||
function p.additively_consistent(et, ratios, distinct, previous) | function p.additively_consistent(et, ratios, use_equave, distinct, previous) | ||
distinct = distinct or false | distinct = distinct or false | ||
previous = previous or {} | previous = previous or {} | ||
-- distinction check | |||
-- approx_set stores ratios and their directly approximated number of steps as keys | |||
-- we find the number of steps for every ratio and check if this number is taken | |||
-- if it's taken, we compare the ratio in question with the stored one | |||
-- if they're unequal, it means different ratios are mapped to the same step | |||
-- therefore distinction isn't satisfied | |||
-- otherwise, we add the ratio and step number to approx_set | |||
-- we do this to previous and new ratios alike | |||
if distinct then | if distinct then | ||
local approx_set = {} | local approx_set = {} | ||
for a_key, a in pairs(previous) do | for a_key, a in pairs(previous) do | ||
local a_approx = ET.approximate(et, rat.as_float(a)) % et.size | local a_approx = use_equave and ET.approximate(et, rat.as_float(a)) % et.size | ||
or ET.approximate(et, rat.as_float(a)) | |||
if approx_set[a_approx] then | if approx_set[a_approx] then | ||
if not rat.eq(rat.modulo_mul(rat.div(a, approx_set[a_approx]), et.equave), 1) then | if use_equave and not rat.eq(rat.modulo_mul(rat.div(a, approx_set[a_approx]), et.equave), 1) | ||
or not rat.eq(a, approx_set[a_approx]) then | |||
mw.log(a_key .. " -> " .. a_approx .. ": conflict!") | mw.log(a_key .. " -> " .. a_approx .. ": conflict!") | ||
return false | return false | ||
Line 76: | Line 95: | ||
end | end | ||
for a_key, a in pairs(ratios) do | for a_key, a in pairs(ratios) do | ||
local a_approx = ET.approximate(et, rat.as_float(a)) % et.size | local a_approx = use_equave and ET.approximate(et, rat.as_float(a)) % et.size | ||
or ET.approximate(et, rat.as_float(a)) | |||
if approx_set[a_approx] then | if approx_set[a_approx] then | ||
if not rat.eq(rat.modulo_mul(rat.div(a, approx_set[a_approx]), et.equave), 1) then | if use_equave and not rat.eq(rat.modulo_mul(rat.div(a, approx_set[a_approx]), et.equave), 1) | ||
or not rat.eq(a, approx_set[a_approx]) then | |||
mw.log(a_key .. " -> " .. a_approx .. ": conflict!") | mw.log(a_key .. " -> " .. a_approx .. ": conflict!") | ||
return false | return false | ||
Line 87: | Line 108: | ||
end | end | ||
end | end | ||
-- ??? | |||
if type(distinct) == "number" then | if type(distinct) == "number" then | ||
return true | return true | ||
end | end | ||
local previous_ordered = {} | local previous_ordered = {} | ||
for _, a in pairs(previous) do | for _, a in pairs(previous) do | ||
Line 106: | Line 130: | ||
local c_approx = ET.approximate(et, rat.as_float(c)) | local c_approx = ET.approximate(et, rat.as_float(c)) | ||
c = rat.modulo_mul(c, et.equave) | if use_equave then | ||
c = rat.modulo_mul(c, et.equave) | |||
end | |||
local c_key = rat.as_ratio(c) | local c_key = rat.as_ratio(c) | ||
if previous[c_key] or ratios[c_key] then | if previous[c_key] or ratios[c_key] then | ||
Line 122: | Line 148: | ||
local c = rat.mul(a, b) | local c = rat.mul(a, b) | ||
local c_approx = ET.approximate(et, rat.as_float(c)) | local c_approx = ET.approximate(et, rat.as_float(c)) | ||
c = rat.modulo_mul(c, et.equave) | if use_equave then | ||
c = rat.modulo_mul(c, et.equave) | |||
end | |||
local c_key = rat.as_ratio(c) | local c_key = rat.as_ratio(c) | ||
if previous[c_key] or ratios[c_key] then | if previous[c_key] or ratios[c_key] then | ||
Line 138: | Line 166: | ||
end | end | ||
-- find additive consistency limit | -- find additive consistency limit of an equal tuning | ||
-- `distinct`: whether distinct ratios are required to be mapped to distinct approximations | -- `distinct`: whether distinct ratios are required to be mapped to distinct approximations | ||
-- - if an integer, it is the regular consistency limit already known | -- - if an integer, it is the regular consistency limit already known (why?) | ||
-- `max_n`: returns nil if the result is equal to or greater than this | |||
function p.consistency_limit(et, distinct, max_n) | function p.consistency_limit(et, distinct, max_n) | ||
Line 153: | Line 181: | ||
end | end | ||
-- use the equave iff the tuning is an edo | |||
local use_equave = rat.eq (et.equave, rat.new (2, 1)) | |||
max_n = max_n or 1 / 0 | max_n = max_n or 1 / 0 | ||
distinct = distinct or false | distinct = distinct or false | ||
Line 162: | Line 192: | ||
return last_n | return last_n | ||
end | end | ||
local ratios = p.limit_modulo_equave(n, et.equave, previous) | local ratios = p.limit_modulo_equave(n, use_equave and et.equave or nil, previous) | ||
for key, _ in pairs(ratios) do | for key, _ in pairs(ratios) do | ||
mw.log("step " .. n .. ": " .. key) | mw.log("step " .. n .. ": " .. key) | ||
end | end | ||
if next(ratios) ~= nil then | if next(ratios) ~= nil then | ||
local consistent = p.additively_consistent(et, ratios, distinct, previous) | local consistent = p.additively_consistent(et, ratios, use_equave, distinct, previous) | ||
if not consistent then | if not consistent then | ||
mw.log("Not consistent at step " .. n .. ", returning " .. last_n) | mw.log("Not consistent at step " .. n .. ", returning " .. last_n) |