local u = require('Module:Utils')
local p = {}
primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
map = {0, 0, 0}
lower = {0, 0 ,0} -- List of smallest sizes that match a map for each prime
upper = {0, 0, 0} -- List of largest sizes that match a map for each prime
pbi = 0 -- Index of the prime that defines the boundary
maptable = {} -- Table of uniform maps with boundaries and wart notation
-- Find the minimum size that corresponds to a given map
function lowerbound(map)
for i=1, #map do
lower[i] = (map[i]-1/2)/u._log(primes[i])
lowermax = math.max(unpack(lower))
end
return math.max(0, lowermax)
end
-- Find the maximum size that corresponds to a given map
function upperbound(map)
for i=1, #map do
upper[i] = (map[i]+1/2)/u._log(primes[i])
uppermin = math.min(unpack(upper))
pbi = u.index_of(upper, uppermin)
end
return math.max(0, uppermin)
end
lb = lowerbound(map) -- Minimum size for the current map
ub = upperbound(map) -- Maximum size for the current map
-- Find the p-limit just intonation point (JIP) corresponding to a given size
function JIP(size, p)
JIP_table = {}
for i=1, u.index_of(primes, p) do
JIP_table[i] = size*u._log(primes[i])
end
return JIP_table
end
-- Find the p-limit simple map corresponding to a given size
function simple_map(size, p)
simple_map_table = {}
for i=1, u.index_of(primes, p) do
simple_map_table[i] = u._round_dec(size*u._log(primes[i]))
end
return simple_map_table
end
-- Find the wart notation corresponding to a given map
function wart(map)
edo = map[1]
simple_map_edo = simple_map(edo, primes[#map])
JIP_edo = JIP(edo, primes[#map])
warts = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
wart_notation = edo
for i=2, #map do
-- direction is 1 if current harmonic mapped flatter than just, otherwise 0
direction = math.ceil(JIP_edo[i]-simple_map_edo[i])
difference = map[i]-simple_map_edo[i]
if difference ~= 0 then
number_warts = (2*math.abs(difference)+(u.signum((-1)^direction*difference)-1)/2)
for j=1,number_warts do
wart_notation = wart_notation .. warts[i]
end
end
end
return wart_notation
end
-- Generate table of p-limit uniform maps between min and max, for use with print_table
function make_table(p, min, max)
if u.index_of(primes, p) == nil then
print(p .. ' is not prime!')
return
else
maptable = {} -- Reset table
for i=1, u.index_of(primes, p) do
map[i] = 0 -- Reset to p-limit null map
lower[i] = 0
upper[i] = 0
end
map = simple_map(min, p) -- Set p-limit map for minimum size
lb = lowerbound(map) -- Update minimum size for new map
ub = upperbound(map) -- Update maximum size for new map
row = {'Min. size', 'Max. size', '[[Wart notation]]'}
for i=1, #map do
table.insert(row, primes[i])
end
table.insert(maptable, row)
while lb < max do
row = {string.format("%.4f", lb), string.format("%.4f", ub), wart(map)}
for j=1, #map do
table.insert(row, map[j])
end
table.insert(maptable, row)
map[pbi] = map[pbi] + 1
lb = lowerbound(map)
ub = upperbound(map)
end
return maptable
end
end
-- Print wiki-formatted table (string) of p-limit uniform maps between min and max
function p.print_table(frame)
local args = getArgs(frame)
return p._round_dec(args[1], args[2], args[3])
end
function p._print_table(p, min, max)
if u.index_of(primes, u.eval_num_arg(p, 5)) == nil then
print(p .. ' is not prime!')
return
end
luatable = make_table(p, u.eval_num_arg(min, 11.5), u.eval_num_arg(max, 12.5))
wikitable = string.format('{| class="wikitable"\n|+ %d-limit [[uniform map]]s between %f and %f', p, min, max)
for i=1, 3 do
wikitable = wikitable .. '\n! ' .. luatable[1][i]
end
wikitable = wikitable .. '\n! Map'
for i=2, #luatable do
wikitable = wikitable .. '\n|-'
for j=1, 3 do
wikitable = wikitable .. '\n| ' .. luatable[i][j]
end
wikitable = wikitable .. '\n| {{map|'
for j=1, #map do
wikitable = wikitable .. ' ' .. luatable[i][j+3]
end
wikitable = wikitable .. '}}'
end
wikitable = wikitable .. '\n|}'
return print(wikitable)
end
return p