|
|
| Line 6: |
Line 6: |
| local getArgs = require("Module:Arguments").getArgs | | local getArgs = require("Module:Arguments").getArgs |
| p = {} | | p = {} |
|
| |
| -- 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 80: |
Line 76: |
| -- numerator or denominator don't exceed the int limit. | | -- numerator or denominator don't exceed the int limit. |
| function p.search_by_int_limit(equave, int_limit) | | function p.search_by_int_limit(equave, int_limit) |
| --local equave = equave or rat.new(2,1) -- Defualt equave is 2/1. | | return p.search_by_int_limit_within_cents(0, rat.cents(equave), int_limit) |
| --local int_limit = int_limit or 50 -- Default is 50
| |
|
| |
| -- Find all ratios from 1/1 to the equave by finding mediants between 1/1
| |
| -- and 1/0. Mediants module has a function for this built-in, but includes
| |
| -- ratios that exceed the equave (for example, if the equave is 2/1, then
| |
| -- the mediants function will include 3/1 and 4/1), which must be removed
| |
| -- afterwards.
| |
| local init_ratios = {{1,1}, {1,0}}
| |
| local ratios = med.find_only_mediants_by_int_limit(init_ratios, int_limit)
| |
|
| |
| -- 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 exceed the equave.
| |
| -- Because the ratios are already sorted by cent value, remove ratios from
| |
| -- the end of the table until there are no more ratios to remove.
| |
| while rat.gt(ratios[#ratios], equave) do
| |
| table.remove(ratios, #ratios)
| |
| end
| |
|
| |
| return ratios
| |
| end | | end |
|
| |
|
| Line 143: |
Line 116: |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
|
| |
|
| -- Prime limit search finds ratios with prime factors that don't exceed some
| | function p.prime_limit_to_subgroup(prime_limit) |
| -- prime limit.
| | local subgroup = {} |
| -- Upper bounds for searching is the equave and int limit.
| |
| function p.search_by_prime_limit(equave, 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 | | for i = 2, prime_limit do |
| local is_prime = true | | local is_prime = true |
| Line 163: |
Line 127: |
| end | | end |
| if is_prime then | | if is_prime then |
| table.insert(primes, rat.new(i)) | | table.insert(subgroup, rat.new(i)) |
| end | | end |
| end | | end |
| | | return subgroup |
| -- Perform subgroup search.
| | end |
| return p.search_by_subgroup(equave, int_limit, primes) | | |
| | -- Prime limit search finds ratios with prime factors that don't exceed some |
| | -- prime limit. |
| | -- Upper bounds for searching is the equave and int limit. |
| | function p.search_by_prime_limit(equave, int_limit, prime_limit) |
| | local subgroup = p.prime_limit_to_subgroup(prime_limit) |
| | return p.search_by_subgroup_within_cents(0, rat.cents(equave), int_limit, subgroup) |
| end | | end |
|
| |
|
| Line 174: |
Line 144: |
| -- prime limit. Searches within a cent range. | | -- prime limit. Searches within a cent range. |
| function p.search_by_prime_limit_within_cents(min_cents, max_cents, int_limit, prime_limit) | | 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 subgroup = p.prime_limit_to_subgroup(prime_limit) |
| --local int_limit = int_limit or 50 -- Default is 50 | | local ratios = p.search_by_subgroup_within_cents(min_cents, max_cents, int_limit, subgroup) |
| --local prime_limit = prime_limit or 5 -- Default is 5-prime-limit
| | while rat.cents(ratios[1]) <= min_cents do |
| | | table.remove(ratios, 1) |
| -- 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 | | end |
|
| | return ratios |
| -- Perform subgroup search.
| |
| return p.search_by_subgroup_within_cents(min_cents, max_cents, int_limit, primes) | |
| end | | end |
|
| |
|
| Line 202: |
Line 156: |
| -------------------------------------------------------------------------------- | | -------------------------------------------------------------------------------- |
|
| |
|
| -- Subgroup search find ratios that are products of at least two (not | | -- Subgroup search find ratios that are products of at least two non-unique |
| -- necessarily unique) elements from the subgroup. EG, for 2.3.7, 2/1, 3/2, 7/4, | | -- elements from the subgroup. |
| -- and 7/6 are within the subgroup, but not 5/4 because there's no 5.
| |
| -- Upper bounds for searching is the equave and int limit.
| |
| function p.search_by_subgroup(equave, int_limit, subgroup) | | function p.search_by_subgroup(equave, int_limit, subgroup) |
| --local equave = equave or rat.new(2,1) -- Defualt equave is 2/1. | | local ratios = p.search_by_subgroup_within_cents(0, rat.cents(equave), int_limit, subgroup) |
| --local int_limit = int_limit or 50 -- Default is 50
| | while rat.cents(ratios[1]) <= min_cents do |
| --local subgroup = subgroup or {rat.new(2), rat.new(3), rat.new(7)} -- Default is 2.3.7 subgroup
| | table.remove(ratios, 1) |
| | |
| -- 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 | | 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.as_float(new_ratio) > rat.as_float(equave) 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)
| |
|
| |
| return ratios | | return ratios |
| end | | end |
| Line 505: |
Line 405: |
| 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)) | | --return p.ratios_as_string(p.search_by_prime_limit_within_cents(372, 440, 17, 30)) |
| | return p.ratios_as_string(p.search_by_int_limit_within_cents(300,500, 20)) |
| end | | end |
|
| |
|