Module:JI ratios: Difference between revisions

ArrowHead294 (talk | contribs)
mNo edit summary
Ganaram inukshuk (talk | contribs)
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
-- - Move filtering functions to separate module?
-- - 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