Module:JI ratios: Difference between revisions
ArrowHead294 (talk | contribs) mNo edit summary |
add search-within-cent-range functions; add todo to convert search-within-equave functions to use the search-within-cent-range functions, since code is near-identical |
||
| Line 8: | Line 8: | ||
-- TODO | -- TODO | ||
-- - | -- - Convert search-within-equave functions to use search-within-cent-range | ||
-- functions, since code is nearly identical. | |||
-- Template for handling multiple entry of JI ratios into a template, and for | -- Template for handling multiple entry of JI ratios into a template, and for | ||
| Line 99: | Line 100: | ||
-- the end of the table until there are no more ratios to remove. | -- the end of the table until there are no more ratios to remove. | ||
while rat.gt(ratios[#ratios], equave) do | while rat.gt(ratios[#ratios], equave) do | ||
table.remove(ratios, #ratios) | |||
end | |||
return ratios | |||
end | |||
-- Cent range search finds ratios within a cent range. Meant for searching for | |||
-- ratios within a single interval range. If searching for ratios within many | |||
-- interval ranges, then try a broad search first. | |||
function p.search_by_int_limit_within_cents(min_cents, max_cents, int_limit) | |||
local init_ratios = {{1,1}, {1,0}} | |||
local ratios = med.find_mediants_by_int_limit(init_ratios, int_limit) | |||
-- Remove last ratio to prevent divide-by-zero | |||
table.remove(ratios, #ratios) | |||
-- Convert to ratios that Module:Rational can work with | |||
for i = 1, #ratios do | |||
ratios[i] = rat.new(ratios[i][1], ratios[i][2]) | |||
end | |||
-- Remove ratios that fall outside the cent range. | |||
while rat.cents(ratios[1]) <= min_cents do | |||
table.remove(ratios, 1) | |||
end | |||
while rat.cents(ratios[#ratios]) >= max_cents do | |||
table.remove(ratios, #ratios) | table.remove(ratios, #ratios) | ||
end | end | ||
| Line 141: | Line 169: | ||
-- Perform subgroup search. | -- Perform subgroup search. | ||
return p.search_by_subgroup(equave, int_limit, primes) | return p.search_by_subgroup(equave, int_limit, primes) | ||
end | |||
-- Prime limit search finds ratios with prime factors that don't exceed some | |||
-- prime limit. Searches within a cent range. | |||
function p.search_by_prime_limit_within_cents(min_cents, max_cents, int_limit, prime_limit) | |||
--local equave = equave or rat.new(2,1) -- Defualt equave is 2/1. | |||
--local int_limit = int_limit or 50 -- Default is 50 | |||
--local prime_limit = prime_limit or 5 -- Default is 5-prime-limit | |||
-- Convert prime limit into an equivalent subgroup (EG, 7-limit becomes | |||
-- 2.3.5.7) so that it can be passed into the subgroup search function. | |||
local primes = {} | |||
for i = 2, prime_limit do | |||
local is_prime = true | |||
for j = 2, math.floor(math.sqrt(i)) do | |||
if i % j == 0 then | |||
is_prime = false | |||
break | |||
end | |||
end | |||
if is_prime then | |||
table.insert(primes, rat.new(i)) | |||
end | |||
end | |||
-- Perform subgroup search. | |||
return p.search_by_subgroup_within_cents(min_cents, max_cents, int_limit, primes) | |||
end | end | ||
| Line 207: | Line 262: | ||
-- Sort | -- Sort | ||
table.sort(ratios, rat.lt) | table.sort(ratios, rat.lt) | ||
return ratios | |||
end | |||
function p.search_by_subgroup_within_cents(min_cents, max_cents, int_limit, subgroup) | |||
--local equave = equave or rat.new(2,1) -- Defualt equave is 2/1. | |||
--local int_limit = int_limit or 50 -- Default is 50 | |||
--local subgroup = subgroup or {rat.new(2), rat.new(3), rat.new(7)} -- Default is 2.3.7 subgroup | |||
-- Find all possible ways to multiply subgroup elements with one another | |||
-- using breadth-first-search. Products found this way should not exceed the | |||
-- int limit, and if a subgroup element is rational, neither its numerator | |||
-- nor denominator should exceed the int limit. | |||
local products = { rat.new(1) } | |||
local i = 1 | |||
while i <= #products do | |||
-- Multiply each subgroup element by the current ratio. The table of | |||
-- product ratios created this way is merged with the running table of | |||
-- ratios. This is the Cartesian product of the single ratio as a set, | |||
-- with the subgroup elements as a set, or {p/q} X subgroup. | |||
local new_products = {} | |||
for j = 1, #subgroup do | |||
local new_ratio = rat.mul(products[i], subgroup[j]) | |||
if rat.is_within_int_limit(new_ratio, int_limit) and not p.find_ratio_in_table(new_products, new_ratio) then | |||
table.insert(new_products, new_ratio) | |||
end | |||
end | |||
-- Merge new products with the table of products, omitting duplicates. | |||
p.merge_tables(products, new_products) | |||
i = i + 1 | |||
end | |||
-- Sort for next step | |||
table.sort(products, rat.lt) | |||
-- Use the products found to find all ratios between 1 and the equave. | |||
-- For each ratio in the table of products, create a set of new ratios by | |||
-- having that ratio be the numerator and all successive ratios be possible | |||
-- denominators. Store these new ratios in a table, and repeat with all | |||
-- successive products, omitting duplicats. From earlier testing, this is | |||
-- faster than performing BFS on each ratio, and yields the same results. | |||
local ratios = {} | |||
for i = 1, #products do | |||
local new_ratios = {} | |||
for j = i, #products do | |||
local new_ratio = rat.div(products[j], products[i]) | |||
if rat.cents(new_ratio) > max_cents then break end | |||
if not p.find_ratio_in_table(new_ratios, new_ratio) and rat.is_within_int_limit(new_ratio, int_limit) then | |||
table.insert(new_ratios, new_ratio) | |||
end | |||
end | |||
-- Merge new ratios with the table of ratios, omitting duplicates. | |||
p.merge_tables(ratios, new_ratios) | |||
end | |||
-- Sort | |||
table.sort(ratios, rat.lt) | |||
-- Remove ratios less than minimum | |||
while rat.cents(ratios[1]) <= min_cents do | |||
table.remove(ratios, 1) | |||
end | |||
return ratios | return ratios | ||
| Line 384: | Line 504: | ||
function p.tester() | function p.tester() | ||
return p.ratios_as_string(p._ji_ratios(p.parse_args("Int Limit: 16; Equave: 3/1; Complements Only: 0"))) | --return p.ratios_as_string(p._ji_ratios(p.parse_args("Int Limit: 16; Equave: 3/1; Complements Only: 0"))) | ||
return p.ratios_as_string(p.search_by_prime_limit_within_cents(372, 440, 17, 30)) | |||
end | end | ||