模組:Complex Number/Solver

local p = {}
local getArgs = {} 
local comp_lib = {}
local matrix_lib = {}
local cmath = {}
local mmath = {}
local toCnumber = tonumber
local yesno = {}
local function load_comp_lib()
	if comp_lib.cmath == nil then 
		comp_lib = require("Module:Complex_Number") 
		cmath = comp_lib.cmath.init()
		toCnumber = cmath.constructor
	end
end
local function load_matrix_lib()
	if matrix_lib.mmath == nil then 
		matrix_lib = require("Module:Complex Number/Matrix") 
		mmath = matrix_lib.mmath.init()
	end
end
local function load_getArgs()
	if type(getArgs) ~= type(tonumber) then 
		getArgs = require('Module:Arguments').getArgs
	end
end
function p._trunc(x,n) 
	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
function p._random(_a, _b)
	local a, b = tonumber(_a), tonumber(_b)
	if type(_a)==type(nil) and type(_b)==type(nil) then return math.random() end
	local str_a = tostring(_a):lower()
	local str_b = tostring(_b):lower()
	if str_a == "nan" or str_a == "-nan" or
		str_b == "nan" or str_b == "-nan" then 
		return math.random()
	end
	if type(_b)==type(nil) then
		local sign = a < 0 and -1 or 1
		if math.abs(a) < 1 then return 0 end
		if math.abs(a) >= 1 and math.abs(a) < 2 then return sign * math.random(0,1) end
		return sign * math.random(math.abs(a))
	end
	if math.abs(a - b) < 1 then return a end
	return math.random(math.min(a, b), math.max(a, b))
end
function p._numberType(input_num) 
	if type(input_num) == type(0) then
		return "real"
	elseif type(input_num) == type({}) then
		return input_num.numberType or "nan"
	else
		return "nan"
	end
end
function p._isNaN(x)
	return (not (x==x)) and (x~=x)
end

function p._solveEQ(...)
	load_comp_lib()
	local coeffs = {...}
	local a = {}
	local zero = toCnumber("0")
	local find_leadership = false
	for i=1,#coeffs do
		local coeff = toCnumber(tostring(coeffs[i]))
		if not find_leadership then
			if coeff ~= zero then
				find_leadership = true
				a[#a+1] = coeff
			end
		else a[#a+1] = coeff end
	end
	local sol = {}
	if #a <= 1 then sol = {}
	elseif #a == 2 then sol = {-a[2]/a[1]}
	elseif #a == 3 then sol = {
		(-a[2] - cmath.sqrt(a[2]*a[2] - 4*a[1]*a[3]))/(2*a[1]),
		(-a[2] + cmath.sqrt(a[2]*a[2] - 4*a[1]*a[3]))/(2*a[1])
	} elseif #a == 4 then sol = p._cubicRoot(a[1],a[2],a[3],a[4])
	elseif #a == 5 then sol = p._quarticRoot(a[1],a[2],a[3],a[4],a[5])
	else error("in solveEQ(): Not Implemented Exception : Solving "..tostring((#a)-1).."th-ptic equation not support.") end
	local real_id = 1
	if #sol > 0 then for i=1,#sol do 
		local re_scale = cmath.re(cmath.abs(cmath.re(sol[i])))
		local im_scale = cmath.re(cmath.abs(cmath.im(sol[i])))
		if re_scale < 1e-14 and im_scale < 1e-14 then 
			real_id = i 
			if re_scale > 0 or im_scale > 0 then sol[i] = 0 end
		elseif im_scale < 1e-14 then 
			real_id = i 
			if im_scale > 0 then sol[i] = cmath.re(sol[i]) end
		elseif re_scale < 1e-14 then 
			if re_scale > 0 then sol[i] = toCnumber(tostring(cmath.im(sol[i]))+"i") end
		end 
	end end
	local result = {}
	local j = real_id
	for i=1,#sol do
		result[#result+1] = sol[((real_id-1)+(i-1))%(#sol)+1]
	end
	return result
end
function p._cubicRootItem(a,b,c,d,it)
	load_comp_lib()
	local alpha = (-b*b*b/(27*a*a*a)-d/(2*a)+(b*c)/(6*a*a))
	local beta = (c/(3*a))-(b*b)/(9*a*a)
	local st = {2*cmath.pi, cmath.zero, -2*cmath.pi}
	local s = st[tonumber(tostring(it))or 1]
	return -b/(3*a)+2*cmath.sqrt(-beta)*cmath.cos((cmath.acos(alpha/cmath.pow(-beta,3/2))+s)/3)
end
function p._cubicRoot(a,b,c,d)
	load_comp_lib()
	return {
		p._cubicRootItem(a,b,c,d,1),
		p._cubicRootItem(a,b,c,d,2),
		p._cubicRootItem(a,b,c,d,3),
	}
end
function p._quarticRootItem(a,b,c,d,e,it)
	load_comp_lib()
	local st = {{-1,-1},{-1,1},{1,-1},{1,1}}
	local s, t = unpack(st[tonumber(tostring(it))or 1]or{1,1})
	local alpha = -3*b*b/(8*a*a)+c/a
	local beta = b*b*b/(8*a*a*a)-b*c/(2*a*a)+d/a
	local gamma = -3*b*b*b*b/(256*a*a*a*a)+b*b*c/(16*a*a*a)-b*d/(4*a*a)+e/a
	if (beta == 0) or (toCnumber(beta)==cmath.zero) then return -b/(4*a)+s*cmath.sqrt((-alpha+t*cmath.sqrt(alpha*alpha-4*gamma))/2)end
	local one_3th = cmath.one / 3.0
	local P = -alpha*alpha/12-gamma
	local Q = -alpha*alpha*alpha/108+alpha*gamma/3-beta*beta/8
	local R = -Q/2+cmath.sqrt(Q*Q/4+P*P*P/27)
	local U = cmath.pow(R,one_3th)
	local y = -(5/6)*alpha + (((U==0) or (toCnumber(U)==cmath.zero))and(-cmath.pow(Q,one_3th))or(U-P/(3*U)))
	local W = cmath.sqrt(alpha+2*y)
	return -b/(4*a)+(s*W+t*cmath.sqrt(-(3*alpha+2*y+s*((2*beta)/W))))/2
end
function p._quarticRoot(a,b,c,d,e)
	load_comp_lib()
	return {
		p._quarticRootItem(a,b,c,d,e,1),
		p._quarticRootItem(a,b,c,d,e,2),
		p._quarticRootItem(a,b,c,d,e,3),
		p._quarticRootItem(a,b,c,d,e,4),
	}
end
--[[
p._quarticEigenRoot({{1, 2, 4, 3}, {5, 7, 6, 8}, {10, 9, 12, 11}, {13, 16, 14, 15}})
p._quarticEigenData({{1, 2, 4, 3}, {5, 7, 6, 8}, {10, 9, 12, 11}, {13, 16, 14, 15}})
{35.4422, 2.72101, -2.05098, -1.11227}
{{0.199913, 0.471587, 0.73557, 1.}, {-0.665669, 1.20938, -1.64109, 1.}, 
{-0.79522, -0.522759, 0.117929, 1.}, {0.230581, -0.767239, -0.488143, 1.}}
]]
function p._quarticEigenRoot(a)
	local e4=1
	local e3=-a[1][1] - a[2][2] - a[3][3] - a[4][4]
	local e2=-a[1][2]*a[2][1] + a[1][1]*a[2][2] - a[1][3]*a[3][1] - a[2][3]*a[3][2] + a[1][1]*a[3][3] + a[2][2]*a[3][3] - a[1][4]*a[4][1] - a[2][4]*a[4][2] - a[3][4]*a[4][3] + a[1][1]*a[4][4] + a[2][2]*a[4][4] + a[3][3]*a[4][4]
	local e1=a[1][3]*a[2][2]*a[3][1] - a[1][2]*a[2][3]*a[3][1] - a[1][3]*a[2][1]*a[3][2] + a[1][1]*a[2][3]*a[3][2] + a[1][2]*a[2][1]*a[3][3] - a[1][1]*a[2][2]*a[3][3] + a[1][4]*a[2][2]*a[4][1] - a[1][2]*a[2][4]*a[4][1] + a[1][4]*a[3][3]*a[4][1] - 
		a[1][3]*a[3][4]*a[4][1] - a[1][4]*a[2][1]*a[4][2] + a[1][1]*a[2][4]*a[4][2] + a[2][4]*a[3][3]*a[4][2] - a[2][3]*a[3][4]*a[4][2] - a[1][4]*a[3][1]*a[4][3] - a[2][4]*a[3][2]*a[4][3] + a[1][1]*a[3][4]*a[4][3] + a[2][2]*a[3][4]*a[4][3] + 
		a[1][2]*a[2][1]*a[4][4] - a[1][1]*a[2][2]*a[4][4] + a[1][3]*a[3][1]*a[4][4] + a[2][3]*a[3][2]*a[4][4] - a[1][1]*a[3][3]*a[4][4] - a[2][2]*a[3][3]*a[4][4]
	local e0=a[1][4]*a[2][3]*a[3][2]*a[4][1] - a[1][3]*a[2][4]*a[3][2]*a[4][1] - a[1][4]*a[2][2]*a[3][3]*a[4][1] + a[1][2]*a[2][4]*a[3][3]*a[4][1] + a[1][3]*a[2][2]*a[3][4]*a[4][1] - a[1][2]*a[2][3]*a[3][4]*a[4][1] - a[1][4]*a[2][3]*a[3][1]*a[4][2] + 
		a[1][3]*a[2][4]*a[3][1]*a[4][2] + a[1][4]*a[2][1]*a[3][3]*a[4][2] - a[1][1]*a[2][4]*a[3][3]*a[4][2] - a[1][3]*a[2][1]*a[3][4]*a[4][2] + a[1][1]*a[2][3]*a[3][4]*a[4][2] + a[1][4]*a[2][2]*a[3][1]*a[4][3] - a[1][2]*a[2][4]*a[3][1]*a[4][3] - 
		a[1][4]*a[2][1]*a[3][2]*a[4][3] + a[1][1]*a[2][4]*a[3][2]*a[4][3] + a[1][2]*a[2][1]*a[3][4]*a[4][3] - a[1][1]*a[2][2]*a[3][4]*a[4][3] - a[1][3]*a[2][2]*a[3][1]*a[4][4] + a[1][2]*a[2][3]*a[3][1]*a[4][4] + a[1][3]*a[2][1]*a[3][2]*a[4][4] - 
		a[1][1]*a[2][3]*a[3][2]*a[4][4] - a[1][2]*a[2][1]*a[3][3]*a[4][4] + a[1][1]*a[2][2]*a[3][3]*a[4][4]
	return p._quarticRoot(e4,e3,e2,e1,e0)
end

function p._quarticEigenData(a)
	local qbRoot = p._quarticEigenRoot(a)
	local at01 = a[2][3]*a[3][2]*a[4][1] - a[2][2]*a[3][3]*a[4][1] - a[2][3]*a[3][1]*a[4][2] + a[2][1]*a[3][3]*a[4][2] + a[2][2]*a[3][1]*a[4][3] - a[2][1]*a[3][2]*a[4][3]
	local at02 = a[2][4]*a[3][2]*a[4][1] - a[2][2]*a[3][4]*a[4][1] - a[2][4]*a[3][1]*a[4][2] + a[2][1]*a[3][4]*a[4][2] + a[2][2]*a[3][1]*a[4][4] - a[2][1]*a[3][2]*a[4][4]
	local at03 = -a[2][4]*a[3][3]*a[4][1] + a[2][3]*a[3][4]*a[4][1] + a[2][4]*a[3][1]*a[4][3] - a[2][1]*a[3][4]*a[4][3] - a[2][3]*a[3][1]*a[4][4] + a[2][1]*a[3][3]*a[4][4]
	local at04 = -a[3][3]*a[4][2] + a[3][2]*a[4][3]
	local at05 = -a[3][4]*a[4][2] + a[3][2]*a[4][4]
	return {{-(1/(a[3][2]*a[4][1] - a[3][1]*a[4][2]))*(at05 - a[3][2]*qbRoot[1]) + ((at04 + a[4][2]*qbRoot[1])*(at02 - a[2][2]*a[3][1]*qbRoot[1] + a[2][1]*a[3][2]*qbRoot[1] + a[3][4]*a[4][1]*qbRoot[1] - a[3][1]*a[4][4]*qbRoot[1] + 
		a[3][1]*(qbRoot[1]*qbRoot[1])))/((a[3][2]*a[4][1] - a[3][1]*a[4][2])*(at01 + a[2][2]*a[4][1]*qbRoot[1] + a[3][3]*a[4][1]*qbRoot[1] - a[2][1]*a[4][2]*qbRoot[1] - a[3][1]*a[4][3]*qbRoot[1] - 
		a[4][1]*(qbRoot[1]*qbRoot[1]))), -((at03 + a[2][3]*a[3][1]*qbRoot[1] - a[2][1]*a[3][3]*qbRoot[1] + a[2][4]*a[4][1]*qbRoot[1] - a[2][1]*a[4][4]*qbRoot[1] + a[2][1]*(qbRoot[1]*qbRoot[1]))/(at01 + a[2][2]*a[4][1]*qbRoot[1] + 
		a[3][3]*a[4][1]*qbRoot[1] - a[2][1]*a[4][2]*qbRoot[1] - a[3][1]*a[4][3]*qbRoot[1] - a[4][1]*(qbRoot[1]*qbRoot[1]))), -((at02 - a[2][2]*a[3][1]*qbRoot[1] + a[2][1]*a[3][2]*qbRoot[1] + a[3][4]*a[4][1]*qbRoot[1] - 
		a[3][1]*a[4][4]*qbRoot[1] + a[3][1]*(qbRoot[1]*qbRoot[1]))/(at01 + a[2][2]*a[4][1]*qbRoot[1] + a[3][3]*a[4][1]*qbRoot[1] - a[2][1]*a[4][2]*qbRoot[1] - a[3][1]*a[4][3]*qbRoot[1] - a[4][1]*(qbRoot[1]*qbRoot[1]))), 1}, {-(1/( 
		a[3][2]*a[4][1] - a[3][1]*a[4][2]))*(at05 - a[3][2]*qbRoot[2]) + ((at04 + a[4][2]*qbRoot[2])*(at02 - a[2][2]*a[3][1]*qbRoot[2] + a[2][1]*a[3][2]*qbRoot[2] + a[3][4]*a[4][1]*qbRoot[2] - a[3][1]*a[4][4]*qbRoot[2] + 
		a[3][1]*(qbRoot[2]*qbRoot[2])))/((a[3][2]*a[4][1] - a[3][1]*a[4][2])* (at01 + a[2][2]*a[4][1]*qbRoot[2] + a[3][3]*a[4][1]*qbRoot[2] - a[2][1]*a[4][2]*qbRoot[2] - a[3][1]*a[4][3]*qbRoot[2] - 
		a[4][1]*(qbRoot[2]*qbRoot[2]))), -((at03 + a[2][3]*a[3][1]*qbRoot[2] - a[2][1]*a[3][3]*qbRoot[2] + a[2][4]*a[4][1]*qbRoot[2] - a[2][1]*a[4][4]*qbRoot[2] + a[2][1]*(qbRoot[2]*qbRoot[2]))/(at01 + a[2][2]*a[4][1]*qbRoot[2] + 
		a[3][3]*a[4][1]*qbRoot[2] - a[2][1]*a[4][2]*qbRoot[2] - a[3][1]*a[4][3]*qbRoot[2] - a[4][1]*(qbRoot[2]*qbRoot[2]))), -((at02 - a[2][2]*a[3][1]*qbRoot[2] + a[2][1]*a[3][2]*qbRoot[2] + a[3][4]*a[4][1]*qbRoot[2] - 
		a[3][1]*a[4][4]*qbRoot[2] + a[3][1]*(qbRoot[2]*qbRoot[2]))/(at01 + a[2][2]*a[4][1]*qbRoot[2] + a[3][3]*a[4][1]*qbRoot[2] - a[2][1]*a[4][2]*qbRoot[2] - a[3][1]*a[4][3]*qbRoot[2] - a[4][1]*(qbRoot[2]*qbRoot[2]))), 1}, {-(1/( 
		a[3][2]*a[4][1] - a[3][1]*a[4][2]))*(at05 - a[3][2]*qbRoot[3]) + ((at04 + a[4][2]*qbRoot[3])*(at02 - a[2][2]*a[3][1]*qbRoot[3] + a[2][1]*a[3][2]*qbRoot[3] + a[3][4]*a[4][1]*qbRoot[3] - a[3][1]*a[4][4]*qbRoot[3] + 
		a[3][1]*(qbRoot[3]*qbRoot[3])))/((a[3][2]*a[4][1] - a[3][1]*a[4][2])*(at01 + a[2][2]*a[4][1]*qbRoot[3] + a[3][3]*a[4][1]*qbRoot[3] - a[2][1]*a[4][2]*qbRoot[3] - a[3][1]*a[4][3]*qbRoot[3] - a[4][1]*(qbRoot[3]*qbRoot[3]))), -((at03 + 
		a[2][3]*a[3][1]*qbRoot[3] - a[2][1]*a[3][3]*qbRoot[3] + a[2][4]*a[4][1]*qbRoot[3] - a[2][1]*a[4][4]*qbRoot[3] + a[2][1]*(qbRoot[3]*qbRoot[3]))/(at01 + a[2][2]*a[4][1]*qbRoot[3] + a[3][3]*a[4][1]*qbRoot[3] - 
		a[2][1]*a[4][2]*qbRoot[3] - a[3][1]*a[4][3]*qbRoot[3] - a[4][1]*(qbRoot[3]*qbRoot[3]))), -((at02 - a[2][2]*a[3][1]*qbRoot[3] + a[2][1]*a[3][2]*qbRoot[3] + a[3][4]*a[4][1]*qbRoot[3] - a[3][1]*a[4][4]*qbRoot[3] + 
		a[3][1]*(qbRoot[3]*qbRoot[3]))/(at01 + a[2][2]*a[4][1]*qbRoot[3] + a[3][3]*a[4][1]*qbRoot[3] - a[2][1]*a[4][2]*qbRoot[3] - a[3][1]*a[4][3]*qbRoot[3] - a[4][1]*(qbRoot[3]*qbRoot[3]))), 1}, {-(1/( a[3][2]*a[4][1] - 
		a[3][1]*a[4][2]))*(at05 - a[3][2]*qbRoot[4]) + ((at04 + a[4][2]*qbRoot[4])*(at02 - a[2][2]*a[3][1]*qbRoot[4] + a[2][1]*a[3][2]*qbRoot[4] + a[3][4]*a[4][1]*qbRoot[4] - a[3][1]*a[4][4]*qbRoot[4] + a[3][1]*(qbRoot[4]*qbRoot[4])))/((
		a[3][2]*a[4][1] - a[3][1]*a[4][2])*(at01 + a[2][2]*a[4][1]* qbRoot[4] + a[3][3]*a[4][1]*qbRoot[4] - a[2][1]*a[4][2]*qbRoot[4] - a[3][1]*a[4][3]*qbRoot[4] - a[4][1]*(qbRoot[4]*qbRoot[4]))), -((at03 + a[2][3]*a[3][1]*qbRoot[4] - 
		a[2][1]*a[3][3]*qbRoot[4] + a[2][4]*a[4][1]*qbRoot[4] - a[2][1]*a[4][4]*qbRoot[4] + a[2][1]*(qbRoot[4]*qbRoot[4]))/(at01 + a[2][2]*a[4][1]*qbRoot[4] + a[3][3]*a[4][1]*qbRoot[4] - a[2][1]*a[4][2]*qbRoot[4] - a[3][1]*a[4][3]*qbRoot[4] - 
		a[4][1]*(qbRoot[4]*qbRoot[4]))), -((at02 - a[2][2]*a[3][1]*qbRoot[4] + a[2][1]*a[3][2]*qbRoot[4] + a[3][4]*a[4][1]*qbRoot[4] - a[3][1]*a[4][4]*qbRoot[4] + a[3][1]*(qbRoot[4]*qbRoot[4]))/(at01 + 
		a[2][2]*a[4][1]*qbRoot[4] + a[3][3]*a[4][1]*qbRoot[4] - a[2][1]*a[4][2]*qbRoot[4] - a[3][1]*a[4][3]*qbRoot[4] - a[4][1]*(qbRoot[4]*qbRoot[4]))), 1}}
end

function p.getNumber(frame) 
    local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        load_getArgs()
        args = getArgs(frame, {parentFirst=true}) --frame.args
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
	local input_text = args[1] or args["1"]
	
	local got_num = tonumber(input_text)
	if got_num == nil then
		load_comp_lib()
		got_num = toCnumber(input_text)
	else
		if p._isNaN(got_num) then got_num=tonumber("nan") end
	end

	if got_num == nil then
		load_comp_lib()
		local qmath = comp_lib.qmath.init()
		local toQnumber = qmath.constructor
		got_num = toQnumber(input_text)
	else
		if p._isNaN(tonumber(tostring(got_num))or 1) then got_num=tonumber("nan") end
	end
	return got_num
end

function p.numberType(frame) 
    local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        load_getArgs()
        args = getArgs(frame, {parentFirst=true}) --frame.args
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame} end
    end
	local input_text = args[1] or args["1"]
	
	local got_num = p.getNumber(args)
	return p._numberType(got_num)
end

function p.trunc(frame,_n) 
    local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        load_getArgs()
        args = getArgs(frame, {parentFirst=true}) --frame.args
        working_frame = frame
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame,_n or 0} end
    end
	local x = tonumber(args[1] or args["1"])or 0
	local n = tonumber(args[2] or args["2"])or 0
	return p._trunc(x,n)
end

function p.random(frame,_b) 
    local args, working_frame
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        load_getArgs()
        args = getArgs(frame, {parentFirst=true}) --frame.args
        working_frame = frame
        math.randomseed(math.floor(os.time() * os.clock()))
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame,_b} end
    end
	local str_a = args[1] or args["1"]or ""
	local str_b = args[2] or args["2"]or ""
	local a = (mw.text.trim(str_a)~="")and tonumber(str_a) or nil
	local b = (mw.text.trim(str_b)~="")and tonumber(str_b) or nil
	return p._random(a,b)
end

function p.get4x4matrix(frame, lua_call)
    local args
    local is_invoke = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        load_getArgs()
        args = getArgs(frame, {parentFirst=true}) --frame.args
        is_invoke = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        if type(args) ~= type({}) then args = {frame} end
    end
    load_matrix_lib()
    local input_text = args[1] or args["1"] or 'nan'
    local input_matrix = mmath.toMatrix(input_text)
    if not (p.numberType(input_text):lower()=="nan") then return args, is_invoke end
    local matrix = {}
    for i=1,4 do
    	local rowdata = {}
    	for j=1,4 do
    		rowdata[#rowdata + 1]=(input_matrix[i]or{})[j] or 0
    	end
    	matrix[#matrix + 1] = mmath.row(unpack(rowdata))
    end
    matrix = mmath.matrix(unpack(matrix)) 
    if lua_call then return args, is_invoke, matrix
    else return matrix end
end

function p.matrix4x4EigenRoot(frame)
	local args, is_invoke, matrix = p.get4x4matrix(frame, true)
	if not matrix then return '' end
	local result = p._quarticEigenRoot(matrix)
	local root = tonumber(args.root)
	if root and result[root] then return result[root] end
	local comma = args.comma or ','
	if comma == '' then comma = ','end
    if is_invoke then
    	local body = ''
    	for i=1,#result do
    		if body~=''then body=body..comma end
    		body=body..tostring(result[i])
    	end
    	return body
    end
	return result
end

function p.matrix4x4EigenVector(frame)
	local args, is_invoke, matrix = p.get4x4matrix(frame, true)
	if not matrix then return '' end
	local result = p._quarticEigenData(matrix)
	local root = tonumber(args.root)
	local comma = args.comma or ','
	if comma == '' then comma = ','end
	if root and result[root] then 
		local output_result = result[root]
	    if is_invoke then
	    	local output_body = ''
	    	for i=1,#output_result do
	    		if output_body~=''then output_body=output_body..comma end
	    		output_body=output_body..tostring(output_result[i])
	    	end
	    	return output_body
	    end
		return output_result
	end
	local comma2 = args.comma2 or ';'
	if comma2 == '' then comma2 = ';'end
    if is_invoke then
    	local body = ''
    	for i=1,#result do
    		if body~=''then body=body..comma2 end
	    	local output_body = ''
	    	local output_result = result[i]
	    	for j=1,#output_result do
	    		if output_body~=''then output_body=output_body..comma end
	    		output_body=output_body..tostring(output_result[j])
	    	end
    		body=body..output_body
    	end
    	return body
    end
	return result
end

function p.solveEQ(frame,...) 
    local args, working_frame
    local is_invoke = false
    if frame == mw.getCurrentFrame() then
        -- We're being called via #invoke. The args are passed through to the module
        -- from the template page, so use the args that were passed into the template.
        load_getArgs()
        args = getArgs(frame, {parentFirst=true}) --frame.args
        working_frame = frame
        is_invoke = true
    else
        -- We're being called from another module or from the debug console, so assume
        -- the args are passed in directly.
        args = frame
        working_frame = mw.getCurrentFrame()
        if type(args) ~= type({}) then args = {frame,...} end
    end
    load_matrix_lib()
    local max_id = -1 for var_id,_ in pairs(args) do local load_id = tonumber(var_id)or-1 if load_id and load_id > max_id then max_id=load_id end end
    if max_id <= 0 then return is_invoke and""or{} end
    local input_list = {}
    for i=1,max_id do
    	local got_num = p.getNumber(args[i])
    	if p._isNaN(tonumber(tostring(got_num))or 1) then got_num = 0 end
    	if got_num==nil then got_num = 0 end
    	input_list[i] = got_num
    end
	local ret = p._solveEQ(unpack(input_list))
	local root = tonumber(args.root)
	local comma = args.comma or ','
	if comma == '' then comma = ','end
	if root and ret[root] then return ret[root] end
    if is_invoke then
    	local body = ''
    	for i=1,#ret do
    		if body~=''then body=body..comma end
    		body=body..tostring(ret[i])
    	end
    	return body
    end
	return ret
end

return p