跳转到内容

模組:Complex Number/Octonion

本页使用了标题或全文手工转换
维基百科,自由的百科全书

这是本页的一个历史版本,由A2569875留言 | 贡献2022年4月13日 (三) 18:26编辑。这可能和当前版本存在着巨大的差异。

local p = {}
local qmath = require("Module:Complex_Number").qmath.init()
local toQnumber = qmath.constructor
function p._isNaN(x)
	return (not (x==x)) and  (x~=x)
end
p.omath={
	abs=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		if nonL.imag == 0 and nonL.jpart == 0 and nonL.kpart == 0 and valL.real == 0 and
			valL.imag == 0 and valL.jpart == 0 and valL.kpart == 0 then return math.abs(nonL.real) end
		if valL.real == 0 and valL.imag == 0 and valL.jpart == 0 and valL.kpart == 0 then return qmath.abs(nonL) end
		local nonL_len, valL_len = qmath.abs(nonL), qmath.abs(valL)
		return math.sqrt( nonL_len * nonL_len + valL_len * valL_len )
	end,
	conjugate=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		return p.omath.getOctonionNumberQ(qmath.conjugate(nonL), -valL) 
	end,
	floor=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		return p.omath.getOctonionNumberQ(qmath.floor(nonL), qmath.floor(valL))
	end,
	ceil=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		return p.omath.getOctonionNumberQ(qmath.ceil(nonL), qmath.ceil(valL))
	end,
	div=function(op1, op2)
		local op_div = p.omath.inverse(op2)
		local _a, _b = p.omath.readOctonionNumberQpart(op1)
		local _c, _d = p.omath.readOctonionNumberQpart(op_div)
		local r_nonL = _a*_c - qmath.conjugate(_d)*_b
		local r_valL = _d*_a + _b*qmath.conjugate(_c)
		return p.omath.getOctonionNumberQ(r_nonL, r_valL) 
	end,
	round=function(op1, op2, op3)
		local nonL, valL = p.omath.readOctonionNumberQpart(op1)
		local digs = p.omath.readOctonionNumberQpart(op2)
		local base = p.omath.readOctonionNumberQpart(op2)
		return p.omath.getOctonionNumberQ(qmath.round(nonL, digs, base), qmath.round(valL, digs, base))
	end,
	re=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		return tonumber(z) or nonL.real 
	end,
	im=function(z) 
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		return (tonumber(z) and 0) or nonL.imag 
	end,
	inverse=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		local nonL_up, valL_up = qmath.conjugate(nonL), -valL
		local nonL_len, valL_len = qmath.abs(nonL), qmath.abs(valL)
		local div_down = ( nonL_len * nonL_len + valL_len * valL_len )
		return p.omath.getOctonionNumberQ(nonL_up / div_down, valL_up / div_down)
	end,
	tovector=function(z)
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		return {nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart}
	end,
	trunc=function(op1, op2)
		local nonL, valL = p.omath.readOctonionNumberQpart(op1)
		local digs = p.omath.readOctonionNumberQpart(op2)
		return p.omath.getOctonionNumberQ(qmath.trunc(nonL, digs), qmath.trunc(valL, digs))
	end,
	arg=function(z) --TODO: verify
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		local nonL_len, valL_len = qmath.abs(nonL), qmath.abs(valL)
		local length = math.sqrt( nonL_len * nonL_len + valL_len * valL_len )
		return math.acos( nonL.real / length )
	end,

	exp=function(z) --Cayley-Dickson construction
		local nonL, valL = p.omath.readOctonionNumberQpart(z)
		local cis_r, cis_i, exp_r = 1, 0, qmath.exp(nonL)
		if valL ~= p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0) then cis_r, cis_i = qmath.cos(valL), qmath.sin(valL) end
		return p.omath.getOctonionNumberQ(exp_r * cis_r, exp_r * cis_i)
	end,
	pow=function(op1,op2)
		local check_op1, check_op2 = tonumber(tostring(op1)) or -1, tonumber(tostring(op2)) or -1
		if check_op1 == 1 then return p.omath.getOctonionNumber(1, 0, 0, 0, 0, 0, 0, 0) end -- 1^z === 1
		if check_op2 == 1 then return op1 end -- z^1 === z
		if check_op2 == 0 then -- z^0
			if check_op1 ~= 0 then return p.omath.getOctonionNumber(1, 0, 0, 0, 0, 0, 0, 0) -- z^0 === 1, z ≠ 0
			else return p.omath.getOctonionNumber(tonumber('nan'), 0, 0, 0, 0, 0, 0, 0) end --0^0 Indeterminate
		elseif check_op1 == 0 then return p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0) end -- 0^z === 0, z ≠ 0
		--a ^ z
		local _zero = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0)
		local a = p.omath.getOctonionNumberQ(p.omath.readOctonionNumberQpart(op1))
		local z = p.omath.getOctonionNumberQ(p.omath.readOctonionNumberQpart(op2))
		a:clean();z:clean();
		if a.valL == _zero and z.valL == _zero then 
			return qmath.pow(a.nonL, z.nonL)
		end
		--TODO : Log not define
		if a.jpart == 0 and z.jpart == 0 and a.kpart == 0 and z.kpart == 0 then 
			local complex = p.cmath.pow(p.cmath.getComplexNumber(a.real, a.imag), p.cmath.getComplexNumber(z.real, z.imag))
			return p.qmath.getQuaternionNumber(complex.real, complex.imag, 0, 0)
		end
		return p.qmath.exp(z * p.qmath.log(a)):clean()
	end,


	OctonionNumberMeta = {
		__add = function (op1, op2) 
			local op1_a, op1_b = p.omath.readOctonionNumberQpart(op1)
			local op2_a, op2_b = p.omath.readOctonionNumberQpart(op2)
			return p.omath.getOctonionNumberQ(op1_a + op2_a, op1_b + op2_b) 
		end,
		__sub = function (op1, op2) 
			local op1_a, op1_b = p.omath.readOctonionNumberQpart(op1)
			local op2_a, op2_b = p.omath.readOctonionNumberQpart(op2)
			return p.omath.getOctonionNumberQ(op1_a - op2_a, op1_b - op2_b) 
		end,
		__mul = function (op1, op2) 
			local _a, _b = p.omath.readOctonionNumberQpart(op1)
			local _c, _d = p.omath.readOctonionNumberQpart(op2)
			local r_nonL = _a*_c - qmath.conjugate(_d)*_b
			local r_valL = _d*_a + _b*qmath.conjugate(_c)
			return p.omath.getOctonionNumberQ(r_nonL, r_valL) 
		end,
		__div = function (op1, op2) 
			local op_div = p.omath.inverse(op2)
			local _a, _b = p.omath.readOctonionNumberQpart(op1)
			local _c, _d = p.omath.readOctonionNumberQpart(op_div)
			local r_nonL = _a*_c - qmath.conjugate(_d)*_b
			local r_valL = _d*_a + _b*qmath.conjugate(_c)
			return p.omath.getOctonionNumberQ(r_nonL, r_valL) 
		end,
		__mod = function (op1, op2) 
			local x = p.omath.readOctonionNumber(op1)
			local y = p.omath.readOctonionNumber(op2)
			return x - y * p.qmath.floor(x / y) 
		end,
		__tostring = function (this) 
			local nonL, valL = p.omath.readOctonionNumberQpart(this)
			local body = ''
			if nonL.real ~= 0 then body = tostring(nonL.real) end
			if nonL.imag ~= 0 then 
				if body ~= '' and nonL.imag > 0 then body = body .. '+' end
				if nonL.imag == -1 then  body = body .. '-' end
				if math.abs(nonL.imag) ~= 1 then body = body .. tostring(nonL.imag) end
				body = body .. 'i'
			end
			if nonL.jpart ~= 0 then 
				if body ~= '' and nonL.jpart > 0 then body = body .. '+' end
				if nonL.jpart == -1 then  body = body .. '-' end
				if math.abs(nonL.jpart) ~= 1 then body = body .. tostring(nonL.jpart) end
				body = body .. 'j'
			end
			if nonL.kpart ~= 0 then 
				if body ~= '' and nonL.kpart > 0 then body = body .. '+' end
				if nonL.kpart == -1 then  body = body .. '-' end
				if math.abs(nonL.kpart) ~= 1 then body = body .. tostring(nonL.kpart) end
				body = body .. 'k'
			end
			if valL.real ~= 0 then 
				if body ~= '' and valL.real > 0 then body = body .. '+' end
				if valL.real == -1 then  body = body .. '-' end
				if math.abs(valL.real) ~= 1 then body = body .. tostring(valL.real) .. '*' end
				body = body .. 'l'
			end
			if valL.imag ~= 0 then 
				if body ~= '' and valL.imag > 0 then body = body .. '+' end
				if valL.imag == -1 then  body = body .. '-' end
				if math.abs(valL.imag) ~= 1 then body = body .. tostring(valL.imag) .. '*' end
				body = body .. 'il'
			end
			if valL.jpart ~= 0 then 
				if body ~= '' and valL.jpart > 0 then body = body .. '+' end
				if valL.jpart == -1 then  body = body .. '-' end
				if math.abs(valL.jpart) ~= 1 then body = body .. tostring(valL.jpart) .. '*' end
				body = body .. 'jl'
			end
			if valL.kpart ~= 0 then 
				if body ~= '' and valL.kpart > 0 then body = body .. '+' end
				if valL.kpart == -1 then  body = body .. '-' end
				if math.abs(valL.kpart) ~= 1 then body = body .. tostring(valL.kpart) .. '*' end
				body = body .. 'kl'
			end
			if p._isNaN(nonL.real) or p._isNaN(nonL.imag) or p._isNaN(nonL.jpart) or p._isNaN(nonL.kpart) or
				p._isNaN(valL.real) or p._isNaN(valL.imag) or p._isNaN(valL.jpart) or p._isNaN(valL.kpart) then body = 'nan' end
			if body == '' then body = '0' end
			return body
		end,
		__unm = function (this)
			return p.omath.getOctonionNumberQ(-this.nonL, -this.valL) 
		end,
		__eq = function (op1, op2)
			return op1.nonL == op2.nonL and op1.valL == op2.valL
		end,
	},
	readOctonionNumber = function(z)
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "complex" then
				return p.omath.getOctonionNumber(z.real, z.imag, 0, 0, 0, 0, 0, 0)
			elseif z.numberType == "quaternion" then
				return p.omath.getOctonionNumberQ(z.real, z.imag, z.jpart, z.kpart, 0, 0, 0, 0)
			elseif z.numberType == "octonion" then
				return z
			end
		elseif type(z) == type(0) then
			return p.omath.getOctonionNumber(z, 0, 0, 0, 0, 0, 0, 0)
		end
	end,
	readOctonionNumberQpart = function(z)
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "complex" then
				return qmath.getQuaternionNumber(z.real, z.imag, 0, 0), qmath.getQuaternionNumber(0, 0, 0, 0)
			elseif z.numberType == "quaternion" then
				return qmath.getQuaternionNumber(z.real, z.imag, z.jpart, z.kpart), qmath.getQuaternionNumber(0, 0, 0, 0)
			elseif z.numberType == "octonion" then
				return z.nonL, z.valL
			end
		elseif type(z) == type(0) then
			return qmath.getQuaternionNumber(z, 0, 0, 0), qmath.getQuaternionNumber(0, 0, 0, 0)
		end
	end,
	getOctonionNumberQ = function(nonL, valL)
		return p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
	end,
	getOctonionNumber = function(real, imag, jpart, kpart, lpart, ilmag, jlpart, klpart)
		OctonionNumber = {}
		setmetatable(OctonionNumber,p.omath.OctonionNumberMeta) 
		function OctonionNumber:update()
			self.nonL:update()
			self.valL:update()
			self.argument = 0
			self.length = math.sqrt( self.nonL.length * self.nonL.length + self.valL.length * self.valL.length )
		end
		function OctonionNumber:clean()
			self.nonL:clean()
			self.valL:clean()
			return self
		end
		OctonionNumber.nonL = qmath.getQuaternionNumber(real, imag, jpart, kpart)
		OctonionNumber.valL = qmath.getQuaternionNumber(lpart, ilmag, jlpart, klpart)
		OctonionNumber.numberType = "octonion"
		return OctonionNumber
	end,
	toOctonionNumberPart = function(num_str)
		local body = ''
		local real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart = 0, 0, 0, 0, 0, 0, 0, 0
		local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
				mw.ustring.gsub(
				num_str or '',
			'(%d)%s*%*%s*([ijkl])','%1%2'),
			'%s+',''),'%++([%d%.])',',+%1'),'%++([ijkl])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijkl])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijkl])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijkl])',',/1%1'),',')
		local first = true
		local continue = false
		mw.logObject(split_str)
		for k,v in pairs(split_str) do
			continue = false
			local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijkl]+)','+1%1')
			if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end

			if val == nil or val == '' then if first == true then first = false continue = true else return end end
			if not continue then
				local num_text = mw.ustring.match(val,"[%+%-][%d%.]+[ijkl]*")
				mw.log(num_text)
				if num_text ~= val then return end
				local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
				if num_part == nil then return end
				local f_start, f_end = mw.ustring.find(num_text,"[ijkl]+")
				local part_str = ''
				if f_start then part_str = mw.ustring.sub(num_text,f_start, f_end) end
				mw.log('f_start',f_start, f_end)
				mw.log('part_str',part_str)
				if part_str == "i" then imag = imag + num_part -- +i
				elseif part_str == "j" then jpart = jpart + num_part -- +j
				elseif part_str == "k" then kpart = kpart + num_part -- +k
				elseif part_str == "l" then lpart = lpart + num_part -- +l
				elseif part_str == "ij" then kpart = kpart + num_part -- +ij == +k
				elseif part_str == "ik" then jpart = jpart - num_part -- +ij == -j
				elseif part_str == "il" then ilpart = ilpart + num_part -- +il
				elseif part_str == "ji" then kpart = kpart - num_part -- +ji == -k
				elseif part_str == "jk" then imag = imag + num_part -- +jk == +i
				elseif part_str == "jl" then ilpart = jlpart + num_part -- +jl

				else
					real = real + num_part
				end
			end
		end
		return real, imag, jpart, kpart
	end,

}


function p.test()

	--local my_num1 = {nonL=toQnumber("3i-k+2"),valL=toQnumber("5i+4+j")}
	--local my_num2 = {nonL=toQnumber("2i-k+1"),valL=toQnumber("4i+3+j")}
	--local my_num1 = {nonL=toQnumber("i"),valL=toQnumber("0"),numberType = "octonion"}
	--local my_num2 = {nonL=toQnumber("i"),valL=toQnumber("0"),numberType = "octonion"}

	local _e = p.omath.getOctonionNumberQ(toQnumber(math.exp(1)), toQnumber("0"))
	local _i = p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0"))
	local _pi = p.omath.getOctonionNumberQ(toQnumber(math.pi), toQnumber("0"))
	mw.logObject(_e)
	mw.logObject(_i)
	mw.logObject(_pi)
	mw.logObject(p.omath.exp(_i*_pi))

	local my_num1 = p.omath.getOctonionNumberQ(toQnumber("0"), toQnumber("i"))
	local my_num2 = p.omath.getOctonionNumberQ(toQnumber("j"), toQnumber("0"))
	local my_num3 = my_num1 * my_num2
	local my_num4 = my_num1 + my_num2
	local my_num5 = p.omath.getOctonionNumberQ(toQnumber("1+2j"), toQnumber("2+3i"))
	mw.logObject(my_num1)
	mw.logObject(my_num2)
	mw.logObject(my_num3)
	mw.logObject(my_num4)
	mw.logObject(my_num5)
	mw.logObject(my_num5 + my_num4)
	mw.logObject(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("2"), toQnumber("0")))
	mw.logObject(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")))
	mw.logObject(p.omath.re(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0"))))
	mw.logObject(p.omath.im(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("2"), toQnumber("0"))))
	--conjugate
	
end
return p