Module:Temperament data: Difference between revisions

From Xenharmonic Wiki
Jump to navigation Jump to search
CompactStar (talk | contribs)
No edit summary
CompactStar (talk | contribs)
No edit summary
Line 1: Line 1:
local rat = require('Module:Rational')
local rat = require('Module:Rational')
local p = {}
local p = {}
-- Utility / matrix functions
 
local function gcd(a,b)
local function gcd(a,b)
   if type(a) == "number" and type(b) == "number" and  
   if type(a) == "number" and type(b) == "number" and  
Line 66: Line 66:


local function matinv(a)
local function matinv(a)
dbl_identity = {}
local dbl_identity = {}
for i = 1, #a do
for i = 1, #a do
dbl_identity[i] = {}
dbl_identity[i] = {}
Line 78: Line 78:
end
end


xn = scalarmatmul(a, 0.000001)
local xn = scalarmatmul(a, 0.000001)
for i = 1, 30 do
for i = 1, 30 do
Line 96: Line 96:
return result
return result
end
end
local function antitranspose(a)
local result = {}
for i = 1, #a[1] do
result[i] = {}
for j = 1, #a do
result[i][j] = a[#a - j + 1][#a[1] - i + 1]
end
end
return result
end


local function pseudoinv(a)
local function pseudoinv(a)
Line 101: Line 113:
end
end


local function nullspace(mapping)
local identity = {}
for i = 1, #mapping[1] do
identity[i] = {}
for j = 1, #mapping[1] do
if i == j then
identity[i][j] = 1
else
identity[i][j] = 0
end
end
end
-- local w = {{0},{1},{0}}
-- for i = 1, #mapping[1] do
-- w[i] = {10}
-- end


-- Actual temperament-related functions start here
return matsub(identity, matmul(pseudoinv(mapping), mapping))
-- Generator list (e.g. 2/1, 3/2 for meantone) is needed so you can input irregular mappings like {{5,8,12},{7,11,16}} for meantone
end
-- and still have the outputted generators be ~2/1 and ~3/2
-- (this will be important later so people using the template can just input an ET list instead of having to figure out the mapping)
-- Generators are passed as monzos in the specified subgroup here


function p.get_te_generator(subgroup, mapping, gens)
local function mapping_from_basis(comma_basis)
return antitranspose(nullspace(antitranspose(comma_basis)))
end
 
local function get_te_tuning_mpa(subgroup, mapping, preimage)
local w = {}
local w = {}
for i = 1, #subgroup do
for i = 1, #subgroup do
Line 127: Line 157:
local vw = matmul(mapping, w)
local vw = matmul(mapping, w)
local g = matmul(jw, pseudoinv(vw))
local g = matmul(jw, pseudoinv(vw))
local result = {}
local mapping_cols = #mapping[1]
return g
local tempered_subgroup = {}
for i = 1, #subgroup do
tempered_subgroup[i] = 0
for j = 1, #mapping do
tempered_subgroup[i] = tempered_subgroup[i] + g[1][j] * mapping[j][i]
end
end
return tempered_subgroup
end
end






return p
return p

Revision as of 02:21, 8 February 2024

Module documentation[view] [edit] [history] [purge]
Note: Do not invoke this module directly; use the corresponding template instead: Template:Temperament data.
Todo: add documentation

local rat = require('Module:Rational')
local p = {}

local function gcd(a,b)
  if type(a) == "number" and type(b) == "number" and 
        a == math.floor(a) and b == math.floor(b) then
    if b == 0 then
      return a
    else
      return gcd(b, a % b) -- tail recursion
    end
  else
    error("Invalid argument to gcd (" .. tostring(a) .. "," .. 
          tostring(b) .. ")", 2)
  end
end


local function matadd(a, b)
	local result = {}
	for i = 1, #a  do
		result[i] = {}
		for j = 1, #(b[1]) do
			result[i][j] = a[i][j] + b[i][j]
		end
	end
	return result
end

local function matsub(a, b)
	local result = {}
	for i = 1, #a  do
		result[i] = {}
		for j = 1, #(b[1]) do
			result[i][j] = a[i][j] - b[i][j]
		end
	end
	return result
end

local function matmul(a, b)
	local result = {}
	for i = 1, #a  do
		result[i] = {}
		for j = 1, #(b[1]) do
			result[i][j] = 0
			for k = 1, #(a[1]) do
				result[i][j] = result[i][j] + (a[i][k] * b[k][j])
			end
		end
	end
	return result
end


local function scalarmatmul(a, b)
	local result = {}
	for i = 1, #a  do
		result[i] = {}
		for j = 1, #(a[1]) do
			result[i][j] = a[i][j] * b
		end
	end
	return result
end

local function matinv(a)
	local dbl_identity = {}
	for i = 1, #a do
		dbl_identity[i] = {}
		for j = 1, #a do
			if i == j then
				dbl_identity[i][j] = 2
			else
				dbl_identity[i][j] = 0
			end
		end
	end

	local xn = scalarmatmul(a, 0.000001)
	
	for i = 1, 30 do
		xn = matmul(xn, matsub(dbl_identity, matmul(a, xn)))
	end
	return xn
end

local function transpose(a)
	local result = {}
	for i = 1, #a[1] do
		result[i] = {}
		for j = 1, #a do
			result[i][j] = a[j][i]
		end
	end
	return result
end

local function antitranspose(a)
	local result = {}
	for i = 1, #a[1] do
		result[i] = {}
		for j = 1, #a do
			result[i][j] = a[#a - j + 1][#a[1] - i + 1]
		end
	end
	return result
end


local function pseudoinv(a)
	return matmul(transpose(a), matinv(matmul(a, transpose(a))))
end

local function nullspace(mapping)
	local identity = {}
	for i = 1, #mapping[1] do
		identity[i] = {}
		for j = 1, #mapping[1] do
			if i == j then
				identity[i][j] = 1
			else
				identity[i][j] = 0
			end
		end
	end

	-- local w = {{0},{1},{0}}
	-- for i = 1, #mapping[1] do
	-- 	w[i] = {10}
	-- end

	return matsub(identity, matmul(pseudoinv(mapping), mapping))
end

local function mapping_from_basis(comma_basis)
	return antitranspose(nullspace(antitranspose(comma_basis)))
end

local function get_te_tuning_mpa(subgroup, mapping, preimage)
	local w = {}
	for i = 1, #subgroup do
		w[i] = {}
		for j = 1, #subgroup do
			if i == j then
				w[i][j] = math.log(2)/math.log(subgroup[i])
			else
				w[i][j] = 0
			end
		end
	end
	
	local jw = {{}}
	for i = 1, #subgroup do
		jw[1][i] = 1
	end
	local vw = matmul(mapping, w)
	local g = matmul(jw, pseudoinv(vw))
	local result = {}
	
	return g
end



return p