Module:Complex Number/Solver

From wiki
Revision as of 12:17, 23 April 2025 by Root (talk | contribs) (1 revision imported)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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