Module:Mediants: Difference between revisions
Jump to navigation
Jump to search
Filter functions -> Search functions, since filtering should suggest finer control over what ratios are allowed, which cannot be done with search functions which limit how far to look for ratios; may potentially break dependent templates |
Removed tenney height search (for now); comments/todo |
||
| Line 4: | Line 4: | ||
-- Module for finding mediants, either by search depth or by search function. | -- Module for finding mediants, either by search depth or by search function. | ||
-- TODO: Add int-limit search | |||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
| Line 19: | Line 21: | ||
-- A search function has two params: a table containing the mediant and the | -- A search function has two params: a table containing the mediant and the | ||
-- depth it was found at, and a search param | -- depth it was found at, and a search param. | ||
-- | -- Mediant data, the first param, is of the form: | ||
-- { ["mediant"] = { p, q }, ["depth"] = d }, where, p, q, d are integers. | |||
-- The search params can be a single numeric value, or a table of values for | |||
-- finer control. | |||
-- Int limit search determines whether a ratio is within an int limit. Does not | -- Int limit search determines whether a ratio is within an int limit. Does not | ||
-- use depth. | -- use depth. Meant for use with searching for JI ratios. | ||
function p.int_limit_search(mediant_data, int_limit) | function p.int_limit_search(mediant_data, int_limit) | ||
local mediant = mediant_data["mediant"] | local mediant = mediant_data["mediant"] | ||
| Line 30: | Line 35: | ||
-- Depth search determines whether a ratio is within a target depth. Does not | -- Depth search determines whether a ratio is within a target depth. Does not | ||
-- use the mediant itself. | -- use the mediant itself. Meant for use with searching for step ratios. | ||
function p.depth_search(mediant_data, search_depth) | function p.depth_search(mediant_data, search_depth) | ||
local depth = mediant_data["depth"] | local depth = mediant_data["depth"] | ||
return depth <= search_depth | return depth <= search_depth | ||
end | end | ||
| Line 113: | Line 111: | ||
-- Depth-based search finds mediants by building a tree of mediants up to a | -- Depth-based search finds mediants by building a tree of mediants up to a | ||
-- specified depth. This is made a standalone function under the reasoning that | -- specified depth. This is made a standalone function under the reasoning that | ||
-- | -- it's a common enough operation. | ||
-- Find mediants by depth, how many times mediants are found in a set of ratios. | -- Find mediants by depth, how many times mediants are found in a set of ratios. | ||
| Line 138: | Line 135: | ||
return ratios | return ratios | ||
end | end | ||
-------------------------------------------------------------------------------- | |||
---------------------- INT-LIMIT-BASED SEARCH FUNCTION ------------------------- | |||
-------------------------------------------------------------------------------- | |||
-- Int limit search finds mediants up to an integer limit, not permitting ratios | |||
-- whose numerator or denominator exceeds the int limit. This is made a stand- | |||
-- alone function under the reasoning that it's a common enough operation. | |||
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
Revision as of 23:49, 14 September 2024
- This module primarily serves as a library for other modules and has no corresponding template.
Module:Mediants is used for finding mediants starting from a set of starting ratios (by default, 1/1 and 1/0), either by search depth, integer limit, or by a custom search function.
| Introspection summary for Module:Mediants | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||||||||||||||||||||||||||
No function descriptions were provided. The Lua code may have further information.
local mos = require("Module:MOS") -- For testing
local utils = require("Module:Utils") -- For testing
local p = {}
-- Module for finding mediants, either by search depth or by search function.
-- TODO: Add int-limit search
--------------------------------------------------------------------------------
------------------------------- SEARCH FUNCTIONS -------------------------------
--------------------------------------------------------------------------------
-- Search functions determine whether a mediant meets a specific criteria for
-- being added to a set of mediants, be it based on something about the mediant,
-- its search depth, or both.
-- NOTE: some search criteria, such as prime limit, are considered unsuitable,
-- since mediants not within a prime limit are used to find ratios within a
-- prime limit, it will likely prevent desired ratios from being found at all.
-- For this reason, these functions are meant for broad search, and finer
-- filtering must be done afterwards.
-- A search function has two params: a table containing the mediant and the
-- depth it was found at, and a search param.
-- Mediant data, the first param, is of the form:
-- { ["mediant"] = { p, q }, ["depth"] = d }, where, p, q, d are integers.
-- The search params can be a single numeric value, or a table of values for
-- finer control.
-- Int limit search determines whether a ratio is within an int limit. Does not
-- use depth. Meant for use with searching for JI ratios.
function p.int_limit_search(mediant_data, int_limit)
local mediant = mediant_data["mediant"]
return math.max(mediant[1], mediant[2]) <= int_limit
end
-- Depth search determines whether a ratio is within a target depth. Does not
-- use the mediant itself. Meant for use with searching for step ratios.
function p.depth_search(mediant_data, search_depth)
local depth = mediant_data["depth"]
return depth <= search_depth
end
--------------------------------------------------------------------------------
---------------------------- GENERAL SEARCH FUNCTION ---------------------------
--------------------------------------------------------------------------------
-- General search function searches for mediants using a filter function. A
-- custom filter function can be passed in to "filter" out mediants. Ratios
-- are added using a while loop, which exits if a loop iteration adds no new
-- ratios.
-- Find mediants by filter, where the filter function and its args are passed in
-- as part of the function call.
function p.find_mediants_by_search_func(init_ratios, search_func, search_args)
local init_ratios = init_ratios or {{1,1}, {1,0}}
local ratios = {}
local depths = {}
for i = 1, #init_ratios do
table.insert(ratios, init_ratios[i])
table.insert(depths, 0)
end
local new_ratios_added = true
while new_ratios_added do
new_ratios_added = false
local new_ratios = {}
local new_depths = {}
for i = 1, #ratios-1 do
local ratio_1 = ratios[i]
local ratio_2 = ratios[i+1]
local mediant = { ratio_1[1] + ratio_2[1], ratio_1[2] + ratio_2[2] }
table.insert(new_ratios, ratio_1)
local depth_1 = depths[i]
local depth_2 = depths[i+1]
local new_depth = math.max(depth_1, depth_2) + 1
table.insert(new_depths, depth_1)
local mediant_data = { ["mediant"] = mediant, ["depth"] = new_depth }
if search_func(mediant_data, search_args) then
table.insert(new_ratios, mediant)
table.insert(new_depths, new_depth)
new_ratios_added = true
end
end
table.insert(new_ratios, ratios[#ratios])
table.insert(new_depths, depths[#depths])
ratios = new_ratios
depths = new_depths
end
return ratios, depths
end
-- Find mediants by filter, where the filter function and its args are passed in
-- as part of the function call. Only returns mediants, not depths.
function p.find_only_mediants_by_search_func(init_ratios, search_func, search_args)
local init_ratios = init_ratios or {{1,1}, {1,0}}
local ratios, depths
ratios, depths = p.find_mediants_by_search_func(init_ratios, search_func, search_args)
return ratios
end
--------------------------------------------------------------------------------
------------------------- DEPTH-BASED SEARCH FUNCTION --------------------------
--------------------------------------------------------------------------------
-- Depth-based search finds mediants by building a tree of mediants up to a
-- specified depth. This is made a standalone function under the reasoning that
-- it's a common enough operation.
-- Find mediants by depth, how many times mediants are found in a set of ratios.
function p.find_mediants(init_ratios, depth)
local init_ratios = init_ratios or {{1,1}, {1,0}}
local depth = depth or 5
local ratios, depths
ratios, depths = p.find_mediants_by_search_func(init_ratios, p.depth_search, depth)
return ratios, depths
end
-- Find mediants by depth, how many times mediants are found in a set of ratios.
-- Does not return depths.
function p.find_only_mediants(init_ratios, depth)
local init_ratios = init_ratios or {{1,1}, {1,0}}
local depth = depth or 5
local ratios, depths
ratios, depths = p.find_mediants_by_search_func(init_ratios, p.depth_search, depth)
return ratios
end
--------------------------------------------------------------------------------
---------------------- INT-LIMIT-BASED SEARCH FUNCTION -------------------------
--------------------------------------------------------------------------------
-- Int limit search finds mediants up to an integer limit, not permitting ratios
-- whose numerator or denominator exceeds the int limit. This is made a stand-
-- alone function under the reasoning that it's a common enough operation.
--------------------------------------------------------------------------------
----------------------------------- TESTER -------------------------------------
--------------------------------------------------------------------------------
function p.tester()
local func = p.int_limit_search
local ratios, depths = p.find_mediants_by_search_func({{1,1}, {1,0}}, func, 50)
--ratios, depths = p.find_mediants({{1,1}, {1,0}}, 7)
local generators = {}
for i = 1, #ratios do
local input_mos = mos.new(5,2)
local gen = mos.bright_gen_to_cents(input_mos, ratios[i])
local gcd = utils._gcd(ratios[i][1], ratios[i][2])
local edo = (ratios[i][1] * 5 + ratios[i][2] * 2)/gcd
--local new_string = string.format("%s:%s\t%s\t%sedo\t%.3f", ratios[i][1]/gcd, ratios[i][2]/gcd, depths[i], edo, gen)
local new_string = string.format("%s/%s\t%s", ratios[i][1]/gcd, ratios[i][2]/gcd, depths[i])
table.insert(generators, new_string)
end
return generators
end
return p