跳转到内容

模組:Complex Number/CayleyDickson

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

local p = {}
local comp_lib = require("Module:Complex_Number")
local cmath = comp_lib.cmath.init()

function p._isNaN(x)
	return (not (x==x)) and  (x~=x)
end
--無法套娃的[[凯莱-迪克森结构]]
function p.get_cdmath(_data, is_bicomplex)
	local q = {}
	q.cdmath={
		_scopeflag=_data,
		_bicomplex=is_bicomplex,
		abs=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			local A_len, B_len = q.cdmath.mathlib.abs(A), q.cdmath.mathlib.abs(B)
			return math.sqrt( A_len * A_len + B_len * B_len )
		end,
		floor=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			return q.cdmath.checkMathform(q.cdmath.mathlib.floor(A), q.cdmath.mathlib.floor(B), z)
		end,
		ceil=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			return q.cdmath.checkMathform(q.cdmath.mathlib.ceil(A), q.cdmath.mathlib.ceil(B), z)
		end,
		div=function(left,z)
			return left*q.cdmath.inverse(z)
		end,
		round=function(op1,op2,op3)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(op1)
			local o2, _2 = q.cdmath.readCayleyDicksonNumberCDpart(op2)
			local o3, _3 = q.cdmath.readCayleyDicksonNumberCDpart(op3)
			return q.cdmath.checkMathform(q.cdmath.mathlib.round(A,o2,o3), q.cdmath.mathlib.round(B,o2,o3), op1,op2,op3)
		end,
		re=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			return q.cdmath.mathlib.re(A)
		end,
		im=function(z) 
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			return q.cdmath.mathlib.im(A)
		end,
		conjugate=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			if q.cdmath._bicomplex then return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(A, -B), z) end
			return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.conjugate(A), -B), z)
		end,
		inverse=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			local A_up, B_up = q.cdmath.mathlib.conjugate(A), -B
			if q.cdmath._bicomplex then A_up = A end
			local A_len, B_len = q.cdmath.mathlib.abs(A), q.cdmath.mathlib.abs(B)
			local div_down = ( A_len * A_len + B_len * B_len )
			return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(A_up / div_down, B_up / div_down), z)
		end,
		tovector=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			local _A, _B = q.cdmath.toSnumber(tostring(A)), q.cdmath.toSnumber(tostring(B))
			return {unpack(q.cdmath.mathlib.tovector(A or 0) or {}), unpack(q.cdmath.mathlib.tovector(B or 0) or {})}
		end,
		trunc=function(op1,op2)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(op1)
			local o2, _2 = q.cdmath.readCayleyDicksonNumberCDpart(op2)
			return q.cdmath.checkMathform(q.cdmath.mathlib.trunc(A,o2), q.cdmath.mathlib.trunc(B,o2), op1,op2)
		end,
		sqrt=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			local s_zero = q.cdmath.toSnumber("0")
			if A == s_zero then 
				return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.sqrt(A), q.cdmath.toSnumber("0")), z)
			end
			return q.cdmath.checkMathform(q.cdmath.pow(z, 0.5), z)
		end,
		root=function(_z,_n,_num)
			local z = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(_z))
			local n = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(_n or 2))
			local num = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(_num or 1))
			local s_i = q.cdmath.toSnumber("i")
			if num == q.cdmath.one or num == q.cdmath.zero or num == nil or s_i == nil then
				return q.cdmath.pow(z, q.cdmath.inverse(n))
			end
			
			local sgn_data = q.cdmath.sgn(q.cdmath.nonRealPart(z))
			if q.cdmath.abs(q.cdmath.nonRealPart(z))<1e-14 then sgn_data=q.cdmath.getCayleyDicksonNumber(s_i, q.cdmath.toSnumber("0")) end
			local result = q.cdmath.pow(q.cdmath.abs(z), q.cdmath.inverse(n)) * q.cdmath.exp(sgn_data * (q.cdmath.arg(z) + (num-1)*(2*math.pi) ) * q.cdmath.inverse(n))
			result:clean()
			return result
		end,
	
		sin=function(z)
			local u = q.cdmath.nonRealPart(z)
			return ( math.cosh(q.cdmath.abs(u)) * math.sin(q.cdmath.re(z)) ) + ( q.cdmath.sgn(u) * math.sinh(q.cdmath.abs(u)) * math.cos(q.cdmath.re(z)) )
		end,
		cos=function(z)
			local u = q.cdmath.nonRealPart(z)
			return ( math.cosh(q.cdmath.abs(u)) * math.cos(q.cdmath.re(z)) ) - ( q.cdmath.sgn(u) * math.sinh(q.cdmath.abs(u)) * math.sin(q.cdmath.re(z)) )
		end,
		tan=function(z)
			local theta = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.sin(theta) * q.cdmath.inverse( q.cdmath.cos(theta) )
		end,
		cot=function(z)
			local theta = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.cos(theta) * q.cdmath.inverse( q.cdmath.sin(theta) )
		end,
	
		asin=function(z)
			local v = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			local u = q.cdmath.nonRealPart(z)
			local sgnu = q.cdmath.sgn(u); 
			if q.cdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + q.cdmath.ele(1) end
			return -sgnu * q.cdmath.asinh( v * sgnu )
		end,
		acos=function(z)
			local v = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			local u = q.cdmath.nonRealPart(z)
			local sgnu = q.cdmath.sgn(u); 
			if q.cdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + q.cdmath.ele(1) end
			return -sgnu * q.cdmath.acosh( v )
		end,
		atan=function(z)
			local v = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			local u = q.cdmath.nonRealPart(z)
			local sgnu = q.cdmath.sgn(u); 
			if q.cdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + q.cdmath.ele(1) end
			return -sgnu * q.cdmath.atanh( v * sgnu )
		end,
		acot=function(z)
			local v = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			local u = q.cdmath.nonRealPart(z)
			local sgnu = q.cdmath.sgn(u); 
			if q.cdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + q.cdmath.ele(1) end
			return sgnu * q.cdmath.acoth( v * sgnu )
		end,
		
		sinh=function(z)
			local u = q.cdmath.nonRealPart(z)
			return ( math.cos(q.cdmath.abs(u)) * math.sinh(q.cdmath.re(z)) ) + ( q.cdmath.sgn(u) * math.sin(q.cdmath.abs(u)) * math.cosh(q.cdmath.re(z)) )
		end,
		cosh=function(z)
			local u = q.cdmath.nonRealPart(z)
			return ( math.cos(q.cdmath.abs(u)) * math.cosh(q.cdmath.re(z)) ) + ( q.cdmath.sgn(u) * math.sin(q.cdmath.abs(u)) * math.sinh(q.cdmath.re(z)) )
		end,
		tanh=function(z)
			local theta = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.sinh(theta) * q.cdmath.inverse( q.cdmath.cosh(theta) )
		end,
		coth=function(z)
			local theta = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.cosh(theta) * q.cdmath.inverse( q.cdmath.sinh(theta) )
		end,
	
		asinh=function(z)
			local _one = q.cdmath.getCayleyDicksonNumber("1", "0")
			local u = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.checkMathform(q.cdmath.elog( u + q.cdmath.sqrt( u * u + _one ) ), z)
		end,
		acosh=function(z)
			local _one = q.cdmath.getCayleyDicksonNumber("1", "0")
			local u = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.checkMathform(q.cdmath.elog( u + q.cdmath.sqrt( u + _one ) * q.cdmath.sqrt( u - _one ) ),z)
		end,
		atanh=function(z)
			local _one = q.cdmath.getCayleyDicksonNumber("1", "0")
			local u = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.checkMathform(( q.cdmath.elog( _one + u ) - q.cdmath.elog( _one - u ) ) / 2, z)
		end,
		acoth=function(z)
			local _one = q.cdmath.getCayleyDicksonNumber("1", "0")
			local u = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.checkMathform(( q.cdmath.elog( _one + q.cdmath.inverse(u) ) - q.cdmath.elog( _one - q.cdmath.inverse(u) ) ) / 2, z)
		end,
	
		dot = function (op1, op2) 
			local nonL1, valL1 = q.cdmath.readCayleyDicksonNumberCDpart(op1)
			local nonL2, valL2 = q.cdmath.readCayleyDicksonNumberCDpart(op2)
			return q.cdmath.mathlib.dot(nonL1, nonL2) + q.cdmath.mathlib.dot(valL1, valL2)
		end,
		scalarPart=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(q.cdmath.mathlib.re(A))), q.cdmath.toSnumber("0")), z)
		end,
		vectorPart=function(z)
			return q.cdmath.nonRealPart(z)
		end,
	
		nonRealPart=function(z) 
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.nonRealPart(A), B), z)
		end,
		sgn=function(z)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			local A_len, B_len = q.cdmath.mathlib.abs(A), q.cdmath.mathlib.abs(B)
			local length = math.sqrt( A_len * A_len + B_len * B_len )
			if length <= 0 then return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber("0"),q.cdmath.toSnumber("0")), z) end
			return q.cdmath.checkMathform(z / length, z)
		end,
		arg=function(z) --TODO: verify
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(z)
			local A_len, B_len = q.cdmath.mathlib.abs(A), q.cdmath.mathlib.abs(B)
			local length = math.sqrt( A_len * A_len + B_len * B_len )
			return math.acos( q.cdmath.mathlib.re(A) / length )
		end,
		cis=function(z)
			local u = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(z))
			return q.cdmath.cos(u) + q.cdmath.ele(1) * q.cdmath.sin(u)
		end,
		exp=function(z) --Cayley-Dickson construction
			local u = q.cdmath.nonRealPart(z)
			return q.cdmath.checkMathform(( (q.cdmath.sgn(u) * math.sin(q.cdmath.abs(u))) + math.cos(q.cdmath.abs(u))) * math.exp(q.cdmath.re(z)), z)
		end,
		elog=function(z) --Cayley-Dickson construction
			local u = q.cdmath.nonRealPart(z)
			return q.cdmath.checkMathform(q.cdmath.sgn(u)*q.cdmath.arg(z)+math.log(q.cdmath.abs(z)), z)
		end,
		log=function(z,basez)
			if basez~=nil then return q.cdmath.checkMathform(q.cdmath.elog(basez) * q.cdmath.inverse(q.cdmath.elog(z)), z) end
			return q.cdmath.elog(z)
		end,
		pow=function(op1,op2)
			local _zero = q.cdmath.getCayleyDicksonNumber("0", "0")
			local a = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(op1))
			local z = q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(op2))
			a:clean();z:clean();
			if a.B == _zero and z.B == _zero then 
				return q.cdmath.checkMathform(q.cdmath.getOctonionNumberQ(q.cdmath.mathlib.pow(a.A, z.A), q.cdmath.toSnumber("0")), op1, op2)
			end
			return q.cdmath.checkMathform(q.cdmath.exp(z * q.cdmath.elog(a)):clean(), op1, op2)
		end,
	
		ele=function(id)
			local _zero = q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber("0"), q.cdmath.toSnumber("0"))
			local eles = (q.cdmath.elements or {})
			local id_msg = tonumber(tostring(id)) or 0
			return q.cdmath.checkMathform(eles[id_msg+1]or _zero, id)
		end,
		readCayleyDicksonNumberCDpart = function(z)
			if type(z) == type(function()end) then return end
			if type(z) == type(true) then return q.cdmath.toSnumber(z and '1' or '0'), q.cdmath.toSnumber("0") end

			local dim = tonumber(({tostring((type(z)==type({}))and z.numberType or ''):gsub("%-onion","")})[1])
			if type(z) == type({}) then --if already be complex number, don't run string find.
				if z.numberType == "complex" or z.numberType == "dualnumber" then
					if q.cdmath.elementCount >= 2 then
						return q.cdmath.toSnumber(tostring(z)), q.cdmath.toSnumber("0")
					else
						return q.cdmath.toSnumber(tostring(q.cdmath.mathlib.re(z))), q.cdmath.toSnumber(tostring(q.cdmath.mathlib.im(z)))
					end
				elseif z.numberType == "quaternion" then
					if q.cdmath.elementCount >= 4 then
						return q.cdmath.toSnumber(tostring(z)), q.cdmath.toSnumber("0")
					elseif q.cdmath.elementCount >= 2 then
						return q.cdmath.toSnumber(tostring(z.real or 0)..'+'..tostring(z.imag or 0)..'i'), q.cdmath.toSnumber(tostring(z.jpart or 0)..'+'..tostring(z.kpart or 0)..'i')
					else
						error("Can not divide into 2 parts.")
					end
				elseif z.numberType == "dualcomplex" then
					if q.cdmath.elementCount >= 4 then
						return q.cdmath.toSnumber(tostring(z)), q.cdmath.toSnumber("0")
					elseif q.cdmath.elementCount >= 2 then
						return q.cdmath.toSnumber(tostring((z.non_epsilon or {}).real or 0)..'+'..tostring((z.non_epsilon or {}).epsilon or 0)..'ε'), q.cdmath.toSnumber(tostring((z.epsilon or {}).real or 0)..'+'..tostring((z.epsilon or {}).epsilon or 0)..'ε')
					else
						error("Can not divide into 2 parts.")
					end
				elseif z.numberType == "octonion" then
					if q.cdmath.elementCount >= 8 then
						return q.cdmath.toSnumber(tostring(z)), q.cdmath.toSnumber("0")
					elseif q.cdmath.elementCount >= 4 then
						return z.nonL, z.valL
					elseif q.cdmath.elementCount >= 2 then
						return q.cdmath.toSnumber(tostring(z.nonL.real or 0)..'+'..tostring(z.nonL.imag or 0)..'i'), q.cdmath.toSnumber(tostring(z.nonL.jpart or 0)..'+'..tostring(z.nonL.kpart or 0)..'i')
					else
						error("Can not divide into 2 parts.")
					end
				elseif dim~=nil then
					if q.cdmath.elementCount > dim then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
					elseif q.cdmath.elementCount == dim then
						return z.A, z.B
					elseif q.cdmath.elementCount < dim then
						return unpack(q.cdmath.mathlib.halfNumberParts(z))
					else
						error(q.cdmath.elementCount .. " " .. tostring(dim) .. " " .. tostring((type(z)==type({}))and z.numberType or '') .." Not support number system.")
					end
				else
					--return q.cdmath.toCayleyDicksonNumber(tostring(z))
					error(q.cdmath.elementCount .. " " .. tostring(dim) .. " " .. tostring((type(z)==type({}))and z.numberType or '') .." Not support number system.")
				end
			elseif type(z) == type(0) then
				return q.cdmath.toSnumber(tostring(z)), q.cdmath.toSnumber("0")
			elseif type(z) == type(true) then
				return q.cdmath.toSnumber(z and '1' or '0'), q.cdmath.toSnumber("0")
			end
		end,
		random=function(op1, op2)
			if type(op1)==type(nil) and type(op2)==type(nil) then return q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.random(), q.cdmath.toSnumber("0")) end
			local op1_a, op1_b = q.cdmath.readCayleyDicksonNumberCDpart(op1)
			if type(op2)==type(nil) then return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.random(op1_a), q.cdmath.mathlib.random(op1_b)), op1) end
			local op2_a, op2_b = q.cdmath.readCayleyDicksonNumberCDpart(op2)
			return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.random(op1_a, op2_a), q.cdmath.mathlib.random(op1_b, op2_b)), op1, op2)
		end,

		isReal=function(z) return q.cdmath.abs(q.cdmath.nonRealPart(z)) < 1e-14 end,
		
		CayleyDicksonNumberMeta = {
			__add = function (op1, op2) 
				local op1_a, op1_b = q.cdmath.readCayleyDicksonNumberCDpart(op1)
				local op2_a, op2_b = q.cdmath.readCayleyDicksonNumberCDpart(op2)
				return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(op1_a + op2_a, op1_b + op2_b), op1, op2)
			end,
			__sub = function (op1, op2) 
				local op1_a, op1_b = q.cdmath.readCayleyDicksonNumberCDpart(op1)
				local op2_a, op2_b = q.cdmath.readCayleyDicksonNumberCDpart(op2)
				return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(op1_a - op2_a, op1_b - op2_b), op1, op2)
			end,
			__mul = function (op1, op2) 
				local _a, _b = q.cdmath.readCayleyDicksonNumberCDpart(op1)
				local _c, _d = q.cdmath.readCayleyDicksonNumberCDpart(op2)
				local r_nonL = _a*_c - q.cdmath.mathlib.conjugate(_d)*_b
				local r_valL = _d*_a + _b*q.cdmath.mathlib.conjugate(_c)
				if q.cdmath._bicomplex then 
					r_nonL = _a * _c - _b * _d
					r_valL = _a * _d + _b * _c
				end
				return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(r_nonL, r_valL), op1, op2)
			end,
			__div = function (op1, op2) 
				local op_div = q.cdmath.inverse(op2)
				local _a, _b = q.cdmath.readCayleyDicksonNumberCDpart(op1)
				local _c, _d = q.cdmath.readCayleyDicksonNumberCDpart(op_div)
				local r_nonL = _a*_c - q.cdmath.mathlib.conjugate(_d)*_b
				local r_valL = _d*_a + _b*q.cdmath.mathlib.conjugate(_c)
				if q.cdmath._bicomplex then 
					r_nonL = _a * _c - _b * _d
					r_valL = _a * _d + _b * _c
				end
				return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(r_nonL, r_valL), op1, op2)
			end,
			__mod = function (op1, op2) 
				local x = q.cdmath.readComplexNumber(op1)
				local y = q.cdmath.readComplexNumber(op2)
				return q.cdmath.checkMathform(x - y * qmath.floor(x / y), op1, op2)
			end,
			__unm = function (this)
				return q.cdmath.checkMathform(q.cdmath.getCayleyDicksonNumber(-this.A, -this.B), this)
			end,
			__eq = function (op1, op2)
				return op1.A == op2.A and op1.B == op2.B
			end,
			__tostring = function (this)
				local A, B = q.cdmath.readCayleyDicksonNumberCDpart(this)
				local strA = tostring(A)
				local strB = tostring(B)
				if strA == "nan" or strA == "-nan" then return strA end
				if strB == "nan" or strB == "-nan" then return strB end
				if strA == "0" and strB == "0" then return "0" end
				local body = ''
				local eles = (q.cdmath.elements or {})
				for i=1,#eles do
					--q.cdmath.readCayleyDicksonNumberCDpart(eles[i])
					local val = tonumber(q.cdmath.dot(this,eles[i]))or 0
					if math.abs(val)>1e-14 then
						local val_str = ''
						local is_one = (math.abs(math.abs(val)-1)<1e-14)
						local has_num = false
						if val>0 then
							if body~=''then val_str = val_str ..'+'end
							val_str = val_str..(is_one and''or tostring(val))
							has_num = true
						elseif val<0 then
							val_str = val_str..(is_one and'-'or tostring(val))
							has_num = true
						end
						if has_num then
							if i==1 then
								body = body..val_str..(is_one and'1'or'')
							else
								if this.mathform then
									body = body..val_str..' e_{'..tostring(i-1)..'}'
								elseif this.htmlform then
									body = body..val_str..(is_one and''or' ')..' e<sub>'..tostring(i-1)..'</sub>'
								else
									body = body..val_str..(is_one and''or'*')..'ele('..tostring(i-1)..')'
								end
							end
						end
					end
				end
				if body=='' then body = 0 end
				--return mw.dumpObject(this)
				return body
			end,
		},
		checkMathform=function(result,...)
			local parms = {...}
			local flag = false
			for i=1,#parms do flag = flag or ((type(parms[i])==type({}))and parms[i].mathform or false)end
			if type(result)==type({})then result.mathform = result.mathform or flag end
			return result
		end,
		mathlib=cmath,
		toSnumber=cmath.constructor,
		mathform = function(this)this.mathform=true return this end,
		htmlform = function(this)this.htmlform=true return this end,
		toCayleyDicksonNumber = function(str)
			--load if already a number
			local dim = tonumber(({tostring((type(str)==type({}))and str.numberType or ''):gsub("%-onion","")})[1])
			if type(str) == type({}) then --if already be complex number, don't run string find.
				if str.numberType == "complex" or str.numberType == "dualnumber" then
					if q.cdmath.elementCount >= 2 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
					else
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(q.cdmath.mathlib.re(str))), q.cdmath.toSnumber(tostring(q.cdmath.mathlib.im(str))))
					end
				elseif str.numberType == "quaternion" then
					if q.cdmath.elementCount >= 4 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
					elseif q.cdmath.elementCount >= 2 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str.real or 0)..'+'..tostring(str.imag or 0)..'i'), q.cdmath.toSnumber(tostring(str.jpart or 0)..'+'..tostring(str.kpart or 0)..'i'))
					end
				elseif str.numberType == "dualcomplex" then
					if q.cdmath.elementCount >= 4 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
					elseif q.cdmath.elementCount >= 2 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring((str.non_epsilon or {}).real or 0)..'+'..tostring((str.non_epsilon or {}).epsilon or 0)..'ε'), q.cdmath.toSnumber(tostring((str.epsilon or {}).real or 0)..'+'..tostring((str.epsilon or {}).epsilon or 0)..'ε'))
					end
				elseif str.numberType == "octonion" then
					if q.cdmath.elementCount >= 8 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
					elseif q.cdmath.elementCount >= 4 then
						return q.cdmath.getCayleyDicksonNumber(str.nonL, str.valL)
					elseif q.cdmath.elementCount >= 2 then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str.nonL.real or 0)..'+'..tostring(str.nonL.imag or 0)..'i'), q.cdmath.toSnumber(tostring(str.nonL.jpart or 0)..'+'..tostring(str.nonL.kpart or 0)..'i'))
					end
				elseif dim~=nil then
					if q.cdmath.elementCount > dim then
						return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
					elseif q.cdmath.elementCount == dim then
						return q.cdmath.getCayleyDicksonNumber(str.A, str.B)
					end
				else
				end
			elseif type(str) == type(0) then
				return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(tostring(str)), q.cdmath.toSnumber("0"))
			elseif type(str) == type(true) then
				return q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber(str and '1' or '0'), q.cdmath.toSnumber("0"))
			end
			--try to parse into substring
			local tmp_num = q.cdmath.toSnumber(tostring(str))
			if tmp_num ~= nil then
				return q.cdmath.getCayleyDicksonNumber(tmp_num,  q.cdmath.toSnumber("0")) 
			end
			--parse full string
			local chk_str = tostring(str)
			local got_list = {}
			local ismath = false
			if mw.ustring.find(chk_str,"%(")then 
				got_list = mw.text.split(mw.ustring.gsub(chk_str,"([%+%-])",",%1"),",")
				for i=1,#got_list do
					got_list[i] = mw.ustring.gsub(got_list[i],"ele","*"):gsub("%*+","*"):gsub("[%(%)]","")
				end
			elseif mw.ustring.find(chk_str,"%{")then 
				got_list = mw.text.split(mw.ustring.gsub(chk_str,"([%+%-])",",%1"),",")
				for i=1,#got_list do
					got_list[i] = mw.ustring.gsub(got_list[i],"^e"," e"):gsub("e","*"):gsub(" +","*"):gsub("%*+","*"):gsub("[_%{%}]","")
				end
				ismath = true
			end
			if #got_list > 0 then
				local eles = (q.cdmath.elements or {})
				local result_number = q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber("0"), q.cdmath.toSnumber("0"))
				local _zero = q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber("0"), q.cdmath.toSnumber("0"))
				local _one = q.cdmath.getCayleyDicksonNumber(q.cdmath.toSnumber("1"), q.cdmath.toSnumber("0"))
				for i=1,#got_list do
					if mw.text.trim(got_list[i])~='' then
						local check_ele = mw.text.split(got_list[i],"%*+")
						local real_coeff = tonumber(check_ele[1])or (tonumber( (tostring(check_ele[1])~='')and(tostring(check_ele[1])..'1')or check_ele[1] ) or 1)
						local real_eleid = tonumber(check_ele[2])or 0
						local this_ele = eles[real_eleid+1]or _zero
						result_number = result_number + this_ele*real_coeff
					end
				end
				result_number.mathform = ismath
				return result_number
			end
			return q.cdmath.getCayleyDicksonNumber(q.cdmath.readCayleyDicksonNumberCDpart(str))
		end,
		getCayleyDicksonNumber = function(a,b)
			local CayleyDicksonNumber = {}
			setmetatable(CayleyDicksonNumber,q.cdmath.CayleyDicksonNumberMeta) 
			function CayleyDicksonNumber:update()
				xpcall(function()
					self.A:update()
					self.B:update()
					self.argument = 0
					self.length = math.sqrt( self.A.length * self.A.length + self.B.length * self.B.length )
				end,function()end)
			end
			function CayleyDicksonNumber:clean()
				xpcall(function()
					self.A:clean()
					self.B:clean()
				end,function()end)
				return self
			end
			CayleyDicksonNumber.A = q.cdmath.toSnumber(a)
			CayleyDicksonNumber.B = q.cdmath.toSnumber(b)
			if not CayleyDicksonNumber.A then CayleyDicksonNumber.A = q.cdmath.toSnumber("0") end
			if not CayleyDicksonNumber.B then CayleyDicksonNumber.B = q.cdmath.toSnumber("0") end
			CayleyDicksonNumber.numberType = q.cdmath.globalNumberType
			return CayleyDicksonNumber
		end,
		halfNumberParts = function(num)
			local A, B = q.cdmath.readCayleyDicksonNumberCDpart(num)
			return {A, B}
		end,
		init = function(math_lib)
			return q.cdmath._init(math_lib)
		end,
		_init = function(math_lib)
			if type(math_lib)==type({})then
				q.cdmath.mathlib = math_lib.init()
				q.cdmath.toSnumber = q.cdmath.mathlib.constructor
			end
			local _zero = q.cdmath.toSnumber("0")

			q.cdmath.elements = {}
			local unit_list = q.cdmath.mathlib.elements or{}
			q.cdmath.elementCount = (#unit_list)*2
			q.cdmath.globalNumberType = tostring(q.cdmath.elementCount).."-onion"
			for i=1,q.cdmath.elementCount do q.cdmath.elements[i] = {} end
			for i=1,#unit_list do
				q.cdmath.elements[i] = q.cdmath.getCayleyDicksonNumber(unit_list[i], "0")
			end
			for i=1,#unit_list do
				q.cdmath.elements[i+#unit_list] = q.cdmath.getCayleyDicksonNumber("0", unit_list[i])
			end
			q.cdmath.pi = q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.pi, _zero)
			q.cdmath["π"] = q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.pi, _zero)
			q.cdmath["°"] = q.cdmath.getCayleyDicksonNumber(q.cdmath.mathlib.pi/180, _zero)
			q.cdmath.e = q.cdmath.getCayleyDicksonNumber(math.exp(1), _zero)
			q.cdmath.nan = q.cdmath.getCayleyDicksonNumber(tonumber("nan"), tonumber("nan"))
			q.cdmath.zero = q.cdmath.getCayleyDicksonNumber("0", _zero)
			q.cdmath.one = q.cdmath.getCayleyDicksonNumber("1", _zero)
			q.cdmath[-1] = q.cdmath.getCayleyDicksonNumber("-1", _zero)
	
			q.cdmath[0],q.cdmath[1] = q.cdmath.zero,q.cdmath.one
			q.cdmath.numberType = comp_lib._numberType
			
			q.cdmath.constructor = q.cdmath.toCayleyDicksonNumber
			
			return q.cdmath
		end
	
	}
	return q
end
p.cdmath = p.get_cdmath(0, false).cdmath
p.bcdmath = p.get_cdmath(0, true).cdmath
function p.checkModuleClass(cls)
	local class = ((type(cls)==type({}))and( ((cls.args or {})[1]) or cls[1] or '')or( (type(cls)==type("string")) and cls or ''))or''
	if mw.ustring.sub(class,1,7):upper()=="MODULE:" then
		local data = mw.ustring.sub(class, 8, -1)
		local func = mw.ustring.find(data,"%.")
		local modu = mw.ustring.sub(data, 1, func -1)
		func = mw.ustring.sub(data, func + 1, -1)
		return mw.text.trim(modu),  mw.text.trim(func)
	end
	return ''
end
--不能套娃
p.cdmathOctonion={
	init = function()
		local omath=require("Module:Complex_Number/Octonion").omath.init()
		p.cdmathOctonion=mw.clone(p.get_cdmath(1).cdmath).init(omath)
		return p.cdmathOctonion._init(omath)
	end
}
p.cdmathSedenion={
	init = function()
		local sdmath=p.sdmath.init()
		p.cdmathSedenion=mw.clone(p.get_cdmath(1).cdmath).init(sdmath)
		return p.cdmathSedenion._init(sdmath)
	end
}
p.cdmathQuaternion={
	init = function()
		local qmath=comp_lib.qmath.init()
		p.cdmathQuaternion=mw.clone(p.get_cdmath(1).cdmath).init(qmath)
		return p.cdmathQuaternion._init(qmath)
	end
}
p.sdmath={
	abs=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		local A_len, B_len = p.sdmath.mathlib.abs(A), p.sdmath.mathlib.abs(B)
		return math.sqrt( A_len * A_len + B_len * B_len )
	end,
	floor=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.checkMathform(p.sdmath.mathlib.floor(A), p.sdmath.mathlib.floor(B), z)
	end,
	ceil=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.checkMathform(p.sdmath.mathlib.ceil(A), p.sdmath.mathlib.ceil(B), z)
	end,
	div=function(left,z)
		return left*p.sdmath.inverse(z)
	end,
	round=function(op1,op2,op3)
		local A, B = p.sdmath.readSedenionNumberCDpart(op1)
		local o2, _2 = p.sdmath.readSedenionNumberCDpart(op2)
		local o3, _3 = p.sdmath.readSedenionNumberCDpart(op3)
		return p.sdmath.checkMathform(p.sdmath.mathlib.round(A,o2,o3), p.sdmath.mathlib.round(B,o2,o3), op1,op2,op3)
	end,
	re=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.mathlib.re(A)
	end,
	im=function(z) 
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.mathlib.im(A)
	end,
	conjugate=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.mathlib.conjugate(A), -B), z)
	end,
	inverse=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		local A_up, B_up = p.sdmath.mathlib.conjugate(A), -B
		local A_len, B_len = p.sdmath.mathlib.abs(A), p.sdmath.mathlib.abs(B)
		local div_down = ( A_len * A_len + B_len * B_len )
		return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(A_up / div_down, B_up / div_down), z)
	end,
	tovector=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		local _A, _B = p.sdmath.toSubNumber(tostring(A)), p.sdmath.toSubNumber(tostring(B))
		return {unpack(p.sdmath.mathlib.tovector(A or 0) or {}), unpack(p.sdmath.mathlib.tovector(B or 0) or {})}
	end,
	trunc=function(op1,op2)
		local A, B = p.sdmath.readSedenionNumberCDpart(op1)
		local o2, _2 = p.sdmath.readSedenionNumberCDpart(op2)
		return p.sdmath.checkMathform(p.sdmath.mathlib.trunc(A,o2), p.sdmath.mathlib.trunc(B,o2), op1,op2)
	end,
	sqrt=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		local s_zero = p.sdmath.toSubNumber("0")
		if A == s_zero then 
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.mathlib.sqrt(A), p.sdmath.toSubNumber("0")), z)
		end
		return p.sdmath.checkMathform(p.sdmath.pow(z, 0.5), z)
	end,
	root=function(_z,_n,_num)
		local z = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(_z))
		local n = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(_n or p.sdmath.toSubNumber("2")))
		local num = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(_num or p.sdmath.toSubNumber("1")))
		local s_i = p.sdmath.toSubNumber("i")
		if num == p.sdmath.one or num == p.sdmath.zero or num == nil or s_i == nil then
			return p.sdmath.pow(z, p.sdmath.inverse(n))
		end
		
		local sgn_data = p.sdmath.sgn(p.sdmath.nonRealPart(z))
		if p.sdmath.abs(p.sdmath.nonRealPart(z))<1e-14 then sgn_data=p.sdmath.getSedenionNumber(s_i, p.sdmath.toSubNumber("0")) end

		local ex = p.sdmath.pow(p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(p.sdmath.abs(z)), p.sdmath.toSubNumber("0")), p.sdmath.inverse(n))
		local cr = sgn_data * (p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(p.sdmath.arg(z)), p.sdmath.toSubNumber("0"))+ 
			(num-p.sdmath.getSedenionNumber(p.sdmath.toSubNumber("1"), p.sdmath.toSubNumber("0")))*
			p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(2*math.pi), p.sdmath.toSubNumber("0")) ) * p.sdmath.inverse(n)
		
		local result = ex * p.sdmath.pow(cr)
		result:clean()
		return result
	end,

	sin=function(z)
		local u = p.sdmath.nonRealPart(z)
		return ( math.cosh(p.sdmath.abs(u)) * math.sin(p.sdmath.re(z)) ) + ( p.sdmath.sgn(u) * math.sinh(p.sdmath.abs(u)) * math.cos(p.sdmath.re(z)) )
	end,
	cos=function(z)
		local u = p.sdmath.nonRealPart(z)
		return ( math.cosh(p.sdmath.abs(u)) * math.cos(p.sdmath.re(z)) ) - ( p.sdmath.sgn(u) * math.sinh(p.sdmath.abs(u)) * math.sin(p.sdmath.re(z)) )
	end,
	tan=function(z)
		local theta = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.sin(theta) * p.sdmath.inverse( p.sdmath.cos(theta) )
	end,
	cot=function(z)
		local theta = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.cos(theta) * p.sdmath.inverse( p.sdmath.sin(theta) )
	end,

	asin=function(z)
		local v = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		local u = p.sdmath.nonRealPart(z)
		local sgnu = p.sdmath.sgn(u); 
		if p.sdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + p.sdmath.ele(1) end
		return -sgnu * p.sdmath.asinh( v * sgnu )
	end,
	acos=function(z)
		local v = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		local u = p.sdmath.nonRealPart(z)
		local sgnu = p.sdmath.sgn(u); 
		if p.sdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + p.sdmath.ele(1) end
		return -sgnu * p.sdmath.acosh( v )
	end,
	atan=function(z)
		local v = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		local u = p.sdmath.nonRealPart(z)
		local sgnu = p.sdmath.sgn(u); 
		if p.sdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + p.sdmath.ele(1) end
		return -sgnu * p.sdmath.atanh( v * sgnu )
	end,
	acot=function(z)
		local v = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		local u = p.sdmath.nonRealPart(z)
		local sgnu = p.sdmath.sgn(u); 
		if p.sdmath.abs(sgnu) < 1e-12 then sgnu = sgnu + p.sdmath.ele(1) end
		return sgnu * p.sdmath.acoth( v * sgnu )
	end,
	
	sinh=function(z)
		local u = p.sdmath.nonRealPart(z)
		return ( math.cos(p.sdmath.abs(u)) * math.sinh(p.sdmath.re(z)) ) + ( p.sdmath.sgn(u) * math.sin(p.sdmath.abs(u)) * math.cosh(p.sdmath.re(z)) )
	end,
	cosh=function(z)
		local u = p.sdmath.nonRealPart(z)
		return ( math.cos(p.sdmath.abs(u)) * math.cosh(p.sdmath.re(z)) ) + ( p.sdmath.sgn(u) * math.sin(p.sdmath.abs(u)) * math.sinh(p.sdmath.re(z)) )
	end,
	tanh=function(z)
		local theta = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.sinh(theta) * p.sdmath.inverse( p.sdmath.cosh(theta) )
	end,
	coth=function(z)
		local theta = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.cosh(theta) * p.sdmath.inverse( p.sdmath.sinh(theta) )
	end,

	asinh=function(z)
		local _one = p.sdmath.getSedenionNumber("1", "0")
		local u = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.checkMathform(p.sdmath.elog( u + p.sdmath.sqrt( u * u + _one ) ), z)
	end,
	acosh=function(z)
		local _one = p.sdmath.getSedenionNumber("1", "0")
		local u = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.checkMathform(p.sdmath.elog( u + p.sdmath.sqrt( u + _one ) * p.sdmath.sqrt( u - _one ) ),z)
	end,
	atanh=function(z)
		local _one = p.sdmath.getSedenionNumber("1", "0")
		local u = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.checkMathform(( p.sdmath.elog( _one + u ) - p.sdmath.elog( _one - u ) ) / 2, z)
	end,
	acoth=function(z)
		local _one = p.sdmath.getSedenionNumber("1", "0")
		local u = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.checkMathform(( p.sdmath.elog( _one + p.sdmath.inverse(u) ) - p.sdmath.elog( _one - p.sdmath.inverse(u) ) ) / 2, z)
	end,

	dot = function (op1, op2) 
		local nonL1, valL1 = p.sdmath.readSedenionNumberCDpart(op1)
		local nonL2, valL2 = p.sdmath.readSedenionNumberCDpart(op2)
		return p.sdmath.mathlib.dot(nonL1, nonL2) + p.sdmath.mathlib.dot(valL1, valL2)
	end,
	scalarPart=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(tostring(p.sdmath.mathlib.re(A))), p.sdmath.toSubNumber("0")), z)
	end,
	vectorPart=function(z)
		return p.sdmath.nonRealPart(z)
	end,

	nonRealPart=function(z) 
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.mathlib.nonRealPart(A), B), z)
	end,
	sgn=function(z)
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		local A_len, B_len = p.sdmath.mathlib.abs(A), p.sdmath.mathlib.abs(B)
		local length = math.sqrt( A_len * A_len + B_len * B_len )
		if length <= 0 then return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.toSubNumber("0"),p.sdmath.toSubNumber("0")), z) end
		return p.sdmath.checkMathform(z / length, z)
	end,
	arg=function(z) --TODO: verify
		local A, B = p.sdmath.readSedenionNumberCDpart(z)
		local A_len, B_len = p.sdmath.mathlib.abs(A), p.sdmath.mathlib.abs(B)
		local length = math.sqrt( A_len * A_len + B_len * B_len )
		return math.acos( p.sdmath.mathlib.re(A) / length )
	end,
	cis=function(z)
		local u = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(z))
		return p.sdmath.cos(u) + p.sdmath.ele(1) * p.sdmath.sin(u)
	end,
	exp=function(z) --Cayley-Dickson construction
		local u = p.sdmath.nonRealPart(z)
		return p.sdmath.checkMathform(( (p.sdmath.sgn(u) * math.sin(p.sdmath.abs(u))) + math.cos(p.sdmath.abs(u))) * math.exp(p.sdmath.re(z)), z)
	end,
	elog=function(z) --Cayley-Dickson construction
		local u = p.sdmath.nonRealPart(z)
		return p.sdmath.checkMathform(p.sdmath.sgn(u)*p.sdmath.arg(z)+math.log(p.sdmath.abs(z)), z)
	end,
	log=function(z,basez)
		if basez~=nil then return p.sdmath.checkMathform(p.sdmath.elog(basez) * p.sdmath.inverse(p.sdmath.elog(z)), z) end
		return p.sdmath.elog(z)
	end,
	pow=function(op1,op2)
		local _zero = p.sdmath.getSedenionNumber("0", "0")
		local a = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(op1))
		local z = p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(op2))
		a:clean();z:clean();
		if a.B == _zero and z.B == _zero then 
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.mathlib.pow(a.A, z.A), p.sdmath.toSubNumber("0")), op1, op2)
		end
		return p.sdmath.checkMathform(p.sdmath.exp(z * p.sdmath.elog(a)):clean(), op1, op2)
	end,

	ele=function(id)
		local _zero = p.sdmath.getSedenionNumber(p.sdmath.toSubNumber("0"), p.sdmath.toSubNumber("0"))
		local eles = (p.sdmath.elements or {})
		local id_msg = tonumber(tostring(id)) or 0
		return p.sdmath.checkMathform(eles[id_msg+1]or _zero, id)
	end,
	readSedenionNumberCDpart = function(z)
		if type(z) == type(function()end) then return end
		if type(z) == type(true) then return p.sdmath.toSubNumber(z and '1' or '0'), p.sdmath.toSubNumber("0") end

		local dim = tonumber(({tostring((type(z)==type({}))and z.numberType or ''):gsub("%-onion","")})[1])
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "complex" then
				return p.sdmath.toSubNumber(tostring(z)), p.sdmath.toSubNumber("0")
			elseif z.numberType == "quaternion" then
				return p.sdmath.toSubNumber(tostring(z)), p.sdmath.toSubNumber("0")
			elseif z.numberType == "octonion" then
				return p.sdmath.toSubNumber(tostring(z)), p.sdmath.toSubNumber("0")
			elseif z.numberType == "sedenion" then
				return z.A, z.B
			end
		elseif type(z) == type(0) then
			return p.sdmath.toSubNumber(tostring(z)), p.sdmath.toSubNumber("0")
		elseif type(z) == type(true) then
			return p.sdmath.toSubNumber(z and '1' or '0'), p.sdmath.toSubNumber("0")
		end
	end,
	random=function(op1, op2)
		if type(op1)==type(nil) and type(op2)==type(nil) then return p.sdmath.getSedenionNumber(p.sdmath.mathlib.random(), p.sdmath.toSubNumber("0")) end
		local op1_a, op1_b = p.sdmath.readSedenionNumberCDpart(op1)
		if type(op2)==type(nil) then return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.mathlib.random(op1_a), p.sdmath.mathlib.random(op1_b)), op1) end
		local op2_a, op2_b = p.sdmath.readSedenionNumberCDpart(op2)
		return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(p.sdmath.mathlib.random(op1_a, op2_a), p.sdmath.mathlib.random(op1_b, op2_b)), op1, op2)
	end,
	isReal=function(z) return p.sdmath.abs(p.sdmath.nonRealPart(z)) < 1e-14 end,
	
	SedenionNumberMeta = {
		__add = function (op1, op2) 
			local op1_a, op1_b = p.sdmath.readSedenionNumberCDpart(op1)
			local op2_a, op2_b = p.sdmath.readSedenionNumberCDpart(op2)
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(op1_a + op2_a, op1_b + op2_b), op1, op2)
		end,
		__sub = function (op1, op2) 
			local op1_a, op1_b = p.sdmath.readSedenionNumberCDpart(op1)
			local op2_a, op2_b = p.sdmath.readSedenionNumberCDpart(op2)
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(op1_a - op2_a, op1_b - op2_b), op1, op2)
		end,
		__mul = function (op1, op2) 
			local _a, _b = p.sdmath.readSedenionNumberCDpart(op1)
			local _c, _d = p.sdmath.readSedenionNumberCDpart(op2)
			local r_nonL = _a*_c - p.sdmath.mathlib.conjugate(_d)*_b
			local r_valL = _d*_a + _b*p.sdmath.mathlib.conjugate(_c)
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(r_nonL, r_valL), op1, op2)
		end,
		__div = function (op1, op2) 
			local op_div = p.sdmath.inverse(op2)
			local _a, _b = p.sdmath.readSedenionNumberCDpart(op1)
			local _c, _d = p.sdmath.readSedenionNumberCDpart(op_div)
			local r_nonL = _a*_c - p.sdmath.mathlib.conjugate(_d)*_b
			local r_valL = _d*_a + _b*p.sdmath.mathlib.conjugate(_c)
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(r_nonL, r_valL), op1, op2)
		end,
		__mod = function (op1, op2) 
			local x = p.sdmath.readComplexNumber(op1)
			local y = p.sdmath.readComplexNumber(op2)
			return p.sdmath.checkMathform(x - y * qmath.floor(x / y), op1, op2)
		end,
		__unm = function (this)
			return p.sdmath.checkMathform(p.sdmath.getSedenionNumber(-this.A, -this.B), this)
		end,
		__eq = function (op1, op2)
			return op1.A == op2.A and op1.B == op2.B
		end,
		__tostring = function (this)
			local A, B = p.sdmath.readSedenionNumberCDpart(this)
			local strA = tostring(A)
			local strB = tostring(B)
			if strA == "nan" or strA == "-nan" then return strA end
			if strB == "nan" or strB == "-nan" then return strB end
			if strA == "0" and strB == "0" then return "0" end
			local body = ''
			local eles = (p.sdmath.elements or {})
			for i=1,#eles do
				--p.sdmath.readSedenionNumberCDpart(eles[i])
				local val = tonumber(p.sdmath.dot(this,eles[i]))or 0
				if math.abs(val)>1e-14 then
					local val_str = ''
					local is_one = (math.abs(math.abs(val)-1)<1e-14)
					local has_num = false
					if val>0 then
						if body~=''then val_str = val_str ..'+'end
						val_str = val_str..(is_one and''or tostring(val))
						has_num = true
					elseif val<0 then
						val_str = val_str..(is_one and'-'or tostring(val))
						has_num = true
					end
					if has_num then
						if i==1 then
							body = body..val_str..(is_one and'1'or'')
						else
							if this.mathform then
								body = body..val_str..' e_{'..tostring(i-1)..'}'
							elseif this.htmlform then
								body = body..val_str..(is_one and''or' ')..' e<sub>'..tostring(i-1)..'</sub>'
							else
								body = body..val_str..(is_one and''or'*')..'ele('..tostring(i-1)..')'
							end
						end
					end
				end
			end
			if body=='' then body = 0 end
			--return mw.dumpObject(this)
			return body
		end,
	},
	checkMathform=function(result,...)
		local parms = {...}
		local flag = false
		for i=1,#parms do flag = flag or ((type(parms[i])==type({}))and parms[i].mathform or false)end
		if type(result)==type({})then result.mathform = result.mathform or flag end
		return result
	end,
	mathlib=cmath,
	toSubNumber=cmath.constructor,
	mathform = function(this)this.mathform=true return this end,
	htmlform = function(this)this.htmlform=true return this end,
	toSedenionNumber = function(str)
		--load if already a number
		local dim = tonumber(({tostring((type(str)==type({}))and str.numberType or ''):gsub("%-onion","")})[1])
		if type(str) == type({}) then --if already be complex number, don't run string find.
			if str.numberType == "complex" then
				return p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(tostring(str)), p.sdmath.toSubNumber("0"))
			elseif str.numberType == "quaternion" then
				return p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(tostring(str)), p.sdmath.toSubNumber("0"))
			elseif str.numberType == "octonion" then
				return p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(tostring(str)), p.sdmath.toSubNumber("0"))
			elseif str.numberType == "sedenion" then
				return p.sdmath.getSedenionNumber(str.A, str.B)
			end
		elseif type(str) == type(0) then
			return p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(tostring(str)), p.sdmath.toSubNumber("0"))
		elseif type(str) == type(true) then
			return p.sdmath.getSedenionNumber(p.sdmath.toSubNumber(str and '1' or '0'), p.sdmath.toSubNumber("0"))
		end
		--try to parse into substring
		local tmp_num = p.sdmath.toSubNumber(tostring(str))
		if tmp_num ~= nil then
			return p.sdmath.getSedenionNumber(tmp_num,  p.sdmath.toSubNumber("0")) 
		end
		--parse full string
		local chk_str = tostring(str)
		local got_list = {}
		local ismath = false
		if mw.ustring.find(chk_str,"%(")then 
			got_list = mw.text.split(mw.ustring.gsub(chk_str,"([%+%-])",",%1"),",")
			for i=1,#got_list do
				got_list[i] = mw.ustring.gsub(got_list[i],"ele","*"):gsub("%*+","*"):gsub("[%(%)]","")
			end
		elseif mw.ustring.find(chk_str,"%{")then 
			got_list = mw.text.split(mw.ustring.gsub(chk_str,"([%+%-])",",%1"),",")
			for i=1,#got_list do
				got_list[i] = mw.ustring.gsub(got_list[i],"^e"," e"):gsub("e","*"):gsub(" +","*"):gsub("%*+","*"):gsub("[_%{%}]","")
			end
			ismath = true
		end
		if #got_list > 0 then
			local eles = (p.sdmath.elements or {})
			local result_number = p.sdmath.getSedenionNumber(p.sdmath.toSubNumber("0"), p.sdmath.toSubNumber("0"))
			local _zero = p.sdmath.getSedenionNumber(p.sdmath.toSubNumber("0"), p.sdmath.toSubNumber("0"))
			local _one = p.sdmath.getSedenionNumber(p.sdmath.toSubNumber("1"), p.sdmath.toSubNumber("0"))
			for i=1,#got_list do
				if mw.text.trim(got_list[i])~='' then
					local check_ele = mw.text.split(got_list[i],"%*+")
					local real_coeff = tonumber(check_ele[1])or (tonumber( (tostring(check_ele[1])~='')and(tostring(check_ele[1])..'1')or check_ele[1] ) or 1)
					local real_eleid = tonumber(check_ele[2])or 0
					local this_ele = eles[real_eleid+1]or _zero
					result_number = result_number + this_ele*real_coeff
				end
			end
			result_number.mathform = ismath
			return result_number
		end
		return p.sdmath.getSedenionNumber(p.sdmath.readSedenionNumberCDpart(str))
	end,
	getSedenionNumber = function(a,b)
		local SedenionNumber = {}
		setmetatable(SedenionNumber,p.sdmath.SedenionNumberMeta) 
		function SedenionNumber:update()
			xpcall(function()
				self.A:update()
				self.B:update()
				self.argument = 0
				self.length = math.sqrt( self.A.length * self.A.length + self.B.length * self.B.length )
			end,function()end)
		end
		function SedenionNumber:clean()
			xpcall(function()
				self.A:clean()
				self.B:clean()
			end,function()end)
			return self
		end
		SedenionNumber.A = p.sdmath.toSubNumber(a)
		SedenionNumber.B = p.sdmath.toSubNumber(b)
		if not SedenionNumber.A then SedenionNumber.A = p.sdmath.toSubNumber("0") end
		if not SedenionNumber.B then SedenionNumber.B = p.sdmath.toSubNumber("0") end
		SedenionNumber.numberType = "sedenion"
		return SedenionNumber
	end,
	halfNumberParts = function(num)
		local A, B = p.sdmath.readSedenionNumberCDpart(num)
		return {A, B}
	end,
	init = function()
		local omath=require("Module:Complex_Number/Octonion").omath.init()
		p.sdmath.mathlib = omath
		p.sdmath.toSubNumber = omath.constructor
		
		local _zero = p.sdmath.toSubNumber("0")

		p.sdmath.elements = {}
		local unit_list = p.sdmath.mathlib.elements or{}
		p.sdmath.elementCount = (#unit_list)*2
		for i=1,p.sdmath.elementCount do p.sdmath.elements[i] = {} end
		for i=1,#unit_list do 
			p.sdmath.elements[i] = p.sdmath.getSedenionNumber(unit_list[i], "0")
		end
		for i=1,#unit_list do 
			p.sdmath.elements[i+#unit_list] = p.sdmath.getSedenionNumber("0", unit_list[i])
		end

		p.sdmath.pi = p.sdmath.getSedenionNumber(p.sdmath.mathlib.pi, _zero)
		p.sdmath["π"] = p.sdmath.getSedenionNumber(p.sdmath.mathlib.pi, _zero)
		p.sdmath["°"] = p.sdmath.getSedenionNumber(p.sdmath.mathlib.pi/180, _zero)
		p.sdmath.e = p.sdmath.getSedenionNumber(math.exp(1), _zero)
		p.sdmath.nan = p.sdmath.getSedenionNumber(tonumber("nan"), tonumber("nan"))
		p.sdmath.zero = p.sdmath.getSedenionNumber("0", _zero)
		p.sdmath.one = p.sdmath.getSedenionNumber("1", _zero)
		p.sdmath[-1] = p.sdmath.getSedenionNumber("-1", _zero)

		p.sdmath[0],p.sdmath[1] = p.sdmath.zero,p.sdmath.one
		p.sdmath.numberType = comp_lib._numberType
		
		p.sdmath.constructor = p.sdmath.toSedenionNumber
		return p.sdmath
	end
}

new_meta = getmetatable( p ) or {}
new_meta.__index = function (this, func_name) 
	if mw.ustring.find(func_name, "=") then
		local eqs, eqe = mw.ustring.find(func_name, "=")
		local check_func_name = mw.ustring.sub(func_name,1, (eqs or 0)-1)
		local check_r = mw.ustring.find(check_func_name, "=")
		if not check_r then
			local tocall_obj = p[check_func_name]
			if type(tocall_obj) == type({}) then
				local math_class = mw.ustring.sub(func_name,(eqe or 0)+1, -1)
				if type(tocall_obj._init) ~= nil then
					local mymath = cmath
				    local mytomath = cmath.constructor
				    if mw.ustring.sub(math_class,1,7):upper()=="MODULE:" then
						local module_name, math_lib_name = p.checkModuleClass(math_class)
						xpcall(function()
							local load_module = require("Module:"..module_name)
							if load_module ~= nil then
								local load_math_lib = load_module[math_lib_name]
								if load_module ~= nil then
									local func_type = type(function()end)
									local my_math_lib = (type(load_math_lib.init) == func_type) and load_math_lib.init() or load_math_lib
									if type(my_math_lib.constructor) == func_type then
										math_class = "mymath"
										mymath = my_math_lib
										mytomath = my_math_lib.constructor
									end
								end
							end
						end,function()end)
					end
					tocall_obj.init=function()
						return tocall_obj._init(mymath)
					end
				end
				return tocall_obj
			end
		end
	end
	return nil
end
setmetatable(p, new_meta) 
return p