Module:Infobox interval
From XenReference
Documentation for this module may be created at Module:Infobox interval/doc
local p = {}
local infobox = require("Module:Infobox")
local rat = require("Module:Rational")
local utils = require("Module:Utils")
local yesno = require("Module:Yesno")
-- check whether the input is a non-empty string
local function value_provided(s)
return type(s) == "string" and #s > 0
end
function p.infobox_interval(frame)
local debug_mode = yesno(frame.args["debug"])
local page_name = frame:preprocess("{{PAGENAME}}")
local rational = false
local small = false -- numerator and denominator can be represented as Lua numbers, or irrational
local regular = false -- finite and greater than zero
local ratio = nil
local cents = nil
local ket = nil
local ratio_string = nil
local infobox_data = {}
local cats = ""
-- intervals with relatively small powers
if value_provided(frame.args["Ratio"]) then
ratio = rat.parse(frame.args["Ratio"])
if ratio ~= nil then
rational = true
small = true
regular = not ratio.nan and not ratio.inf and not ratio.zero and ratio.sign > 0
cents = rat.cents(ratio)
ket = rat.as_ket(ratio, frame)
ratio_string = rat.as_ratio(ratio)
end
end
-- intervals with large powers
if ratio == nil and value_provided(frame.args["Ket"]) then
ratio = rat.from_ket(frame.args["Ket"])
if ratio ~= nil then
rational = true
small = false
regular = true
cents = rat.cents(ratio)
ket = rat.as_ket(ratio, frame)
-- display Ratio unless it is page name, in which case it is probably a fallback -- what does this mean?
if frame.args["Ratio"] ~= page_name then
ratio_string = frame.args["Ratio"] or ""
end
end
elseif ratio ~= nil and value_provided(frame.args["Ket"]) then
cats = cats .. "[[Category:Todo:remove explicit ket notation]]"
end
-- irrational intervals
if ratio == nil and value_provided(frame.args["Cents"]) then
cents = tonumber(frame.args["Cents"])
if cents ~= nil then
rational = false
small = true
regular = true
if value_provided(frame.args["Ket"]) then
ket = frame.args["Ket"]
end
-- Ratio is LaTeX unless it is page name, in which case it is probably a fallback -- what does this mean?
if frame.args["Ratio"] ~= page_name then
ratio_string = frame.args["Ratio"] or ""
else
cats = cats .. "[[Category:Todo:add interval ratio]]"
end
end
elseif ratio ~= nil and value_provided(frame.args["Cents"]) then
cats = cats .. "[[Category:Todo:remove explicit cents]]"
end
if not (regular or rational) then
cats = cats .. "[[Category:Todo:initialise interval]]"
end
-- categorize by rationality and prime limit
if regular then
if rational then
local prime_limit = 2
if not rat.eq(ratio, 1) then
prime_limit = rat.max_prime(ratio)
end
cats = cats .. "[[Category:Rational intervals]]" .. "[[Category:" .. prime_limit .. "-limit intervals]]"
else
cats = cats .. "[[Category:Irrational intervals]]"
end
end
local special_properties = {}
if rational then
if small and rat.is_superparticular(ratio) then
if rat.is_square_superparticular(ratio) then
table.insert(special_properties, "[[Square superparticular|square superparticular]]")
else
table.insert(special_properties, "[[Superparticular interval|superparticular]]")
end
cats = cats .. "[[Category:Superparticular ratios]]"
end
if rat.is_reduced(ratio, 2, not small) then
table.insert(special_properties, "[[Octave reduction|reduced]]")
end
if rat.is_harmonic(ratio) then
num, den = rat.as_pair (ratio)
table.insert(special_properties, "[[harmonic]]")
cats = cats .. "[[Category:Harmonics|" .. string.rep("#", string.len(num)) .. "]]"
if rat.is_prime(ratio) then
table.insert(special_properties, "[[prime harmonic]]")
cats = cats .. "[[Category:Prime harmonics|" .. string.rep("#", string.len(num)) .. "]]"
end
if rat.is_highly_composite(ratio) then
table.insert(special_properties, "[[highly composite harmonic]]")
cats = cats .. "[[Category:Highly composite harmonics|" .. string.rep("#", string.len(num)) .. "]]"
end
elseif rat.is_harmonic(ratio, true, not small) then
table.insert(special_properties, "[[Harmonic|reduced harmonic]]")
cats = cats .. "[[Category:Octave-reduced harmonics]]"
elseif rat.is_subharmonic(ratio, true, not small) then
table.insert(special_properties, "[[Subharmonic|reduced subharmonic]]")
cats = cats .. "[[Category:Octave-reduced subharmonics]]"
end
elseif regular then
if cents >= 0 and cents < 1200 then
table.insert(special_properties, "[[Octave reduction|reduced]]")
end
end
if value_provided(ratio_string) then
if rational then
table.insert(infobox_data, {
"Ratio",
ratio_string,
})
else
table.insert(infobox_data, {
"Expression",
"<math>" .. ratio_string .. "</math>",
})
end
end
if regular and rational then
if ket:match("<sup>") then
-- there was a subsequence of 4+ zeros
table.insert(infobox_data, {
"[[Interval space|Subgroup monzo]]",
rat.as_subgroup_ket(ratio, frame),
})
else
table.insert(infobox_data, {
"Factorization",
rat.factorisation(ratio),
})
table.insert(infobox_data, {
"[[Interval space|Monzo]]",
ket,
})
end
elseif rational then
table.insert(infobox_data, {
"Factorization",
rat.factorisation(ratio),
})
elseif value_provided(ket) then
-- irrational ket is provided:
table.insert(infobox_data, {
"[[Interval space|Monzo]]",
frame:expandTemplate({
title = "Monzo",
args = { ket },
}),
})
end
if regular then
table.insert(infobox_data, {
"Size in [[cent]]s",
utils._round(cents, 7) .. "¢",
})
end
local name = frame.args["Name"]
if value_provided(name) then
local caption = "Name"
if name:match(",") then
caption = "Names"
-- removing manual line breaks
local matches
name, matches = name:gsub("<br%s*/?>", "")
-- removing whitespaces after commas
name = name:gsub(",%s+", ",")
-- placing line breaks after commas
name = name:gsub(",", ",<br>")
end
table.insert(infobox_data, {
caption,
name,
})
else
table.insert(infobox_data, {
"Name(s)",
"<abbr title=\"missing value for parameter 'Name'\">''missing''</abbr><sup>[[Template:Infobox Interval| ? ]]</sup>",
})
end
if #special_properties > 0 then
table.insert(infobox_data, {
"Special properties",
table.concat(special_properties, ",<br>"),
})
end
-- interval complexity
if rational and regular then
table.insert(infobox_data, {
"{{adv|Harmonic distance (log<sub>2</sub> ''nd'')}}",
"{{adv|" .. utils._round(rat.tenney_height(ratio), 6) .. "}}",
})
table.insert(infobox_data, {
"{{adv|Wilson norm (sopfr(''nd''))}}",
"{{adv|" .. utils._round(rat.wilson_height(ratio), 6) .. "}}",
})
end
if value_provided(frame.args["Calc"]) or (regular and rational) then
local query = frame.args["Calc"] or ""
if not value_provided(query) then
if small then
query = ratio_string
else
query = "|" .. rat.as_ket(ratio, nil, false, true) .. ">"
end
end
query = mw.uri.encode(query)
table.insert(infobox_data, {
"<span style=\"font-size: 75%;\">[https://www.yacavone.net/xen-calc/?q=" .. query .. " Open this interval in ''xen-calc'']</span>",
})
end
local result = infobox.build("<u>Interval information</u>", infobox_data)
if not debug_mode then
result = result
end
return frame:preprocess(result)
end
return p
