Module:JI ratios: Difference between revisions

Ganaram inukshuk (talk | contribs)
some bugfixes and testing
Ganaram inukshuk (talk | contribs)
Created new prime-limit search function; some cleanup with int-limit search
Line 32: Line 32:


--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
----------------------------- HELPER FUNCTIONS -------- ------------------------
------------------------------ HELPER FUNCTIONS --------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Does not return anything; entries in source are added to destination.
function p.merge_ratio_tables_without_duplicates(dest_table, source_table)
for i = 1, #source_table do
if not p.find_ratio_in_table(dest_table, source_table[i]) then
table.insert(dest_table, source_table[i])
end
end
end
-- Checks whether a ratio was already in a table
function p.find_ratio_in_table(table_, ratio)
local found = false
for i = 1, #table_ do
if rat.as_float(table_[i]) == rat.as_float(ratio) then
found = true
break
end
end
return found
end


-- Preprocess fine-search args
-- Preprocess fine-search args
Line 72: Line 93:
end
end


-- Remove ratios whose complements exceed the int limit
--------------------------------------------------------------------------------
-- Ratios should already of the form defined by module:rational
------------------------------- FILTER FUNCTIONS -------------------------------
-- This function modifies the table of ratios directly, as it has no return
--------------------------------------------------------------------------------
-- value.
 
function p.remove_non_complementing_ratios(ratios, equave, fine_search_args)
-- Remove ratios whose complements exceed the int limit and Tenney height.
-- If filtering based on Tenney height is not needed, then Tenney height is set
-- to infinity instead, which should be done by the calling function.
function p.filter_ratios_by_complements(ratios, equave, fine_search_args)
if fine_search_args["Complements Only"] then
if fine_search_args["Complements Only"] then
local filtered_ratios = {}
local filtered_ratios = {}
for i = 1, #ratios do
for i = 1, #ratios do
local complement = rat.mul(rat.inv(ratios[i]), equave)
local complement = rat.mul(rat.inv(ratios[i]), equave)
local a, b
if rat.int_limit(complement) <= fine_search_args["Int Limit"] and rat.tenney_height(complement) <= fine_search_args["Tenney Height"] then
a, b = rat.as_pair(complement)
table.insert(filtered_ratios, ratios[i])
if math.max(a,b) <= fine_search_args["Int Limit"] and rat.tenney_height(complement) <= fine_search_args["Tenney Height"] then
end
end
return filtered_ratios
else
return ratios
end
end
 
-- Remove ratios that exceed the Tenney height. This is skipped if the Tenney
-- height is infinity.
function p.filter_ratios_by_tenney_height(ratios, equave, fine_search_args)
if not fine_search_args["Tenney Height"] == 1/0 then
local filtered_ratios = {}
for i = 1, #ratios do
if rat.tenney_height(ratios[i]) <= fine_search_args["Tenney Height"] then
table.insert(filtered_ratios, ratios[i])
table.insert(filtered_ratios, ratios[i])
end
end
Line 99: Line 136:


-- Int-limit-based search; finds ratios between 1/1 and an equave, within an int
-- Int-limit-based search; finds ratios between 1/1 and an equave, within an int
-- limit. An optional tenney height can be passed in.
-- limit.
-- Int limit is hardcoded to a max size to restrict the size of output, to avoid
-- risk of out-of-memory operations or the like.
function p.search_within_equave(equave, fine_search_args)
function p.search_within_equave(equave, fine_search_args)
local equave = equave or rat.new(2,1) -- Defualt equave is 2/1.
local equave = equave or rat.new(2,1) -- Defualt equave is 2/1.
Line 107: Line 142:
local init_ratios = {{1,1}, {1,0}}
local init_ratios = {{1,1}, {1,0}}
local search_func = p.int_limit_mediant_search
local ratios = med.find_only_mediants_by_int_limit(init_ratios, fine_search_args["Int Limit"])
local search_args = {
["Equave"] = equave,
["Int Limit"]    = fine_search_args["Int Limit"],
["Tenney Height"] = fine_search_args["Tenney Height"],
["Complements Only"] = fine_search_args["Complements Only"]
}
local ratios = med.find_only_mediants_by_search_func(init_ratios, search_func, search_args)
-- Convert to ratios that Module:Rational can work with
-- Convert to ratios that Module:Rational can work with
Line 122: Line 150:
-- Remove ratios that exceed the equave.
-- Remove ratios that exceed the equave.
-- Note that mediant search results in sorted ratios, so remove them from
-- Note that mediant search returns sorted ratios, so remove them from the
-- the end until there's no more to remove.
-- end until there's no more to remove.
while rat.gt(ratios[#ratios], equave) do
while rat.gt(ratios[#ratios], equave) do
table.remove(ratios, #ratios)
table.remove(ratios, #ratios)
end
end
-- Filter out ratios whose complements exceed the int limit
-- Filter out ratios that exceed the int limit.
ratios = p.remove_non_complementing_ratios(ratios, equave, fine_search_args)
ratios = p.filter_ratios_by_tenney_height(ratios, equave, fine_search_args)
-- Filter out ratios if their equave complement would be filtered out.
ratios = p.filter_ratios_by_complements(ratios, equave, fine_search_args)
return ratios
return ratios
end
-- Int limit search function, with equave and tenney height cutoffs.
-- If nil is passed in for the tenney height, it will defualt to infinity.
-- To be passed into mediant-search function, as part of int-limit-search
-- function call.
function p.int_limit_mediant_search(mediant_data, search_args)
local mediant  = mediant_data["mediant"]
local ratio_1  = mediant_data["ratio_1"]
local equave        = search_args["Equave"]
local equave_as_float = rat.as_float(equave)
local rat_1_as_float = ratio_1[1] / ratio_1[2]
local mediant_th = math.log(mediant[1] * mediant[2]) / math.log(2)
-- When the ratio is added, is ratio 1 within the equave? If so, add the
-- new ratio.
local within_equave = rat_1_as_float < equave_as_float
-- Is the mediant within the int limit and tenney height?
local within_int_limit = math.max(mediant[1], mediant[2]) <= search_args["Int Limit"]
local within_tenney_height = mediant_th <= search_args["Tenney Height"]
return within_equave and within_int_limit and within_tenney_height
end
end


Line 161: Line 168:
---------------- WORK-IN-PROGERSS SUBGROUP-BASED SEARCH FUNCTION ---------------
---------------- WORK-IN-PROGERSS SUBGROUP-BASED SEARCH FUNCTION ---------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function p.search_by_prime_limit_new(prime_limit, equave, fine_search_args)
local prime_limit = prime_limit or 5
local equave = equave or rat.new(2,1)
local fine_search_args = p.preprocess_fine_search_args(fine_search_args)
-- Find all primes up to the prime limit.
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 on the primes found, as subgroup-search code can
-- be reused for prime-limit search.
return p.search_by_subgroup_new(primes, equave, fine_search_args)
end


-- WORK-IN-PROGRESS!!
-- WORK-IN-PROGRESS!!
function p.search_by_subgroup_new(subgroup, equave, fine_search_args)
function p.search_by_subgroup_new(subgroup, equave, fine_search_args)
local subgroup = subgroup or {rat.new(2), rat.new(5), rat.new(17,14), rat.new(28,19)}
local subgroup = subgroup or {rat.new(2), rat.new(3), rat.new(7)}
local equave = equave or rat.new(2,1)
local equave = equave or rat.new(2,1)
local fine_search_args = p.preprocess_fine_search_args(fine_search_args)
local fine_search_args = p.preprocess_fine_search_args(fine_search_args)
-- Fine search params for ease of access
-- Fine search params for ease of access
local int_limit = fine_search_args["Int Limit"]
local tenney_height = fine_search_args["Tenney Height"]
local tenney_height = fine_search_args["Tenney Height"]
local comps_only = fine_search_args["Complements Only"]
local comps_only = fine_search_args["Complements Only"]
local int_limit = fine_search_args["Int Limit"]
-- Search for ratios within int limit within subgroup by multiplication.
-- Search for ratios within int limit within subgroup by multiplication.
Line 195: Line 227:
p.merge_ratio_tables_without_duplicates(ratios, new_ratios)
p.merge_ratio_tables_without_duplicates(ratios, new_ratios)
end
end
-- Use the products found to find all ratios between 1 and the equave
-- Implementation 2; slower!!
--[[local subgroup_inv = {}
for i = 1, #subgroup do
table.insert(subgroup_inv, rat.inv(subgroup[i]))
end
local ratios = {}
for i = 1, #products do
local new_ratios = p.multiply_ratios_using_bfs(products[i], subgroup_inv, int_limit)
local new_ratios_filtered = {}
for j = 1, #new_ratios do
if rat.as_float(new_ratios[j]) <= rat.as_float(equave) and rat.as_float(new_ratios[j]) >= 1 then
table.insert(new_ratios_filtered, new_ratios[j])
end
end
p.merge_ratio_tables_without_duplicates(ratios, new_ratios_filtered)
end]]--
-- Sort
-- Sort
Line 234: Line 248:
end
end


-- BFS helper function; returns { ratio } X subgroup
-- Helper function for BFS search; returns { ratio } X subgroup
function p.multiply_ratio_by_subgroup_elements(ratio, subgroup, int_limit)
function p.multiply_ratio_by_subgroup_elements(ratio, subgroup, int_limit)
local ratios = {}
local ratios = {}
Line 244: Line 258:
end
end
return ratios
return ratios
end
-- Does not return anything; entries in source are added to destination.
function p.merge_ratio_tables_without_duplicates(dest_table, source_table)
for i = 1, #source_table do
if not p.find_ratio_in_table(dest_table, source_table[i]) then
table.insert(dest_table, source_table[i])
end
end
end
-- Checks whether a ratio was already in a table
function p.find_ratio_in_table(table_, ratio)
local found = false
for i = 1, #table_ do
if rat.as_float(table_[i]) == rat.as_float(ratio) then
found = true
break
end
end
return found
end
end


Line 281: Line 274:
function p.search_by_subgroup_within_equave(subgroup, equave, fine_search_args)
function p.search_by_subgroup_within_equave(subgroup, equave, fine_search_args)
local subgroup = subgroup or { 2, 3, 7 }
local subgroup = subgroup or { 2, 3, 7 }
local equave = equave or rat.new(2,1) -- Defualt equave is 2/1.
local equave = equave or rat.new(2,1) -- Defualt equave is 2/1
local fine_search_args = p.preprocess_fine_search_args(fine_search_args)
local fine_search_args = p.preprocess_fine_search_args(fine_search_args)
Line 364: Line 357:
-- Filter out ratios whose complements exceed the int limit
-- Filter out ratios whose complements exceed the int limit
ratios = p.remove_non_complementing_ratios(ratios, equave, fine_search_args)
ratios = p.filter_ratios_by_complements(ratios, equave, fine_search_args)
return ratios
return ratios
Line 559: Line 552:


local equave = rat.new(2,1)
local equave = rat.new(2,1)
local fine_search_args = p.parse_search_args("Subgroup: 2.5.9.21; Int Limit: 100; Complements Only: 1; Tenney Height: 100000000")
local fine_search_args = p.parse_search_args("Subgroup: 2.5.9.21; Complements Only: 1; Tenney Height: 100000000")
local subgroup = { rat.new(2), rat.new(3), rat.new(9,7), rat.new(11,7), rat.new(25), rat.new(31,29) }
local subgroup = {rat.new(2), rat.new(3), rat.new(5), rat.new(7)}




return p.search_by_subgroup_new(subgroup, equave, fine_search_args)
return p.search_by_subgroup_new(subgroup, equave, 50, fine_search_args)
end
end


return p
return p