模組:Complex Number

--'
local p = { PrimeTable = {} }
local numlib = require("Module:Number")
local numdata = require("Module:Number/data")
local calclib = require("Module:Complex Number/Calculate")
local sollib = require("Module:Complex_Number/Solver")

p._numberType = sollib._numberType
p._isNaN = sollib._isNaN

--debug
--local cmath,tonum=p.cmath.init(),p.cmath.init().toComplexNumber; mw.logObject(cmath.abs(cmath.nonRealPart(tonum("2+3i"))))
local eReal, eImag = 'reω', 'ω'
p.cmath = {
	abs=function(z)
		local real, imag = p.cmath.readPart(z)
		if math.abs(imag) < 1e-12 then return math.abs(real) end
		return math.sqrt(real * real + imag * imag)
	end,
	floor=function(z)
		local real, imag = p.cmath.readPart(z)
		return p.cmath.getComplexNumber(math.floor(real), math.floor(imag)) 
	end,
	ceil=function(z)
		local real, imag = p.cmath.readPart(z)
		return p.cmath.getComplexNumber(math.ceil(real), math.ceil(imag)) 
	end,
	round=function(op1,op2,op3)
		local number = p.cmath.getComplexNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or op1.imag or 0) 
		local digs = p.cmath.getComplexNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or (op2 or {}).imag or 0) 
		local base = p.cmath.getComplexNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or (op3 or {}).imag or 0) 
		local round_rad = p.cmath.pow(base,digs)
		local check_number = number * round_rad
		check_number.real = check_number.real + 0.5; check_number.imag = check_number.imag + 0.5; 
		return p.cmath.floor( check_number ) / round_rad
	end,
	div=function(op1,op2)
		local a, c = tonumber(op1) or op1.real, tonumber(op2) or op2.real
		local b, d = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
		local op1_d, op2_d = a*a + b*b, c*c + d*d
		if op2_d <= 0 then return op1_d / op2_d end
		return p.cmath.getComplexNumber((a * c + b * d) / op2_d, (b * c - a * d) / op2_d) 
	end,
	re=function(z)return tonumber(z) or z.real end,
	im=function(z) return (tonumber(z) and 0) or z.imag end,
	nonRealPart=function(z) return p.cmath.getComplexNumber(0, (tonumber(z) and 0) or z.imag) end,
	conjugate=function(z)
		local real, imag = p.cmath.readPart(z)
		return p.cmath.getComplexNumber(real, -imag)
	end,
	inverse=function(z)
		local real, imag = p.cmath.readPart(z)
		return p.cmath.getComplexNumber(real, -imag) / ( real*real + imag*imag )
	end,
	tovector=function(z)
		return {p.cmath.readPart(z)}
	end,
	trunc=function(z,digs)
		local real, imag = p.cmath.readPart(z)
		local n = tonumber(digs) or digs.real or 0
		return p.cmath.getComplexNumber(sollib._trunc(real,n), sollib._trunc(imag,n))
	end,
	digits=function(z)
		local real, imag = p.cmath.readPart(z)
		real, imag = math.floor(math.abs(real)), math.floor(math.abs(imag))
		return math.max(tostring(real):len(),tostring(imag):len())
	end,
	--判斷是否為第一象限高斯質數
	is_prime_quadrant1=function(z)
		local real, imag = p.cmath.readPart(z)
		if imag == 0 and real == 0 then return false end
		if not numdata._is_integer(imag) or not numdata._is_integer(real) then return false end
		if imag == 0 then 
			if real <= 1 then return false end
			if numdata._is_integer((real - 3.0) / 4.0) then
				if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end
				p.PrimeTable.primeIndexOf({(real or 0)+2})
				return p.PrimeTable.lists[real] ~= nil
			end
		end
		--非第一象限高斯質數
		if imag < 0 or real < 0 then return false end
		if imag ~= 0 and real == 0 then return false end
		local value = imag*imag + real*real
		--both are nonzero and a² + b² is a prime number (which will not be of the form 4n + 3).
		if numdata._is_integer((value - 3.0) / 4.0) then return false end
		if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end
		p.PrimeTable.primeIndexOf({value+2})
		return p.PrimeTable.lists[value] ~= nil
	end,
	sqrt=function(z)
		local real, imag = p.cmath.readPart(z)
		local argument = 0
		local length = math.sqrt( real * real + imag * imag )
		if imag ~= 0 then
			argument = 2.0 * math.atan(imag / (length + real))
		else
			if real > 0 then argument = 0.0 
			else argument = math.pi end
		end
		local sq_len = math.sqrt(length)
		return p.cmath.getComplexNumber(sq_len * math.cos(argument/2.0), sq_len * math.sin(argument/2.0)):clean()
	end,
	root=function(_z,_n,_num)
		local z = p.cmath.getComplexNumber(p.cmath.readPart(_z))
		local n = p.cmath.getComplexNumber(p.cmath.readPart(_n or 2))
		local num = p.cmath.getComplexNumber(p.cmath.readPart(_num or 1))
		if num == p.cmath.one or num == p.cmath.zero or num == nil then
			return p.cmath.pow(z, p.cmath.inverse(n))
		end
		local sgn_data = p.cmath.getComplexNumber(0, 1)
		local result = p.cmath.pow(p.cmath.abs(z), p.cmath.inverse(n)) * p.cmath.exp(sgn_data * (p.cmath.arg(z) + (num-1)*(2*math.pi) ) * p.cmath.inverse(n))
		result:clean()
		return result
	end,
	sin=function(z)
		local real, imag = p.cmath.readPart(z)
		return p.cmath.getComplexNumber(math.sin(real) * math.cosh(imag), math.cos(real) * math.sinh(imag)) 
	end,
	cos=function(z)
		local real, imag = p.cmath.readPart(z)
		return p.cmath.getComplexNumber(math.cos(real) * math.cosh(imag), -math.sin(real) * math.sinh(imag)) 
	end,
	tan=function(z)
		local theta = p.cmath.readComplexNumber(z)  
		return p.cmath.sin(theta) / p.cmath.cos(theta)
	end,
	cot=function(z)
		local theta = p.cmath.readComplexNumber(z)  
		return p.cmath.cos(theta) / p.cmath.sin(theta)
	end,

	asin=function(z)
		local real, imag = p.cmath.readPart(z)
		local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
		local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
		return -sgnimag * p.cmath.asinh( v * sgnimag )
	end,
	acos=function(z)
		local real, imag = p.cmath.readPart(z)
		local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
		local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
		return -sgnimag * p.cmath.acosh( v )
	end,
	atan=function(z)
		local real, imag = p.cmath.readPart(z)
		local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
		local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
		return -sgnimag * p.cmath.atanh( v * sgnimag )
	end,
	acot=function(z)
		local real, imag = p.cmath.readPart(z)
		local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
		local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
		return sgnimag * p.cmath.acoth( v * sgnimag )
	end,
	
	sinh=function(z)
		local real, imag = p.cmath.readPart(z)
		local im_sgn if imag > 0 then im_sgn = 1 elseif imag < 0 then im_sgn = -1 else im_sgn = 0 end
		return p.cmath.getComplexNumber( math.cos(math.abs(imag)) * math.sinh(real) , im_sgn * math.sin(math.abs(imag)) * math.cosh(real) )
	end,
	cosh=function(z)
		local real, imag = p.cmath.readPart(z)
		local im_sgn if imag > 0 then im_sgn = 1 elseif imag < 0 then im_sgn = -1 else im_sgn = 0 end
		return p.cmath.getComplexNumber( math.cos(math.abs(imag)) * math.cosh(real) , im_sgn * math.sin(math.abs(imag)) * math.sinh(real) )
	end,
	tanh=function(z)
		local theta = p.cmath.readComplexNumber(z)
		return p.cmath.sinh(theta) / p.cmath.cosh(theta)
	end,
	coth=function(z)
		local theta = p.cmath.readComplexNumber(z)
		return p.cmath.cosh(theta) / p.cmath.sinh(theta)
	end,

	asinh=function(z)
		local real, imag = p.cmath.readPart(z)
		local u = p.cmath.getComplexNumber(real, imag)
		return p.cmath.log( u + p.cmath.sqrt( u * u + p.cmath.getComplexNumber(1,0) ) )
	end,
	acosh=function(z)
		local real, imag = p.cmath.readPart(z)
		local u = p.cmath.getComplexNumber(real, imag)
		return p.cmath.log( u + p.cmath.sqrt( u + p.cmath.getComplexNumber(1,0) ) * p.cmath.sqrt( u + p.cmath.getComplexNumber(-1,0) ) )
	end,
	atanh=function(z)
		local real, imag = p.cmath.readPart(z)
		local u = p.cmath.getComplexNumber(real, imag)
		return ( p.cmath.log( 1 + u ) - p.cmath.log( 1 - u ) ) / 2
	end,
	acoth=function(z)
		local real, imag = p.cmath.readPart(z)
		local u = p.cmath.getComplexNumber(real, imag)
		return ( p.cmath.log( 1 + p.cmath.inverse(u) ) - p.cmath.log( 1 - p.cmath.inverse(u) ) ) / 2
	end,

	dot=function (op1, op2)
		local real1, imag1 = p.cmath.readPart(op1)
		local real2, imag2 = p.cmath.readPart(op2)
		return real1 * real2 + imag1 * imag2 
	end,
	outer = function (op1, op2) 
		return p.cmath.getComplexNumber(0, 0)
	end,
	sgn=function(z)
		local real, imag = p.cmath.readPart(z)
		if real == 0 and imag == 0 then return p.cmath.getComplexNumber(0, 0) end
		local length = math.sqrt( real * real + imag * imag )
		return p.cmath.getComplexNumber(real/length, imag/length)
	end,
	arg=function(z)
		local real, imag = p.cmath.readPart(z)
		if imag ~= 0 then
			local length = math.sqrt( real * real + imag * imag )
			return 2.0 * math.atan(imag / (length + real))
		else
			if real >= 0 then return 0.0 
			else return math.pi end
		end
		return tonumber("nan")
	end,
	cis=function(z)
		local real, imag = p.cmath.readPart(z)
		local hyp = 1
		if imag ~= 0 then hyp = math.cosh(imag) - math.sinh(imag) end
		return p.cmath.getComplexNumber(math.cos(real) * hyp, math.sin(real) * hyp)
	end,
	exp=function(z)
		local real, imag = p.cmath.readPart(z)
		local cis_r, cis_i, exp_r = 1, 0, math.exp(real)
		if imag ~= 0 then cis_r, cis_i = math.cos(imag), math.sin(imag) end
		return p.cmath.getComplexNumber(exp_r * cis_r, exp_r * cis_i)
	end,
	elog=function(z)
		local real, imag = p.cmath.readPart(z)
		local argument = 0
		local length = math.sqrt( real * real + imag * imag )
		if imag ~= 0 then
			argument = 2.0 * math.atan(imag / (length + real))
		else
			if real > 0 then argument = 0.0 
			else argument = math.pi end
		end
		return p.cmath.getComplexNumber(math.log(length), argument)
	end,
	log=function(z,basez)
		if basez~=nil then return p.cmath.elog(basez) * p.cmath.inverse(p.cmath.elog(z)) end
		return p.cmath.elog(z)
	end,
	eisenstein=function(op1)
		local real1, imag1 = tonumber(op1) or op1.real,  (tonumber(op1) and 0) or op1.imag
		local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
		return p._eisenstein_integer(real1+sqrt33*imag1, 2*sqrt33*imag1)
	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.cmath.getComplexNumber(1,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.cmath.getComplexNumber(1,0) -- z^0 === 1, z ≠ 0
			else return p.cmath.getComplexNumber(tonumber('nan'),0) end -- 0^0 Indeterminate
		elseif check_op1 == 0 then 
			if check_op2 < 0 then return p.cmath.getComplexNumber(tonumber('inf'),0) end -- 0^(-n) Infinity
			return p.cmath.getComplexNumber(0,0) -- 0^z === 0, z ≠ 0
		end
		--a ^ z
		local a = p.cmath.getComplexNumber( tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.imag )
		local z = p.cmath.getComplexNumber( tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag )
		return p.cmath.exp(z * p.cmath.log(a)):clean()
	end,

	random = function (op1, op2)
		if type(op1)==type(nil) and type(op2)==type(nil) then return p.cmath.getComplexNumber(math.random(),0) end
		local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or (op2 or{}).real
		local imag1, imag2 = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or (op2 or{}).imag
		if type(op2)==type(nil) then return p.cmath.getComplexNumber(sollib._random(real1), sollib._random(imag1)) end
		return p.cmath.getComplexNumber(sollib._random(math.min(real1,real2), math.max(real1,real2)), sollib._random(math.min(imag1,imag2), math.max(imag1,imag2))) 
	end,

	isReal=function(z) return math.abs((tonumber(z) and 0) or z.imag) < 1e-14 end,
	
	ComplexNumberMeta = {
		__add = function (op1, op2) 
			local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local imag1, imag2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			return p.cmath.getComplexNumber(real1 + real2, imag1 + imag2) 
		end,
		__sub = function (op1, op2) 
			local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local imag1, imag2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			return p.cmath.getComplexNumber(real1 - real2, imag1 - imag2) 
		end,
		__mul = function (op1, op2) 
			local a, c = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local b, d = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			return p.cmath.getComplexNumber(a * c - b * d, b * c + a * d) 
		end,
		__div = function (op1, op2) 
			local a, c = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local b, d = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			local op1_d, op2_d = a*a + b*b, c*c + d*d
			if op2_d <= 0 then return op1_d / op2_d end
			return p.cmath.getComplexNumber((a * c + b * d) / op2_d, (b * c - a * d) / op2_d) 
		end,
		__mod = function (op1, op2) 
			local x = p.cmath.getComplexNumber(tonumber(op1) or (op1 or {}).real, (tonumber(op1) and 0) or (op1 or {}).imag)
			local y = p.cmath.getComplexNumber(tonumber(op2) or (op2 or {}).real, (tonumber(op2) and 0) or (op2 or {}).imag) 
			return x - y * p.cmath.floor(x / y) 
		end,
		__tostring = function (this) 
			local body = ''
			if this.real ~= 0 then body = tostring(this.real) end
			if this.imag ~= 0 then 
				if body ~= '' and this.imag > 0 then body = body .. '+' end
				if this.imag == -1 then  body = body .. '-' end
				if math.abs(this.imag) ~= 1 then body = body .. tostring(this.imag) end
				body = body .. 'i'
			end
			if sollib._isNaN(this.real) or sollib._isNaN(this.imag) then body = 'nan' end
			if body == '' then body = '0' end
			return body
		end,
		__unm = function (this)
			return p.cmath.getComplexNumber(-this.real, -this.imag) 
		end,
		__eq = function (op1, op2)
			local diff_real = math.abs( (tonumber(op1) or (op1 or {}).real) - (tonumber(op2) or (op2 or {}).real) )
			local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or (op1 or {}).imag) - ( (tonumber(op2) and 0) or (op2 or {}).imag) )
			return diff_real < 1e-12 and diff_imag1 < 1e-12
		end,
	},
	readComplexNumber = function(z)
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "complex" then
				return z
			elseif z.numberType == "quaternion" then
				return p.cmath.getComplexNumber(z.real, z.imag)
			end
		elseif type(z) == type(0) then
			return p.cmath.getComplexNumber(z, 0)
		elseif type(z) == type(true) then
			return p.cmath.getComplexNumber(z and 1 or 0, 0)
		end
		return p.cmath.getComplexNumber(tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or (z or {}).imag or 0)
	end,
	readPart = function(z)
		if type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find.
			return z.real, z.imag
		elseif type(z) == type(0) then
			return z, 0
		elseif type(z) == type(true) then
			return z and 1 or 0, 0
		end
		return tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or (z or {}).imag or 0
	end,
	ele=function(id)
		local _zero = p.cmath.getComplexNumber(0, 0)
		local eles = (p.cmath.elements or {})
		local id_msg = tonumber(tostring(id)) or 0
		return eles[id_msg+1]or _zero
	end,
	getComplexNumber = function(real,imag)
		local ComplexNumber = {}
		setmetatable(ComplexNumber,p.cmath.ComplexNumberMeta) 
		function ComplexNumber:update()
			self.argument = 0
			self.length = math.sqrt( self.real * self.real + self.imag * self.imag )
			if self.imag ~= 0 then
				self.argument = 2.0 * math.atan(self.imag / (self.length + self.real))
			else
				if self.real > 0 then self.argument = 0.0 
				else self.argument = math.pi end
			end
		end
		function ComplexNumber:clean()
			if math.abs(self.real) <= 1e-12 then self.real = 0 end
			if math.abs(self.imag) <= 1e-12 then self.imag = 0 end
			if math.abs(self.real - math.floor(self.real)) <= 1e-12 then self.real = math.floor(self.real) end
			if math.abs(self.imag - math.floor(self.imag)) <= 1e-12 then self.imag = math.floor(self.imag) end
			return self
		end
		ComplexNumber.real, ComplexNumber.imag = real, imag
		ComplexNumber.numberType = "complex"
		return ComplexNumber
	end,
	toComplexNumber = function(num_str)
		if type(num_str)==type({"table"}) and num_str.isEisensteinNumber == true then 
			real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local eis = p._eisenstein_integer(real+sqrt33*imag, 2*sqrt33*imag)
			eis.real,eis.imag = real, imag
			return eis 
		end
		if type(num_str) == type({}) then --if already be complex number, don't run string find.
			if num_str.numberType == "complex" then
				return num_str
			elseif num_str.numberType == "quaternion" then
				return p.cmath.getComplexNumber(num_str.real, num_str.imag)
			end
		elseif type(num_str) == type(0) then
			return p.cmath.getComplexNumber(num_str, 0)
		elseif type(num_str) == type(true) then
			return p.cmath.getComplexNumber(num_str and 1 or 0, 0)
		elseif type(num_str) == type("string") then
			local check_number = tonumber(num_str)
			if check_number ~= nil then return p.cmath.getComplexNumber(check_number, 0) end
		end
		local real, imag
		if num_str == nil then return nil end
		if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
			real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag
		else real, imag = p.cmath.toComplexNumberPart(num_str)end
		if real == nil or imag == nil then return nil end
		return p.cmath.getComplexNumber(real, imag)
	end,
	toComplexNumberPart = function(num_str)
		if type(num_str) == type(function()end) then return end
		if type(num_str) == type(true) then if num_str then return 1,0 else return 0,0 end end
		local body = ''
		local real, imag = 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(
				tostring(num_str) or '',
			'%s+',''),'%++([%d%.])',',+%1'),'%++([ij])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ij])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ij])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ij])',',/1%1'),',')
		local first = true
		local continue = false
		
		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.ustring.gsub(mw.text.trim(v),'[ij]+','i'),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ij])','+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%.]+i?")
				if num_text ~= val then return end
				local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
				if num_part == nil then return end
				if mw.ustring.find(num_text,"i") then
					imag = imag + num_part
				else
					real = real + num_part
				end
			end
		end
		return real, imag
	end,
	halfNumberParts = function(num)
		local real, imag = p.cmath.readPart(num)
		return {real, imag}
	end,
	init = function()
		p.cmath.e = p.cmath.getComplexNumber(math.exp(1), 0) 
		p.cmath.pi = p.cmath.getComplexNumber(math.pi, 0) 
		p.cmath["π"] = p.cmath.getComplexNumber(math.pi, 0)
		p.cmath["°"] = p.cmath.getComplexNumber(math.pi/180, 0)
		p.cmath.nan = p.cmath.getComplexNumber(tonumber("nan"), tonumber("nan")) 
		p.cmath.infi = p.cmath.getComplexNumber(0, tonumber("inf")) 
		p.cmath.zero = p.cmath.getComplexNumber(0, 0) 
		p.cmath.one = p.cmath.getComplexNumber(1, 0) 
		p.cmath[-1] = p.cmath.getComplexNumber(-1, 0) 
		p.cmath[eImag] = p._eisenstein_integer(0, 1)
		p.cmath.i = p.cmath.getComplexNumber(0, 1) 
		p.cmath[0],p.cmath[1] = p.cmath.zero,p.cmath.one
		p.cmath.numberType = sollib._numberType
		p.cmath.constructor = p.cmath.toComplexNumber
		p.cmath.elements = {
			p.cmath.getComplexNumber(1, 0),
			p.cmath.getComplexNumber(0, 1)
		}
		return p.cmath
	end
}
p.math={
	init = function()
		local my_math = math 
		my_math.e, my_math.nan = math.exp(1), tonumber("nan")
		my_math["π"] = math.pi
		my_math["°"] = math.pi/180
		my_math.zero, my_math.one, my_math[-1] = 0, 1, -1
		my_math[0],my_math[1] = my_math.zero,my_math.one
		
		my_math.inverse = function(x)return 1.0/(tonumber(x)or 1.0)end
		my_math.sgn=function(x)if x==0 then return 0 elseif x<0 then return -1 elseif x>0 then return 1 else return tonumber("nan")end end
		my_math.arg=function(x)if x >= 0 then return 0.0 else return math.pi end end
		my_math.re=function(z) return tonumber(z) or z.real or 0 end
		my_math.im=function(z) return (tonumber(z) and 0) or z.imag or 0 end
		my_math.conjugate=function(z) return tonumber(z) or z.real or 0 end
		my_math.root=function(z,n) return math.pow((tonumber(z)or 1.0), (1.0/(tonumber(n)or 1.0))) end
		my_math.nonRealPart=function(z) return (tonumber(z) and 0) or z.imag or 0 end
		my_math.tovector=function(z) return {tonumber(z) or z.real or 0} end
		my_math.trunc=function(z,digs) 
			local x = tonumber(z) or z.real or 0
			local n = tonumber(digs) or digs.real or 0
			local _10_n = math.pow(10,n)
			local _10_n_x = _10_n * x
			return (x >= 0)and(math.floor(_10_n_x) / _10_n)or(math.ceil(_10_n_x) / _10_n)
		end
		my_math.div=function(op1,op2) return tonumber(op1) / tonumber(op2) end
		my_math.dot=function(x,y)return x*y end
		
		--sin, cos, tan are already support
		my_math.cot=function(z)local theta = tonumber(z)return math.cos(theta) / math.sin(theta)end
		
		--asin, acos, atan are already support
		my_math.acot=function(x)return p.cmath.acot(x).real end
		
		--sinh, cosh, tanh are already support
		my_math.coth=function(x)return math.cosh(x) / math.sinh(x) end
		
		my_math.asinh=function(x)return math.log( x + math.sqrt( x * x + 1 ) )end
		my_math.acosh=function(x)return math.log( x + math.sqrt( x * x - 1 ) )end
		my_math.atanh=function(x) local result = p.cmath.atanh(x):clean() if math.abs(result.imag) > 1e-12 then return tonumber('nan') else return result.real end end
		my_math.acoth=function(x) local result = p.cmath.acoth(x):clean() if math.abs(result.imag) > 1e-12 then return tonumber('nan') else return result.real end end
		
		my_math.ele=function(id)
			if (tonumber(tostring(id))or -1) == 0 then return 1 end
			return 0
		end

		my_math.isReal = function(x) if type(x)==type(true) then return true else return tonumber(x)~=nil end end

		my_math.numberType = sollib._numberType
		my_math.constructor = function(x) if type(x)==type(true) then return x and 1 or 0 else return tonumber(x) end end

		my_math.elements = {1}
		return my_math
	end
}
p.bmath={
	abs=function(_z)
		local z = p.bmath.toBoolean(_z)
		return (not not z.value) and 1 or 0
	end,
	sgn=function(_z)
		local z = p.bmath.toBoolean(_z)
		return (not not z.value) and 1 or 0
	end,
	as=function(op1, op2)
		local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
		b.value = a.value
		return b 
	end,
	nonRealPart=function(bv) return p.bmath.toBoolean(0) end,
	BooleanNumberMeta = {
		__add = function (op1, op2) 
			local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
			a.value = a.value or b.value
			return a 
		end,
		__sub = function (op1, op2) 
			local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
			a.value = a.value and (not b.value)
			return a 
		end,
		__mul = function (op1, op2) 
			local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
			a.value = a.value and b.value
			return a 
		end,
		__tostring = function (this) return this.value_table[this.value] end,
		__unm = function (this)local that = p.bmath.toBoolean(this)that.value = not that.value return that end,
		__eq = function (op1, op2)return p.bmath.toBoolean(op1).value == p.bmath.toBoolean(op2).value end,
	},
	value_table={
		[1]={[true]=1,[false]=0},[0]={[true]=1,[false]=0},
		['1']={[true]=1,[false]=0},['0']={[true]=1,[false]=0},
		['yes']={[true]='yes',[false]='no'},['no']={[true]='yes',[false]='no'},
		['y']={[true]='Y',[false]='N'},['n']={[true]='Y',[false]='N'},
		[true]={[true]=true,[false]=false},[false]={[true]=true,[false]=false},
		['true']={['true']=true,['false']=false},['false']={['true']=true,['false']=false},
		['t']={[true]='T',[false]='F'},['f']={[true]='T',[false]='F'},
		['on']={[true]='on',[false]='off'},['off']={[true]='on',[false]='off'},
		['是']={[true]='是',[false]='否'},['否']={[true]='是',[false]='否'},
		['真']={[true]='真',[false]='假'},['假']={[true]='真',[false]='假'},
		['有']={[true]='有',[false]='無'},['無']={[true]='有',[false]='無'},['无']={[true]='有',[false]='无'},
		['开']={[true]='开',[false]='关'},['关']={[true]='开',[false]='关'},
		['開']={[true]='開',[false]='關'},['關']={[true]='開',[false]='關'},},
	toBoolean = function(num_str)
		local BooleanNumber = {}
		if (type(num_str) == type({}) and num_str.numberType == "boolean") then return num_str end
		if (type(num_str) == type({})) and num_str.value_table ~= nil and num_str.value ~= nil then 
			BooleanNumber = {value_table=num_str.value_table,value=num_str.value}
		elseif (type(num_str) == type({}) and type(num_str.numberType)==type("string") and num_str.numberType ~= "boolean")then 
			local data = tostring(num_str) ~= "0"
			BooleanNumber = {}
			BooleanNumber.value_table={[true]='T',[false]='F'}
			BooleanNumber.value=data
		elseif (type(num_str) == type(0))then 
			local data = math.abs(num_str) > 1e-14
			BooleanNumber = {}
			BooleanNumber.value_table={[true]='T',[false]='F'}
			BooleanNumber.value=data
		elseif (type(num_str) == type(true))then 
			local data = num_str
			BooleanNumber = {}
			BooleanNumber.value_table={[true]='T',[false]='F'}
			BooleanNumber.value=data
		else
			if yesno == nil then yesno = require('Module:Yesno') end
			local input_str = mw.ustring.gsub(mw.text.trim(tostring(num_str)),"%s",'')
			input_str = mw.ustring.gsub(input_str,"([真假有無无])",function(str) return(
				{['真']='是',['假']='否',['有']='是',['無']='否',['无']='否'})[str] or str end)
			local data = yesno(num_str) or yesno(input_str)
			if data == nil then return nil end
			BooleanNumber = {}
			BooleanNumber.value_table=p.bmath.value_table[num_str] or p.bmath.value_table[input_str] or {[true]='T',[false]='F'}
			BooleanNumber.value=data
		end
		setmetatable(BooleanNumber,p.bmath.BooleanNumberMeta) 
		BooleanNumber.numberType = "boolean"
		return BooleanNumber
	end,
	init = function()
		p.bmath.zero = p.bmath.toBoolean(0) 
		p.bmath.one = p.bmath.toBoolean(1) 
		p.bmath[0],p.bmath[1] = p.bmath.zero,p.bmath.one
		p.bmath.is_bool_lib = true
		p.bmath.numberType = sollib._numberType
		p.bmath.constructor = p.bmath.toBoolean
		p.bmath.elements = {true}
		return p.bmath
	end
}
p.qmath = {
	abs=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		if imag == 0 and jpart == 0 and kpart == 0 then return math.abs(real) end
		return math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart )
	end,
	floor=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		return p.qmath.getQuaternionNumber(math.floor(real), math.floor(imag), math.floor(jpart), math.floor(kpart))
	end,
	ceil=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		return p.qmath.getQuaternionNumber(math.ceil(real), math.ceil(imag), math.ceil(jpart), math.ceil(kpart))
	end,
	div=function(left,z)
		local lreal, limag, ljpart, lkpart = p.qmath.readPart(left)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		return p.qmath.getQuaternionNumber(lreal, limag, ljpart, lkpart) * (p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) / ( real*real + imag*imag + jpart*jpart + kpart*kpart ))
	end,
	round=function(op1,op2,op3)
		local number = p.qmath.getQuaternionNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or (op1.imag or 0) or 0, (tonumber(op1) and 0) or (op1.jpart or 0) or 0, (tonumber(op1) and 0) or (op1.kpart or 0) or 0) 
		local digs = p.qmath.getQuaternionNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or ((op2 or {}).imag or 0) or 0, (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) or 0 ) 
		local base = p.qmath.getQuaternionNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or ((op3 or {}).imag or 0) or 0, (tonumber(op3) and 0) or ((op3 or {}).jpart or 0) or 0, (tonumber(op3) and 0) or ((op3 or {}).kpart or 0) or 0 ) 
		local round_rad = p.qmath.pow(base,digs)
		local check_number = number * round_rad
		check_number.real = check_number.real + 0.5; check_number.imag = check_number.imag + 0.5; 
		check_number.jpart = check_number.jpart + 0.5; check_number.kpart = check_number.kpart + 0.5; 
		return p.qmath.floor( check_number ) * p.qmath.inverse(round_rad)
	end,
	re=function(z)return tonumber(z) or z.real end,
	im=function(z) return (tonumber(z) and 0) or z.imag end,
	conjugate=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		return p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart )
	end,
	inverse=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		return p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) / ( real*real + imag*imag + jpart*jpart + kpart*kpart )
	end,
	tovector=function(z)
		return {p.qmath.readPart(z)}
	end,
	trunc=function(z,digs)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local n = tonumber(digs) or digs.real or 0
		return p.qmath.getQuaternionNumber( sollib._trunc(real,n), sollib._trunc(imag,n), sollib._trunc(jpart,n), sollib._trunc(kpart,n) )
	end,
	sqrt=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		if jpart == 0 and kpart == 0 then 
			local complex = p.cmath.sqrt(p.cmath.getComplexNumber(real, imag))
			return p.qmath.getQuaternionNumber(complex.real, complex.imag, 0, 0)
		end
		return p.qmath.pow(z, 0.5)
	end,
	root=function(_z,_n,_num)
		local z = p.qmath.getQuaternionNumber(p.qmath.readPart(_z))
		local n = p.qmath.getQuaternionNumber(p.qmath.readPart(_n or 2))
		local num = p.qmath.getQuaternionNumber(p.qmath.readPart(_num or 1))
		if num == p.qmath.one or num == p.qmath.zero or num == nil then
			return p.qmath.pow(z, p.qmath.inverse(n))
		end
		local sgn_data = p.qmath.sgn(p.qmath.nonRealPart(z))
		if math.abs(sgn_data.imag)<1e-14 and math.abs(sgn_data.jpart)<1e-14 and math.abs(sgn_data.kpart)<1e-14 then sgn_data=p.qmath.getQuaternionNumber(0,1,0,0) end
		local result = p.qmath.pow(p.qmath.abs(z), p.qmath.inverse(n)) * p.qmath.exp(sgn_data * (p.qmath.arg(z) + (num-1)*(2*math.pi) ) * p.qmath.inverse(n))
		result:clean()
		return result
	end,
	sin=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
		return ( math.cosh(p.qmath.abs(u)) * math.sin(real) ) + ( p.qmath.sgn(u) * math.sinh(p.qmath.abs(u)) * math.cos(real) )
	end,
	cos=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
		return ( math.cosh(p.qmath.abs(u)) * math.cos(real) ) - ( p.qmath.sgn(u) * math.sinh(p.qmath.abs(u)) * math.sin(real) )
	end,
	tan=function(z)
		local theta = p.qmath.readComplexNumber(z)
		return p.qmath.sin(theta) * p.qmath.inverse( p.qmath.cos(theta) )
	end,
	cot=function(z)
		local theta = p.qmath.readComplexNumber(z)
		return p.qmath.cos(theta) * p.qmath.inverse( p.qmath.sin(theta) )
	end,

	asin=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		local sgnu = p.qmath.sgn(u); 
		if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
		return -sgnu * p.qmath.asinh( v * sgnu )
	end,
	acos=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		local sgnu = p.qmath.sgn(u); 
		if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
		return -sgnu * p.qmath.acosh( v )
	end,
	atan=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		local sgnu = p.qmath.sgn(u); 
		if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
		return -sgnu * p.qmath.atanh( v * sgnu )
	end,
	acot=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		local sgnu = p.qmath.sgn(u); 
		if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
		return sgnu * p.qmath.acoth( v * sgnu )
	end,

	sinh=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
		return ( math.cos(p.qmath.abs(u)) * math.sinh(real) ) + ( p.qmath.sgn(u) * math.sin(p.qmath.abs(u)) * math.cosh(real) )
	end,
	cosh=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return ( math.cos(p.qmath.abs(u)) * math.cosh(real) ) + ( p.qmath.sgn(u) * math.sin(p.qmath.abs(u)) * math.sinh(real) )
	end,
	tanh=function(z)
		local theta = p.qmath.readComplexNumber(z)
		return p.qmath.sinh(theta) * p.qmath.inverse( p.qmath.cosh(theta) )
	end,
	coth=function(z)
		local theta = p.qmath.readComplexNumber(z)
		return p.qmath.cosh(theta) * p.qmath.inverse( p.qmath.sinh(theta) )
	end,

	asinh=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return p.qmath.log( u + p.qmath.sqrt( u * u + p.qmath.getQuaternionNumber(1,0,0,0) ) )
	end,
	acosh=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return p.qmath.log( u + p.qmath.sqrt( u + p.qmath.getQuaternionNumber(1,0,0,0) ) * p.qmath.sqrt( u + p.qmath.getQuaternionNumber(-1,0,0,0) ) )
	end,
	atanh=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return ( p.qmath.log( 1 + u ) - p.qmath.log( 1 - u ) ) / 2
	end,
	acoth=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return ( p.qmath.log( 1 + p.qmath.inverse(u) ) - p.qmath.log( 1 - p.qmath.inverse(u) ) ) / 2
	end,

	dot = function (op1, op2) 
		local a, t = tonumber(op1) or op1.real, tonumber(op2) or op2.real
		local b, x = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
		local c, y = (tonumber(op1) and 0) or (op1.jpart or 0), (tonumber(op2) and 0) or (op2.jpart or 0)
		local d, z = (tonumber(op1) and 0) or (op1.kpart or 0), (tonumber(op2) and 0) or (op2.kpart or 0)
		return a * t + b * x + c * y + d * z
	end,
	outer = function (op1, op2) 
		local a, t = tonumber(op1) or op1.real, tonumber(op2) or op2.real
		local b, x = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
		local c, y = (tonumber(op1) and 0) or (op1.jpart or 0), (tonumber(op2) and 0) or (op2.jpart or 0)
		local d, z = (tonumber(op1) and 0) or (op1.kpart or 0), (tonumber(op2) and 0) or (op2.kpart or 0)
		return p.qmath.getQuaternionNumber(0,
			c*z-d*y,
			d*x-b*z,
			b*y-x*c
		)
	end,

	scalarPartQuaternion=function(z)
		return p.qmath.getQuaternionNumber(tonumber(z) or z.real, 0, 0, 0)
	end,
	nonRealPart=function(z) return p.qmath.getQuaternionNumber(0, (tonumber(z) and 0) or (z.imag or 0), (tonumber(z) and 0) or (z.jpart or 0), (tonumber(z) and 0) or (z.kpart or 0)) end,
	vectorPartQuaternion=function(z)
		return p.qmath.getQuaternionNumber(0, (tonumber(z) and 0) or (z.imag or 0), (tonumber(z) and 0) or (z.jpart or 0), (tonumber(z) and 0) or (z.kpart or 0))
	end,
	sgn=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local length = math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart )
		if length <= 0 then return p.qmath.getQuaternionNumber(0,0,0,0) end
		return z / length
	end,
	arg=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local length = math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart )
		return math.acos( real / length )
	end,
	cis=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return p.qmath.cos(u) + p.qmath.getQuaternionNumber(0,1,0,0) * p.qmath.sin(u)
	end,
	exp=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
		return ( (p.qmath.sgn(u) * math.sin(p.qmath.abs(u))) + math.cos(p.qmath.abs(u))) * math.exp(real)
	end,
	elog=function(z)
		local real, imag, jpart, kpart = p.qmath.readPart(z)
		local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
		return (p.qmath.sgn(u) * p.qmath.arg(v)) + math.log(p.qmath.abs(v))
	end,
	log=function(z,basez)
		if basez~=nil then return p.qmath.elog(basez) * p.qmath.inverse(p.qmath.elog(z)) end
		return p.qmath.elog(z)
	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.qmath.getQuaternionNumber(1,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.qmath.getQuaternionNumber(1,0,0,0) -- z^0 === 1, z ≠ 0
			else return p.qmath.getQuaternionNumber(tonumber('nan'),0,0,0) end --0^0 Indeterminate
		elseif check_op1 == 0 then 
			if check_op2 < 0 then return p.qmath.getQuaternionNumber(tonumber('inf'),0,0,0) end -- 0^(-n) Infinity
			return p.qmath.getQuaternionNumber(0,0,0,0) -- 0^z === 0, z ≠ 0
		end
		--a ^ z
		local a = p.qmath.getQuaternionNumber( p.qmath.readPart(op1) )
		local z = p.qmath.getQuaternionNumber( p.qmath.readPart(op2) )
		a:clean();z:clean();
		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,

	random = function (op1, op2)
		if type(op1)==type(nil) and type(op2)==type(nil) then return p.qmath.getQuaternionNumber(math.random(), 0, 0, 0) end
		local a, t = tonumber(op1) or (op1 or {}).real or 0, tonumber(op2) or (op2 or{}).real or 0
		local b, x = (tonumber(op1) and 0) or (op1 or {}).imag or 0, (tonumber(op2) and 0) or (op2 or{}).imag or 0
		local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or{}).jpart or 0)
		local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or{}).kpart or 0)
		if type(op2)==type(nil) then return p.qmath.getQuaternionNumber(sollib._random(a), sollib._random(b), sollib._random(c), sollib._random(d)) end
		return p.qmath.getQuaternionNumber(sollib._random(math.min(a, t), math.max(a, t)), sollib._random(math.min(b, x), math.max(b, x)), sollib._random(math.min(c, y), math.max(c, y)), sollib._random(math.min(d, z), math.max(d, z)))
	end,

	isReal=function(z) return p.qmath.abs(p.qmath.nonRealPart(z)) < 1e-14 end,
	
	QuaternionNumberMeta = {
		__add = function (op1, op2) 
			local a, t = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local b, x = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
			local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
			return p.qmath.getQuaternionNumber(a + t, b + x, c + y, d + z) 
		end,
		__sub = function (op1, op2) 
			local a, t = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local b, x = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
			local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
			return p.qmath.getQuaternionNumber(a - t, b - x, c - y, d - z) 
		end,
		__mul = function (op1, op2) 
			local a1, a2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local b1, b2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			local c1, c2 = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
			local d1, d2 = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
			return p.qmath.getQuaternionNumber(
				a1 * a2 - b1 * b2 - c1 * c2 - d1 * d2, 
				a1 * b2 + b1 * a2 + c1 * d2 - d1 * c2,
				a1 * c2 - b1 * d2 + c1 * a2 + d1 * b2, 
				a1 * d2 + b1 * c2 - c1 * b2 + d1 * a2
			) 
		end,
		__div = function (op1, op2) 
			local r1, r2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local i1, i2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
			local j1, j2 = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
			local k1, k2 = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
			if i2 ~= 0 or j2 ~= 0 or k2 ~= 0 then error( "Quaternion can not divide by non scalar value" ) end
			local op1_d, op2_d = r1*r1 + i1*i1 + j1*j1 + k1*k1, r2*r2 + i2*i2 + j2*j2 + k2*k2
			if op2_d <= 0 then return op1_d / op2_d end
			return p.qmath.getQuaternionNumber(r1/r2, i1/r2, j1/r2, k1/r2) 
		end,
		__mod = function (op1, op2) 
			local x = p.qmath.getQuaternionNumber(tonumber(op1) or (op1 or {}).real, (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op1) and 0) or ((op1 or {}).kpart or 0) )
			local y = p.qmath.getQuaternionNumber(tonumber(op2) or (op2 or {}).real, (tonumber(op2) and 0) or (op2 or {}).imag, (tonumber(op2) and 0) or ((op2 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) ) 
			return x - y * p.qmath.floor(x / y) 
		end,
		__tostring = function (this) 
			local body = ''
			if this.real ~= 0 then body = tostring(this.real) end
			if this.imag ~= 0 then 
				if body ~= '' and this.imag > 0 then body = body .. '+' end
				if this.imag == -1 then  body = body .. '-' end
				if math.abs(this.imag) ~= 1 then body = body .. tostring(this.imag) end
				body = body .. 'i'
			end
			if this.jpart ~= 0 then 
				if body ~= '' and this.jpart > 0 then body = body .. '+' end
				if this.jpart == -1 then  body = body .. '-' end
				if math.abs(this.jpart) ~= 1 then body = body .. tostring(this.jpart) end
				body = body .. 'j'
			end
			if this.kpart ~= 0 then 
				if body ~= '' and this.kpart > 0 then body = body .. '+' end
				if this.kpart == -1 then  body = body .. '-' end
				if math.abs(this.kpart) ~= 1 then body = body .. tostring(this.kpart) end
				body = body .. 'k'
			end
			if sollib._isNaN(this.real) or sollib._isNaN(this.imag) or sollib._isNaN(this.jpart) or sollib._isNaN(this.kpart) then body = 'nan' end
			if body == '' then body = '0' end
			return body
		end,
		__unm = function (this)
			return p.qmath.getQuaternionNumber(-this.real, -this.imag, -this.jpart, -this.kpart) 
		end,
		__eq = function (op1, op2)
			local diff_real = math.abs( (tonumber(op1) or (op1 or {}).real) - (tonumber(op2) or (op2 or {}).real) )
			local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or (op1 or {}).imag) - ( (tonumber(op2) and 0) or (op2 or {}).imag) )
			local diff_jpart = math.abs( ( (tonumber(op1) and 0) or ((op1 or {}).jpart or 0)) - ( (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)) )
			local diff_kpart = math.abs( ( (tonumber(op1) and 0) or ((op1 or {}).kpart or 0)) - ( (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)) )
			return diff_real < 1e-12 and diff_imag1 < 1e-12 and diff_jpart < 1e-12 and diff_kpart < 1e-12
		end,
	},
	ele=function(id)
		local _zero = p.qmath.getQuaternionNumber(0, 0, 0, 0)
		local eles = (p.qmath.elements or {})
		local id_msg = tonumber(tostring(id)) or 0
		return eles[id_msg+1]or _zero
	end,
	readComplexNumber = function(z)
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "complex" then
				return p.qmath.getQuaternionNumber(z.real, z.imag, 0, 0)
			elseif z.numberType == "quaternion" then
				return z
			end
		elseif type(z) == type(0) then
			return p.qmath.getQuaternionNumber(z, 0, 0, 0)
		elseif type(z) == type(true) then
			return p.qmath.getQuaternionNumber(z and 1 or 0, 0, 0, 0)
		end
		return p.qmath.getQuaternionNumber(tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, 
			((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).imag or 0), 
			((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).jpart or 0), 
			((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).kpart or 0)) 
	end,
	readPart = function(z)
		if type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find.
			if z.numberType == "quaternion"then
				return z.real, z.imag, z.jpart, z.kpart
			else
				return z.real, z.imag, 0, 0
			end
		elseif type(z) == type(0) then
			return z, 0, 0, 0
		elseif type(z) == type(true) then
			return z and 1 or 0, 0, 0, 0
		end
		return tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, 
			((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).imag or 0), 
			((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).jpart or 0), 
			((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).kpart or 0)
	end,
	getQuaternionNumber = function(real, imag, jpart, kpart)
		local QuaternionNumber = {}
		setmetatable(QuaternionNumber,p.qmath.QuaternionNumberMeta) 
		function QuaternionNumber:update()
			self.argument = 0
			self.length = math.sqrt( self.real * self.real + self.imag * self.imag
				+ self.jpart * self.jpart + self.kpart * self.kpart )
		end
		function QuaternionNumber:clean()
			if math.abs(self.real) <= 1e-12 then self.real = 0 end
			if math.abs(self.imag) <= 1e-12 then self.imag = 0 end
			if math.abs(self.jpart) <= 1e-12 then self.jpart = 0 end
			if math.abs(self.kpart) <= 1e-12 then self.kpart = 0 end
			if math.abs(self.real - math.floor(self.real)) <= 1e-12 then self.real = math.floor(self.real) end
			if math.abs(self.imag - math.floor(self.imag)) <= 1e-12 then self.imag = math.floor(self.imag) end
			if math.abs(self.jpart - math.floor(self.jpart)) <= 1e-12 then self.jpart = math.floor(self.jpart) end
			if math.abs(self.kpart - math.floor(self.kpart)) <= 1e-12 then self.kpart = math.floor(self.kpart) end
			return self
		end
		QuaternionNumber.real, QuaternionNumber.imag, QuaternionNumber.jpart, QuaternionNumber.kpart = real, imag, jpart, kpart
		QuaternionNumber.numberType = "quaternion"
		return QuaternionNumber
	end,
	toQuaternionNumber = function(num_str)
		local real, imag, jpart, kpart
		if num_str == nil then return nil end
		if type(num_str) == type({}) then --if already be complex number, don't run string find.
			if num_str.numberType == "quaternion" then
				return num_str 
			elseif num_str.numberType == "complex" then
				return p.qmath.getQuaternionNumber(num_str.real, num_str.imag, 0, 0)
			end
		elseif type(num_str) == type(1) then
			return p.qmath.getQuaternionNumber(num_str, 0, 0, 0)
		elseif type(num_str) == type(true) then
			return p.qmath.getQuaternionNumber(num_str and 1 or 0, 0, 0, 0)
		end
		if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
			real, imag, jpart, kpart = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or (num_str.imag or 0), (tonumber(num_str) and 0) or (num_str.jpart or 0), (tonumber(num_str) and 0) or (num_str.kpart or 0)
		else
			real, imag, jpart, kpart = p.qmath.toQuaternionNumberPart(tostring(num_str))
		end
		if real == nil or imag == nil or jpart == nil or kpart == nil then return nil end
		return p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
	end,
	toQuaternionNumberPart = function(num_str)
		if type(num_str) == type(function()end) then return end
		if type(num_str) == type(true) then if num_str then return 1,0,0,0 else return 0,0,0,0 end end
		local body = ''
		local real, imag, jpart, kpart = 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(
				tostring(num_str) or '',
			'%s+',''),'%++([%d%.])',',+%1'),'%++([ijk])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijk])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijk])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijk])',',/1%1'),',')
		local first = true
		local continue = false
		
		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'),'^([ijk])','+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%.]+[ijk]?")
				if num_text ~= val then return end
				local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
				if num_part == nil then return end
				if mw.ustring.find(num_text,"i") then
					imag = imag + num_part
				elseif mw.ustring.find(num_text,"j") then
					jpart = jpart + num_part
				elseif mw.ustring.find(num_text,"k") then
					kpart = kpart + num_part
				else
					real = real + num_part
				end
			end
		end
		return real, imag, jpart, kpart
	end,
	halfNumberParts = function(num)
		local real, imag, jpart, kpart = p.qmath.readPart(num)
		return {p.cmath.getComplexNumber(real, imag), p.cmath.getComplexNumber(jpart, kpart)}
	end,
	init = function()
		p.qmath.pi = p.qmath.getQuaternionNumber(math.pi, 0, 0, 0) 
		p.qmath["π"] = p.qmath.getQuaternionNumber(math.pi, 0, 0, 0)
		p.qmath["°"] = p.qmath.getQuaternionNumber(math.pi/180, 0, 0, 0)
		p.qmath.e = p.qmath.getQuaternionNumber(math.exp(1), 0, 0, 0)
		p.qmath.nan = p.qmath.getQuaternionNumber(tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan")) 
		p.qmath.infi = p.qmath.getQuaternionNumber(0, tonumber("inf"), 0, 0) 
		p.qmath.infj = p.qmath.getQuaternionNumber(0, 0, tonumber("inf"), 0) 
		p.qmath.infk = p.qmath.getQuaternionNumber(0, 0, 0, tonumber("inf")) 
		p.qmath.zero = p.qmath.getQuaternionNumber(0, 0, 0, 0) 
		p.qmath.one = p.qmath.getQuaternionNumber(1, 0, 0, 0) 
		p.qmath[-1] = p.qmath.getQuaternionNumber(-1, 0, 0, 0) 
		p.qmath.i = p.qmath.getQuaternionNumber(0, 1, 0, 0) 
		p.qmath.j = p.qmath.getQuaternionNumber(0, 0, 1, 0)
		p.qmath.k = p.qmath.getQuaternionNumber(0, 0, 0, 1) 
		p.qmath[0],p.qmath[1] = p.qmath.zero,p.qmath.one
		p.qmath.numberType = sollib._numberType
		p.qmath.constructor = p.qmath.toQuaternionNumber
		p.qmath.elements = {
			p.qmath.getQuaternionNumber(1, 0, 0, 0),
			p.qmath.getQuaternionNumber(0, 1, 0, 0),
			p.qmath.getQuaternionNumber(0, 0, 1, 0),
			p.qmath.getQuaternionNumber(0, 0, 0, 1),
		}
		return p.qmath
	end
}
p._efloor=function(z)
	local real, imag = tonumber(z) or z[eReal], (tonumber(z) and 0) or z[eImag]
	return p._eisenstein_integer(math.floor(real), math.floor(imag)) 
end
p._eisenstein_meta={
	__add = function (op1, op2) 
		local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
		local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
		if not real2 or not imag2 then 
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
			real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 
		end
		return p._eisenstein_integer(real1 + real2, imag1 + imag2) 
	end,
	__sub = function (op1, op2) 
		local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
		local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
		if not real2 or not imag2 then 
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
			real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 
		end
		return p._eisenstein_integer(real1 - real2, imag1 - imag2) 
	end,
	__mul = function (op1, op2) 
		local a, c = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
		local b, d = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
		if not c or not d then 
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
			c, d = real3+sqrt33*imag3, 2*sqrt33*imag3 
		end
		return p._eisenstein_integer(a * c - b * d, b * c + a * d - b * d) 
	end,
	__div = function (op1, op2) 
		local a, c = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
		local b, d = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
		if not c or not d then 
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
			c, d = real3+sqrt33*imag3, 2*sqrt33*imag3 
		end
		if c==d or c*c == (c*d*d)/(c-d) then
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local pn, q = p.cmath.getComplexNumber(a-b/2, sqrt32 * b), p.cmath.getComplexNumber(c-d/2, sqrt32 * d)
			local p_q = pn/q
			local real1, imag1 = tonumber(p_q) or p_q.real, (tonumber(p_q) and 0) or p_q.imag
			return p._eisenstein_integer(real1+sqrt33*imag1, 2*sqrt33*imag1)
		end
		local op1_d, op2_d = c*d/(c-d), c*c + (c*d*d)/(c-d)
		return p._eisenstein_integer((a * c + b * op1_d) / op2_d, (b * c - a * op1_d + b * op1_d) / op2_d)
	end,
	__mod = function (op1, op2) 
		local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
		local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
		if not real2 or not imag2 then 
			local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
			local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
			real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 
		end
		local x = p._eisenstein_integer(real1, imag1)
		local y = p._eisenstein_integer(real2, imag2) 
		return x - y * p._efloor(x / y) 
	end,
		__tostring = function (this) 
			local body = ''
			if this[eReal] ~= 0 then body = tostring(this[eReal]) end
			if this[eImag] ~= 0 then 
				if body ~= '' and this[eImag] > 0 then body = body .. '+' end
				if this[eImag] == -1 then  body = body .. '-' end
				if math.abs(this[eImag]) ~= 1 then body = body .. tostring(this[eImag]) end
				body = body .. eImag
			end
			if body == '' then body = '0' end
			return body
		end,
		__unm = function (this)
			return p._eisenstein_integer(-this[eReal], -this[eImag]) 
		end,
		__eq = function (op1, op2)
			local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
			local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
			if not real2 or not imag2 then 
				local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
				local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
				real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 
			end
			local diff_real = math.abs( real1 - real2 )
			local diff_imag1 = math.abs( imag1 - imag2 )
			return diff_real < 1e-12 and diff_imag1 < 1e-12
		end,
}

function p._eisenstein_integer(int_a, int_b)
	local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
	local eisenstein = p.cmath.getComplexNumber(int_a-int_b/2, sqrt32 * int_b)
	eisenstein[eReal], eisenstein[eImag] = int_a,int_b
	setmetatable(eisenstein,p._eisenstein_meta)
	eisenstein.isEisensteinNumber = true
	return eisenstein
end
function p._toEisensteinNumber(num_str)
	local real, imag
	if num_str == nil then return nil end
	if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
		real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag
	else
		real, imag = p._toEisensteinNumberPart(num_str)
	end
	if real == nil or imag == nil then return nil end
	return p._eisenstein_integer(real, imag)
end
function p._toEisensteinNumberPart(num_str)
	if type(num_str) == type(function()end) then return end
	local body = ''
	local real, imag, omg = 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(
			tostring(num_str) or '',
		'%s+',''),'%++([%d%.])',',+%1'),'%++([ijω])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijω])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijω])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijω])',',/1%1'),',')
	local first = true
	local continue = false
	
	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.ustring.gsub(mw.text.trim(v),'[ijω]+','i'),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijω])','+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%.]+i?")
			if num_text ~= val then return end
			local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
			if num_part == nil then return end
			if mw.ustring.find(num_text,"i") then
				imag = imag + num_part
			elseif mw.ustring.find(num_text,"ω") then
				omg = omg + num_part
			else
				real = real + num_part
			end
		end
	end
	local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
	return real+sqrt33*imag, 2*sqrt33*imag+omg
end

return p