local p = {}
local getArgs = require('Module:Arguments').getArgs
local ext_mathlib = require("Module:Complex Number/Functions")._init
local use_other_module = false
local TrackingCategory = require('Module:TrackingCategory')
local Operators = require('Module:Complex_Number/Calculate/Operators')
local strip_marker_temp, strip_marker_temp_len = {}, 0
local function numberToAZ(num)
local body = ''
local s = tostring(math.floor(tonumber(num)))
for i = 1, mw.ustring.len(s) do
body = body .. mw.ustring.char(tonumber(mw.ustring.sub(s, i, i)) + 65)
end
return body
end
local function _remove_strip_marker(str)return mw.text.decode(mw.text.unstrip(str)) end
local function _load_strip_marker(str)return mw.ustring.gsub(mw.text.decode(mw.text.unstripNoWiki(str)),"\127'\"`UNIQ.-QINU`\"'\127",function(strip)
strip_marker_temp_len = strip_marker_temp_len + 1
local idx_az = numberToAZ(strip_marker_temp_len)
strip_marker_temp[idx_az] = strip
return ' UNQ' .. idx_az .. ' '
end)end
local function _subst_strip(str)
local UNIQ mw.ustring.gsub(str, "UNQ(%a+)$", function(num) UNIQ = UNIQ or num end)
return strip_marker_temp[UNIQ or -1] or str
end
local function _subst_error_strip(str)
local UNIQ mw.ustring.gsub(str, "UNQ(%a+)$", function(num) UNIQ = UNIQ or num end)
return mw.ustring.gsub(strip_marker_temp[UNIQ or -1] or str, "\127'\"`UNIQ%-%-(%a+).-QINU`\"'\127", "<%1></%1>")
end
local function _function_preprocessing(input_str,math_lib, number_Constructer, debug_flag, jsut_load)
local input_fo, ftable = Operators.function_preload(input_str,{},math_lib, number_Constructer, debug_flag, p.nocalc, jsut_load)
if type(ftable)~=type({"table"})then return input_fo, {} end
local final_scope=Operators.fill_function(ftable,{})
final_scope=Operators.fill_scope(final_scope, math_lib, number_Constructer, debug_flag, p.calc_by_postfix)
return input_fo, final_scope
end
local function _adj_math_output(unmathstr)
return mw.ustring.gsub(unmathstr,"ω","\\omega ")
:gsub("([%+%-]?)(%d*%.?%d+)e([%+%-]?%d+)","%1%2^{%3}")
end
function p.calc_table(frame)
local variable_process = require("Module:Number/data")
local args
local can_math = false
local should_math = 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.
args = getArgs(frame, {
parentFirst=true,
trim = false,
removeBlanks = false
}) --frame.args
local yesno = require('Module:Yesno')
can_math = yesno(args['use math'] or args['use_math'])
should_math = yesno(args['should math'] or args['should_math'])
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local yesno = require('Module:Yesno')
if yesno(args.useOtherModule or 'no') == true then use_other_module = true end
local first_number_list = {"2","3","4","5","6","7","8","9"}
local second_number_list
local calculate_str, calculate_title = "{{{left}}} * {{{right}}}", "×"
if args['number list'] or args['number_list'] then first_number_list = mw.text.split(args['number list'] or args['number_list'] or '',',') end
if args['number list2'] or args['number_list2'] then second_number_list = mw.text.split(args['number list2'] or args['number_list2'] or '',',') end
if args['calculate'] then calculate_str = mw.text.trim(_remove_strip_marker(args['calculate'])) end
if args['calculate title'] or args['calculate_title'] then calculate_title = mw.text.trim(args['calculate title'] or args['calculate_title']) end
if second_number_list == nil or (second_number_list and (second_number_list == {} or #second_number_list == 0) ) then
second_number_list = first_number_list
end
local body, buffer_str, table_str = "", '', ''
if comp_number == nil then comp_number = require("Module:Complex Number") end
local cmath, qmath, bmath = comp_number.cmath.init(), comp_number.qmath.init(), comp_number.bmath.init()
local mathtag = p.tagmath.init()
body = body .. "! " .. (args["main head css"] or args["main_head_css"] or '') .. " | " .. calculate_title .. ' \n'
for j=1,#second_number_list do
local second_it = mw.text.trim(second_number_list[j] or '')
if second_it ~= nil then
local second_num_math = second_it
if should_math or can_math then second_num_math = _adj_math_output(second_num_math) end
if can_math then second_num_math = frame:callParserFunction{name = "#tag:math", args = {second_num_math}} end
body = body .. "! " .. (args["head css"] or args["head_css"] or '') .. " | " .. second_num_math .. ' \n'
end
end
body = body .. '\n'
for i=1,#first_number_list do
local first_it = mw.text.trim(first_number_list[i] or '')
if first_it ~= nil then
body = body .. "|-\n"; table_str = ''
local first_num_math = tostring(first_it)
if should_math or can_math then first_num_math = _adj_math_output(first_num_math) end
if can_math then first_num_math = frame:callParserFunction{name = "#tag:math", args = {first_num_math}} end
body = body .. "! " .. (args["head css"] or args["head_css"] or '') .. " | " .. first_num_math .. " \n"
for j=1,#second_number_list do
local second_it = mw.text.trim(second_number_list[j] or '')
if second_it ~= nil then
buffer_str = variable_process._getFormatingStringByArgument(calculate_str, {
left=tostring(first_it),right=tostring(second_it)
})
local exec_result = p.calc( buffer_str or '', ( {
cmath = cmath,
qmath = qmath,
bmath = bmath,
mathtag = mathtag,
} ) [ args['class'] ] , (( {
cmath = cmath.toComplexNumber,
qmath = qmath.toQuaternionNumber,
bmath = bmath.toBoolean,
mathtag = mathtag.toTagMath,
} ) [ args['class'] ] ) )
local exec_result_str = mw.text.trim(tostring(exec_result) or '')
local exec_check = mw.text.trim((tonumber(exec_result_str) and args[tonumber(exec_result_str)]) or args[exec_result_str] or '')
if exec_check == '' then exec_check = nil end
table_str = table_str .. '|' .. (exec_check or args["number css"] or args["number_css"] or '') .. "| "
if should_math or can_math then exec_result_str = _adj_math_output(exec_result_str) end
if can_math then exec_result_str = frame:callParserFunction{name = "#tag:math", args = {exec_result_str}} end
table_str = table_str .. mw.text.trim(exec_result_str) .. ' \n'
end
end
body = body .. table_str
end
end
if use_ext_mathlib == true then TrackingCategory.append('使用擴充複變函數庫的頁面') end
return body
end
function p.calculate(frame)
local args
local can_math = false
local should_math = 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.
args = getArgs(frame) --frame.args
local yesno = require('Module:Yesno')
can_math = yesno(args['use math'] or args['use_math'])
should_math = yesno(args['should math'] or args['should_math'])
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local yesno = require('Module:Yesno')
if yesno(args.useOtherModule or 'no') == true then use_other_module = true end
if comp_number == nil then comp_number = require("Module:Complex Number") end
local cmath, qmath, bmath = comp_number.cmath.init(), comp_number.qmath.init(), comp_number.bmath.init()
local mathtag = p.tagmath.init()
local body = p.calc( _load_strip_marker(args[1] or args['1'] or ''), ( {
cmath = cmath,
qmath = qmath,
bmath = bmath,
mathtag = mathtag,
} ) [ args['class'] ] , (( {
cmath = cmath.toComplexNumber,
qmath = qmath.toQuaternionNumber,
bmath = bmath.toBoolean,
mathtag = mathtag.toTagMath,
} ) [ args['class'] ] ) )
if should_math or can_math then body = _adj_math_output(tostring(body)) end
if can_math then body = frame:callParserFunction{name = "#tag:math", args = {tostring(body)}} end
return body
end
function p.functionGraph(frame)
if comp_number == nil then comp_number = require("Module:Complex Number") end
local cmath, qmath = comp_number.cmath.init(), comp_number.qmath.init()
if not getArgs then getArgs = require('Module:Arguments').getArgs end
local args = getArgs(frame, {parentFirst=true})
local exprs = {}
local body_args, x_start, x_end, y_min, y_max, sampling = {}, 0, 1, nil, nil, 50
for arg_name, arg_value in pairs( args ) do
if tonumber(arg_name) ~= nil then exprs[#exprs + 1] = _remove_strip_marker(arg_value)
elseif mw.ustring.lower(arg_name) == "start" then x_start = tonumber(arg_value)
elseif mw.ustring.lower(arg_name) == "end" then x_end = tonumber(arg_value)
elseif mw.ustring.lower(arg_name) == "sampling" then sampling = tonumber(arg_value)
elseif mw.ustring.lower(arg_name) == "min" then y_min = tonumber(arg_value)
elseif mw.ustring.lower(arg_name) == "max" then y_max = tonumber(arg_value)
else body_args[arg_name] = arg_value
end
end
local yesno = require('Module:Yesno')
if yesno(args.useOtherModule or 'no') == true then use_other_module = true end
local body = p._functionGraph(exprs,
x_start, x_end, sampling, y_min, y_max, body_args, ( {
cmath = cmath,
qmath = qmath,
} ) [ frame.args['class'] ] , (( {
cmath = cmath.toComplexNumber,
qmath = qmath.toQuaternionNumber,
} ) [ frame.args['class'] ] ) )
body.width = 400
body.height = 100; body.type="line"
body.interpolate = frame.args['interpolate'] or "monotone"
for arg_name, arg_value in pairs( body_args ) do
body[arg_name] = arg_value
end
body = mw.getCurrentFrame():expandTemplate{title = "Graph:Chart", args = body}
if use_ext_mathlib == true then TrackingCategory.append('使用擴充複變函數庫的頁面') end
return body
end
function p.toPostfix(frame)--單純印出字串,不運算
local args
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.
args = getArgs(frame, {
trim = false,
removeBlanks = false
}) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local format = mw.text.decode(args.format or"{{{1}}} ");
format = mw.ustring.gsub(format, "%{%{%{.-%}%}%}", "%%s" );
local it = mw.ustring.find(format, "%%s", 1)
format = mw.ustring.gsub(format, "\\n", "\n")
local expr_geter = _function_preprocessing(_load_strip_marker(args[1] or args['1'] or ''),{}, nil, nil, true)
local result, body = p.infixToPostfix( expr_geter ), ''
for i, result_str in pairs( result ) do
if mw.text.trim(result_str.name) ~= '|' and result_str.propetry ~= "func start" then
body = body .. mw.ustring.gsub(format, "%%s", _subst_strip(mw.text.trim(tostring(result_str.name))))
end
end
return body
end
function p.toPrefix(frame)--單純印出字串,不運算
local args
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.
args = getArgs(frame, {
trim = false,
removeBlanks = false
}) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local format = mw.text.decode(args.format or"{{{1}}} ");
format = mw.ustring.gsub(format, "%{%{%{.-%}%}%}", "%%s" );
local it = mw.ustring.find(format, "%%s", 1)
format = mw.ustring.gsub(format, "\\n", "\n")
local expr_geter = _function_preprocessing(_load_strip_marker(args[1] or args['1'] or ''),{}, nil, nil, true)
local postfix, body = p.infixToPostfix( expr_geter ), ''
local pre_stack = {}
local cmt_str = ""
local cmt_count = 0
local function _item_tostring(item)return _subst_strip((type(item)==type({"table"}))and(item.name or tostring(item))or tostring(item))end
local function tail_process()
if cmt_str ~= "" then
local oper_out_format = (cmt_count==2) and "%s , %s" or ((cmt_count==1) and "%s %s" or "%s (, %s)")
pre_stack[#pre_stack<=0 and 1 or #pre_stack] = mw.ustring.format(oper_out_format,
_item_tostring(pre_stack[#pre_stack]and(pre_stack[#pre_stack]..' ')or''),
_item_tostring(cmt_str)
)
cmt_str = ""
else
local new_top = ''
for i=1,#pre_stack do
if new_top ~= '' then new_top = new_top .. ' ' end
new_top = new_top .. _item_tostring(pre_stack[i])
end
for i=#pre_stack,1,-1 do pre_stack[i] = nil end
pre_stack[1] = new_top
end
end
for i = 1,#postfix do
local it = postfix[i]
local opdata = (it.propetry == "operator") and p.symbol_table[it.name] or {count=0}
if it.name == "," then
--case 逗號
if cmt_str == "" then
if #pre_stack >= 2 then
cmt_str = mw.ustring.format("%s %s",
_item_tostring(pre_stack[#pre_stack-1]),
_item_tostring(pre_stack[#pre_stack]))
cmt_count = 2
pre_stack[#pre_stack] = nil
else
cmt_str = _item_tostring(pre_stack[#pre_stack]or ' ')
cmt_count = mw.test.trim(cmt_str)=='' and 0 or 1
end
else
local new_cmt = (pre_stack[#pre_stack]and(' '.._item_tostring(pre_stack[#pre_stack])))or ''
cmt_str = cmt_str .. new_cmt
cmt_count = cmt_count + (mw.text.trim(new_cmt)=='' and 0 or 1)
end
pre_stack[#pre_stack] = nil
elseif it.propetry == "func start" then
pre_stack[#pre_stack+1] = "$function_start\127"
elseif it.propetry == "func" then
local par_count = 0
local find_func_head = #pre_stack while not mw.ustring.find(_item_tostring(pre_stack[find_func_head]),"%$function_start\127") do
if find_func_head < 1 then par_count = 0 break end
par_count = par_count + 1
find_func_head = find_func_head - 1
end
local par_data = _item_tostring(pre_stack[find_func_head]or'$function_start\127')
find_func_head = find_func_head <= 0 and #pre_stack or find_func_head
local mark_start, mark_end = mw.ustring.find(par_data,"%$function_start\127")
par_data = mw.text.split(mark_start and par_data or "$function_start\127","%$function_start\127")
local tail_data = ''
if cmt_str ~= "" then
tail_data = mw.ustring.format("%s %s",_item_tostring(par_data[2]),_item_tostring(cmt_str))
par_count = par_count + cmt_count
end
local par_it = find_func_head+1 while par_it <= #pre_stack do
tail_data = mw.ustring.format("%s %s",tail_data,_item_tostring(pre_stack[par_it]))
par_it = par_it + 1
end
tail_data = mw.ustring.format((par_count==2) and "%s %s" or "(%s %s)",_item_tostring(it),tail_data)
local head_data = mw.text.trim(par_data[1])
pre_stack[find_func_head] = (head_data=='' and '' or head_data..' ')..tail_data
par_it = find_func_head+1 while par_it <= #pre_stack do pre_stack[par_it]=nil end
cmt_str = ""
cmt_count=0
elseif opdata.count == 1 then
if opdata.count == 1 or cmt_str == "" then
pre_stack[#pre_stack] = mw.ustring.format("(%s %s)",
_item_tostring(it),_item_tostring(pre_stack[#pre_stack])
)
else
local oper_out_format = (cmt_count==2) and "%s %s" or "(%s %s)"
pre_stack[(#pre_stack<=0 and 0 or #pre_stack) + 1] = mw.ustring.format(oper_out_format,
_item_tostring(it),_item_tostring(cmt_str)
)
end
cmt_str = ""
cmt_count=0
elseif opdata.count == 2 then
--case 2元運算子
if #pre_stack == 1 and cmt_str ~= "" then
local oper_out_format = (cmt_count==2) and "%s %s , %s" or ((cmt_count==1) and "%s %s %s" or "%s %s (, %s)")
pre_stack[#pre_stack] = mw.ustring.format(oper_out_format,
_item_tostring(it),
_item_tostring(pre_stack[#pre_stack]),
_item_tostring(cmt_str)
)
cmt_str = ""
cmt_count=0
else
pre_stack[#pre_stack-1] = mw.ustring.format("%s %s %s",
_item_tostring(it),
_item_tostring(pre_stack[#pre_stack-1]),
_item_tostring(pre_stack[#pre_stack])
)
pre_stack[#pre_stack] = nil
end
elseif it.propetry == "operator" then
elseif it.name == "$END" then
--case 結尾
tail_process()
else--otherwise
pre_stack[#pre_stack+1] = it
end
end
tail_process()
local result = mw.text.trim(_item_tostring(pre_stack[1]) or _item_tostring(pre_stack[0]))
if mw.ustring.sub(result,1,1) == '(' and mw.ustring.sub(result,-1,-1) == ')' then result = mw.ustring.sub(result,2,-2) end
result = mw.text.split(mw.ustring.gsub(result,'%s+',' '),'%s+')
for i, result_str in pairs( result ) do
if mw.text.trim(result_str) ~= '|' then
body = body .. mw.ustring.gsub(format, "%%s", result_str)
end
end
body = mw.ustring.gsub(body,"⇽","←")
return body
end
function p._functionGraph(expr_arr,x_start,x_end,sampling, y_min, y_max, body_args, math_lib, number_Constructer)
if (yesno or require('Module:Yesno'))((body_args or {}).useOtherModule or 'no') == true then use_other_module = true end
if comp_number == nil then comp_number = require("Module:Complex Number") end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local postfix = {}
local check_func = {}
local x_arr, y_arr = {}, {}
if type(expr_arr) == type({}) then
for i=1,#expr_arr do
local check_parametric = mw.text.split(expr_arr[i],';')
if #check_parametric == 1 then
local pre_expr, pre_scope = _function_preprocessing(expr_arr[i], mathlib, numberConstructer, false)
postfix[#postfix + 1] = p.infixToPostfix(pre_expr, debug_flag)
if pre_scope then postfix[#postfix].scope = pre_scope end
elseif #check_parametric >= 3 then
postfix[#postfix + 1]={parametric=true}
postfix[#postfix].x_name = check_parametric[1] or 't'
postfix[#postfix].y_name = check_parametric[2] or 't'
postfix[#postfix].x = p.infixToPostfix(check_parametric[1] or 't', debug_flag)
postfix[#postfix].y = p.infixToPostfix(check_parametric[2] or 't', debug_flag)
postfix[#postfix].t = check_parametric[3] or 't'
postfix[#postfix].min = numberConstructer(check_parametric[4]) or numberConstructer(0)
postfix[#postfix].max = numberConstructer(check_parametric[5]) or numberConstructer(1)
end
y_arr[#y_arr + 1] = {}
x_arr[#x_arr + 1] = {}
end
else
local check_parametric = mw.text.split(expr_arr,';')
if #check_parametric == 1 then
local pre_expr, pre_scope = _function_preprocessing(expr_arr, mathlib, numberConstructer, false)
postfix[#postfix + 1] = p.infixToPostfix(pre_expr, debug_flag)
if pre_scope then postfix[#postfix].scope = pre_scope end
elseif #check_parametric >= 3 then
postfix[#postfix + 1]={parametric=true}
postfix[#postfix].x_name = check_parametric[1] or 't'
postfix[#postfix].y_name = check_parametric[2] or 't'
postfix[#postfix].x = p.infixToPostfix(check_parametric[1] or 't', debug_flag)
postfix[#postfix].y = p.infixToPostfix(check_parametric[2] or 't', debug_flag)
postfix[#postfix].t = check_parametric[3] or 't'
postfix[#postfix].min = numberConstructer(check_parametric[4]) or numberConstructer(0)
postfix[#postfix].max = numberConstructer(check_parametric[5]) or numberConstructer(1)
end
y_arr[#y_arr + 1] = {}
x_arr[#x_arr + 1] = {}
end
for i=0,sampling do
local it = x_start + (i * (x_end-x_start) / sampling)
local x_val = it
for j=1,#expr_arr do
local calc_val = " "
xpcall(function()
if type(postfix[j]) == type({}) and postfix[j].parametric == true then
local it_t = postfix[j].min + (i * (postfix[j].max - postfix[j].min) / sampling)
--參數式
calc_val = p.calc_by_postfix(postfix[j].y, {[postfix[j].t]=it_t}, mathlib, numberConstructer, false)
x_val = p.calc_by_postfix(postfix[j].x, {[postfix[j].t]=it_t}, mathlib, numberConstructer, false)
else
calc_val = p.calc_by_postfix(postfix[j], {
x=it,
last=function(num) --for Template:數列
local last_num = (body_args or {})['last' .. tonumber(num or 1)] or 0
return numberConstructer(y_arr[j][#(y_arr[j])-(tonumber(num)or 1)+1] or last_num)
end,
}, mathlib, numberConstructer, false)
if( tonumber((body_args or {})["calc diff " .. tostring(j) ]) == 1 )then
local dy = p.calc_by_postfix(postfix[j], {x=(it + 1e-6)}, mathlib, numberConstructer, false)
calc_val = 1e6 * (dy - calc_val)
end
end
if y_max and mathlib.re(calc_val) > y_max then calc_val = y_max end
if y_min and mathlib.re(calc_val) < y_min then calc_val = y_min end
if x_end and mathlib.re(x_val) > x_end then x_val = x_end end
if x_start and mathlib.re(x_val) < x_start then x_val = x_start end
end,function(_)end)
if tonumber((body_args or {})["round number"]) ~= nil then
if calc_val then
calc_val = mathlib.round(calc_val, tonumber((body_args or {})["round number"]), 10)
end
end
if tonumber((body_args or {})["nonreal is nan"]) == 1 then
if math.abs(tonumber(mathlib.abs(mathlib.nonRealPart(calc_val))) or 0) > 1e-14 then calc_val = nil end
end
local num_check = mw.ustring.lower(tostring(numberConstructer(calc_val)))
if mw.ustring.match(num_check,"nan") or mw.ustring.match(num_check,"nil") or mw.ustring.match(num_check,"inf") then calc_val = ' ' end
num_check = mw.ustring.lower(tostring(numberConstructer(x_val)))
if mw.ustring.match(num_check,"nan") or mw.ustring.match(num_check,"nil") or mw.ustring.match(num_check,"inf") then x_val = ' ' end
y_arr[j][ (#(y_arr[j]) + 1) ] = tostring(calc_val)
x_arr[j][ (#(x_arr[j]) + 1) ] = tostring(x_val)
end
end
local result={}
if #expr_arr > 0 then result.legend = "函數" end
for i=1,#expr_arr do
result['x'] = table.concat(x_arr[i],',')
result['y' .. tostring(i)] = table.concat(y_arr[i],',')
result['y' .. tostring(i) .. "Title"] = tostring( (body_args or {})[tostring(i) .. " name" ] or expr_arr[i] )
if type(postfix[i]) == type({}) and postfix[i].parametric == true then
result['y' .. tostring(i) .. "Title"] = "x=" .. postfix[i].x_name .. "; y=" .. postfix[i].y_name
elseif( tonumber((body_args or {})["calc diff " .. tostring(i) ]) == 1 )then
result['y' .. tostring(i) .. "Title"] = '( ' .. result['y' .. tostring(i) .. "Title"] .. " )\'"
end
if check_func[ result['y' .. tostring(i) .. "Title"] ] ~= nil then
local new_name = result['y' .. tostring(i) .. "Title"] .. " ,(" .. tostring(check_func[ result['y' .. tostring(i) .. "Title"] ]+1) .. ")"
check_func[ result['y' .. tostring(i) .. "Title"] ] = check_func[ result['y' .. tostring(i) .. "Title"] ] + 1
result['y' .. tostring(i) .. "Title"] = new_name
else check_func[ result['y' .. tostring(i) .. "Title"] ] = 1
end
end
return result
end
local function stringToTable(s) --字串轉陣列
local t, i = {}, 1
while i <= mw.ustring.len(s) do
if mw.ustring.sub(s, i, i) ~= ' ' then
local j, k = mw.ustring.find(s,"[%d%a]+",i)
if (j or (i+1)) > i then
t[#t + 1] = mw.ustring.sub(s, i, i)
else
t[#t + 1] = mw.ustring.sub(s, j, k)
i = k
end
end
i = i + 1
end
return t
end
local function print_sk(sk,sp)
local body, sp_checker = '', mw.text.trim(sp or '')
for i = 1,#sk do
local checker = ((type(sk[i]) == type({})) and sk[i].name or nil) or sk[i]
if type(checker) == type({}) then
local cats = ""
for cati=1,#checker do if cats ~= "" then cats = cats .. ',' end cats = cats .. tostring(checker[cati])end checker = cats
end
if mw.text.trim( (type(checker)==type(function()end))and "function" or checker ) ~= sp_checker then
if body ~= '' then body = body .. (sp or ' ') end
if type(sk[i]) == type({}) and sk[i].name then
if sk[i].name == "$END" then body = body .. '$' else body = body .. sk[i].name end
else
if tostring(sk[i]) == 'table' and sk[i].assign=="assign" then body = body .. (tostring(sk[i][1])=="$END" and "${字串結尾}" or _subst_error_strip(tostring(sk[i][1])))
else body = body .. _subst_error_strip(tostring(sk[i])) end
end
end
end
return body
end
--mw.log(p.calc("45*5+(1+5-9+((12-5)+5i+(9)/4)*sqrt(-6))*-8",require("Module:Complex Number").cmath.init(),require("Module:Complex Number").cmath.init().toComplexNumber,true))
-- 346.97959 - 181.262241 i
--mw.log(p.calc("45*5+(1+5-9+((12-5)+5+(9)/4)*sin(-6))*-8",nil,nil,true))
-- 217.146633205
--mw.log(p.calc("(i*j*k)",require("Module:Complex Number").qmath.init(),require("Module:Complex Number").qmath.init().toQuaternionNumber,true))
-- (-1)
function p.calc(input_str, math_lib, number_Constructer, debug_flag)
if comp_number == nil then comp_number = require("Module:Complex Number") end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local adj_input_str = input_str
if math_lib and math_lib.is_bool_lib == true then adj_input_str = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(' ' .. input_str .. ' ',"%s+and%s+"," * "),"[&∧]","*"),"%s+or%s+"," + "),"∨","+"),"%s+not%s+"," - "),"¬","-") end
local pre_expr, pre_scope = _function_preprocessing(adj_input_str, math_lib, number_Constructer, debug_flag)
local postfix = p.infixToPostfix(pre_expr, debug_flag)
if pre_scope then postfix.scope = pre_scope end
return p.calc_by_postfix(postfix, {}, math_lib, number_Constructer, debug_flag)
end
function p.nocalc(input_str, math_lib, number_Constructer, debug_flag)
if comp_number == nil then comp_number = require("Module:Complex Number") end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local adj_input_str = input_str
if math_lib and math_lib.is_bool_lib == true then adj_input_str = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(' ' .. input_str .. ' ',"%s+and%s+"," * "),"[&∧]","*"),"%s+or%s+"," + "),"∨","+"),"%s+not%s+"," - "),"¬","-") end
return p.infixToPostfix(adj_input_str, debug_flag)
end
function p.calc_by_postfix(postfix, scope, math_lib, number_Constructer, debug_flag)
if comp_number == nil then comp_number = require("Module:Complex Number") end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local local_scope = {}
local call_stack = {{}}
local calc_stack = {}
local dbg_func, do_dbg = mw.log, true
if debug_flag ~= true then dbg_func, do_dbg = function()end,false end
if type(postfix.scope) == type({}) then for pk, pv in pairs(postfix.scope) do scope[pk] = scope[pk] or postfix.scope[pk]end end
for i = 1,#postfix do
local it = postfix[i]
if it.propetry == "func start" then
call_stack[#call_stack + 1] = {}
elseif it.propetry == "operator" then
local opdata = p.symbol_table[it.name]
local to_ass
xpcall(function()
if it.name == ',' then
if calc_stack[#calc_stack-1] ~= ',' and calc_stack[#calc_stack] ~= ',' and #(call_stack[#call_stack]) > 0 then call_stack[#call_stack+1]={} end
if calc_stack[#calc_stack-1] == ',' and calc_stack[#calc_stack] == ',' then
local call_stack_top_left,call_stack_top_right = {},{}
for ij = 1, #(call_stack[#call_stack-1]) do call_stack_top_left[#call_stack_top_left + 1] = (call_stack[#call_stack-1])[ij] end
for ij = 1, #(call_stack[#call_stack]) do call_stack_top_right[#call_stack_top_right + 1] = (call_stack[#call_stack])[ij] end
local cma_result_left,cma_result_right = p.symbol_table[','].calc( mathlib, unpack( call_stack_top_left ) ), p.symbol_table[','].calc( mathlib, unpack( call_stack_top_right ) )
call_stack[#call_stack] = nil
call_stack[#call_stack] = nil
local call_stack_count = #call_stack
for queue_it = call_stack_count,1,-1 do call_stack[queue_it+1]=call_stack[queue_it]end
call_stack[1] = { cma_result_left, cma_result_right }
else
if calc_stack[#calc_stack-1] ~= ',' then
local call_stack_count = #(call_stack[#call_stack])
for queue_it = call_stack_count,1,-1 do (call_stack[#call_stack])[queue_it+1]=(call_stack[#call_stack])[queue_it]end
(call_stack[#call_stack])[1] = calc_stack[#calc_stack-1]
--(call_stack[#call_stack])[#(call_stack[#call_stack]) + 1] = calc_stack[#calc_stack-1]
end
if calc_stack[#calc_stack] ~= ',' then (call_stack[#call_stack])[#(call_stack[#call_stack]) + 1] = calc_stack[#calc_stack] end
end
calc_stack[#calc_stack] = nil; calc_stack[#calc_stack] = ','
elseif opdata.count == 1 then
if calc_stack[#calc_stack] == ',' and #call_stack > 0 then
local call_stack_top = {}
for ij = 1, #(call_stack[#call_stack]) do call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[ij] end
local cma_result = p.symbol_table[','].calc( mathlib, unpack( call_stack_top ) )
calc_stack[#calc_stack] = opdata.calc(cma_result,mathlib,numberConstructer)
call_stack[#call_stack] = calc_stack[#calc_stack]
else
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
error("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" ") end
end
calc_stack[#calc_stack] = opdata.calc(calc_stack[#calc_stack],mathlib,numberConstructer)
end
else
if it.name ~= '←' then
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
else error("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" " ) end
end
if ((type(calc_stack[#calc_stack - 1]) == type({})) and calc_stack[#calc_stack - 1] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack - 1][1]]
if get_data then calc_stack[#calc_stack - 1] = local_scope[calc_stack[#calc_stack - 1][1]]
else error("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack - 1][1])) .. "\" ") end
end
else
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
else get_data = (scope or {})[calc_stack[#calc_stack][1]] or _G[calc_stack[#calc_stack][1]] or mathlib[calc_stack[#calc_stack][1]]
if type(get_data) == type(function()end) then calc_stack[#calc_stack] = get_data
else error("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" ") end
end
end
to_ass = calc_stack[#calc_stack - 1]
end
if (calc_stack[#calc_stack] == ',' or calc_stack[#calc_stack-1] == ',') and #call_stack > 0 then
local cma_result_left,cma_result_right
if calc_stack[#calc_stack-1] == ',' and calc_stack[#calc_stack] == ',' then
local call_stack_top_left,call_stack_top_right = {},{}
for ij = 1, #(call_stack[#call_stack-1]) do call_stack_top_left[#call_stack_top_left + 1] = (call_stack[#call_stack-1])[ij] end
for ij = 1, #(call_stack[#call_stack]) do call_stack_top_right[#call_stack_top_right + 1] = (call_stack[#call_stack])[ij] end
cma_result_left,cma_result_right = p.symbol_table[','].calc( mathlib, unpack( call_stack_top_left ) ), p.symbol_table[','].calc( mathlib, unpack( call_stack_top_right ) )
calc_stack[#calc_stack - 1] = opdata.calc(cma_result_left ,cma_result_right, mathlib,numberConstructer)
call_stack[#call_stack] = nil call_stack[#call_stack] = nil
local call_stack_count = #call_stack
for queue_it = call_stack_count,1,-1 do call_stack[queue_it+1]=call_stack[queue_it]end
call_stack[1] = calc_stack[#calc_stack - 1]
else
cma_result_left,cma_result_right = calc_stack[#calc_stack - 1]or 0, calc_stack[#calc_stack]or 0
local call_stack_top = {}
for ij = 1, #(call_stack[#call_stack]) do call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[ij] end
local cma_result = p.symbol_table[','].calc( mathlib, unpack( call_stack_top ) )
if calc_stack[#calc_stack-1] == ',' then cma_result_left = cma_result
elseif calc_stack[#calc_stack] == ',' then cma_result_right = cma_result end
calc_stack[#calc_stack - 1] = opdata.calc(cma_result_left ,cma_result_right, mathlib,numberConstructer)
call_stack[#call_stack] = nil
local call_stack_count = #call_stack
for queue_it = call_stack_count,1,-1 do call_stack[queue_it+1]=call_stack[queue_it]end
call_stack[1] = calc_stack[#calc_stack - 1]
end
else
calc_stack[#calc_stack - 1] = opdata.calc(calc_stack[#calc_stack - 1]or 0 ,calc_stack[#calc_stack]or 0,mathlib,numberConstructer)
end
calc_stack[#calc_stack] = nil
end
end, function(message)
error("計算失敗:套用運算子 \"" .. _subst_error_strip(mw.text.trim(it.name)) .. "\" 發生錯誤 \"" .. message .. "\" .")
end)
xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
if it.name == '←' and type(mathlib.mathdef)~=type(function()end) then
local cantass = "計算失敗:套用運算子 \"" .. _subst_error_strip(mw.text.trim(it.name)) .. "\" 發生錯誤:無法將 \"".. tostring(to_ass[1] or to_ass) .."\" 的值設定為 \"" .. tostring(calc_stack[#calc_stack] ) .. "\" ."
local check_num = numberConstructer(to_ass[1] or to_ass)
if check_num then error(cantass) elseif local_scope then local_scope[to_ass[1]] = calc_stack[#calc_stack] else error(cantass)end
end
if do_dbg == true then dbg_func(it.name, '\t', print_sk(calc_stack,', ') ) end
elseif it.propetry == "func" then
local calfunc, functype = mathlib[it.name], type(tonumber)
if type(calfunc) ~= functype and type((scope or {})[it.name]) == functype then calfunc = scope[it.name] end
if type(calfunc) ~= functype and type(_G[it.name]) == functype then calfunc = _G[it.name] end
if type(calfunc) ~= functype and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
mathlib = ext_mathlib(mathlib, numberConstructer)
calfunc = mathlib[it.name]
if use_ext_mathlib ~= true and type(calfunc) == functype then use_ext_mathlib = true end
end
if type(calfunc) ~= functype and type((local_scope or {})[it.name]) == functype then calfunc = local_scope[it.name] end
local is_other_module = false
if type(calfunc) ~= functype and use_other_module == true then
local check_func = mw.text.split(it.name,"AtModule")
if #check_func > 1 then
xpcall(function()
local load_module = require( "Module:" .. check_func[2])
calfunc = load_module[check_func[1]]
is_other_module = true
end, function(message)
error("計算失敗:執行函數 \"" .. "Module:" .. check_func[2] .. '#' .. check_func[1] .. "\" 發生錯誤 \"" .. message .. "\" .")
end)
end
end
local callstr = it.name
if type(calfunc) == functype then
xpcall(function()
local call_stack_top = {}
for j = 1, #(call_stack[#call_stack]) do
if ((type((call_stack[#call_stack])[j] ) == type({})) and (call_stack[#call_stack])[j] or {}).assign == "assign" then
local get_data = (local_scope or {})[(call_stack[#call_stack])[j][1]]
if get_data then (call_stack[#call_stack])[j] = local_scope[(call_stack[#call_stack])[j][1]]
else error("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring((call_stack[#call_stack])[j][1])) .. "\" ") end
end
call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[j]
end
if call_stack_top == ',' or call_stack_top == '' or call_stack_top == nil then
call_stack_top[#call_stack_top + 1] = calc_stack[#calc_stack]
end
if #call_stack_top > 0 then
if do_dbg == true then callstr = callstr .. '(' .. print_sk(call_stack_top,',') .. ')' end
local wrap_call_stack_top = call_stack_top
if is_other_module then
wrap_call_stack_top = {}
for k,v in pairs(call_stack_top) do wrap_call_stack_top[k] = tostring(v) end
end
local calc_result = calfunc( unpack( wrap_call_stack_top ) )
if type(calc_result) == type('') then calc_result = numberConstructer(calc_result) end
calc_stack[#calc_stack] = calc_result
else
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
else error("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" ") end
end
local wrap_call_stack_top = calc_stack[#calc_stack]
if is_other_module then wrap_call_stack_top = tostring(wrap_call_stack_top) end
local calc_result = calfunc( wrap_call_stack_top )
if type(calc_result) == type('') then calc_result = numberConstructer(calc_result) end
calc_stack[#calc_stack] = calc_result
end
call_stack[#call_stack] = nil
end, function(message)
error("計算失敗:執行函數 \"" .. _subst_error_strip(it.name) .. "\" 發生錯誤 \"" .. message .. "\" .")
end)
else
if it.name == '(' then error("計算失敗:未封閉的括號") end
error("計算失敗:無法執行函數 \"" .. _subst_error_strip(it.name) .. "\" ")
end
xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
if do_dbg == true then dbg_func(callstr, '\t', print_sk(calc_stack,', ') ) end
else
local get_data = numberConstructer(it.name)
if get_data == nil then get_data = numberConstructer((scope or {})[it.name]) or numberConstructer(_G[it.name]) or numberConstructer(mathlib[it.name]) or numberConstructer(it.name) end
if get_data == nil then get_data={it.name,assign="assign"}end
calc_stack[#calc_stack + 1] = get_data
xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
if do_dbg == true then dbg_func(it.name, '\t', print_sk(calc_stack,', ') ) end
end
end
if #calc_stack == 1 then
local checker = calc_stack[#calc_stack]
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
checker = tostring(calc_stack[#calc_stack][1])
end
if checker == ',' then
for call_i=#call_stack,1,-1 do
for call_j=1,#(call_stack[call_i]) do
if ((type(call_stack[call_i][call_j]) == type({})) and call_stack[call_i][call_j] or {}).assign == "assign" then
local get_data = (local_scope or {})[call_stack[call_i][call_j][1]]
if get_data then call_stack[call_i][call_j] = local_scope[call_stack[call_i][call_j][1]]
else call_stack[call_i][call_j] = tostring(call_stack[call_i][call_j][1]) end
end
if checker == ',' then checker = '' else checker = checker..', ' end
checker = checker .. tostring(call_stack[call_i][call_j])
end
end
end
return checker
elseif #calc_stack > 1 then
error("計算失敗:缺少運算子,數字 [" .. print_sk(calc_stack,', ') .. "] 無法運算。")
end
return numberConstructer(0)
end
p.symbol_table=Operators.symbol_table
function p.infixToPostfix(input_str, debug_flag)
local str, index, num_list = input_str, 0, {};
local dbg_func, do_dbg = mw.log, true
if debug_flag ~= true then dbg_func, do_dbg = function()end,false end
str = mw.ustring.gsub(str,"([%+%-]?)(%d*%.?%d+)e([%+%-]?%d+)",function(n_sign,n_num,n_pow)return n_sign.."("..n_num.."*10^("..n_pow.."))"end)
str = mw.ustring.gsub(str,"([A-Za-hj-z])i","%1I")
str = mw.ustring.gsub(str,"([A-Za-ik-z])j","%1J")
str = mw.ustring.gsub(str,"([A-Za-jl-z])k","%1K")
str = mw.ustring.gsub(str,"i([A-Za-hj-z])","I%1")
str = mw.ustring.gsub(str,"j([A-Za-ik-z])","J%1")
str = mw.ustring.gsub(str,"k([A-Za-jl-z])","K%1")
local result = mw.ustring.gsub(str,"%d*%.?%d*%s*[ijk]?",
function(b)
if b ~= nil and mw.text.trim(b) ~= '' then
index = index + 1
num_list[#num_list + 1] = b
return ' ' .. tostring(index)
end
return ''
end
);
result = mw.ustring.gsub(result,"I","i")
result = mw.ustring.gsub(result,"J","j")
result = mw.ustring.gsub(result,"K","k")
--------------------------------------------------------
local str2, index, azid, func_list = result, 0, '', {};
local result = mw.ustring.gsub(str2,"[π°]",
function(b)
if b ~= nil and mw.text.trim(b) ~= '' then
num_list[#num_list + 1] = b
return ' ˙ ' .. tostring(#num_list) .. ' '
end
end
);
result = mw.ustring.gsub(result,"%a[%a%d]*%s*%(?",
function(b)
if b ~= nil and mw.text.trim(b) ~= '' then
if mw.ustring.find(b,"%(") then
local func_name = mw.ustring.match(b,"%a[%a%d]*")
if func_name ~= nil and mw.text.trim(func_name) ~= '' then
index, azid = index + 1, numberToAZ(index)
func_list[azid] = func_name
return ' ' .. azid .. ' '
end
else
num_list[#num_list + 1] = b
return ' ' .. tostring(#num_list) .. ' '
end
end
return ''
end
);
for i=1,#num_list do num_list[i] = mw.ustring.gsub(num_list[i],"%s+",'') end
local mid_expr = stringToTable(result)
mid_expr[#mid_expr + 1] = "$END"
local stack, postfix = {{name="$END",elements=0}}, {}
for i = 1,#mid_expr do
local it = mid_expr[i]
if it == "$END" then
while #stack > 0 and stack[#stack].name ~= "$END" do
local psymbol_tablestackstacknamecount,_fl = -1
_fl,psymbol_tablestackstacknamecount = xpcall(function()return p.symbol_table[stack[#stack].name].count end,function()end)
if (stack[#stack] or {elements=0}).elements < (psymbol_tablestackstacknamecount or -1) then
if do_dbg == true then dbg_func("==operator ",stack[#stack].name, " need ",p.symbol_table[stack[#stack].name].count, " elements, but got ",stack[#stack].elements) end
return {}
end
postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
stack[#stack] = nil --pop
if stack[#stack] then stack[#stack].elements = (stack[#stack].elements or 0) + 1 end
end
if do_dbg == true then dbg_func("結束",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
elseif mw.ustring.match(it,"[%a%(]") then
stack[#stack + 1] = {name=it,elements=0,propetry='func'}
if do_dbg == true then dbg_func(it, "括號開始",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
if func_list[it] ~= nil then postfix[#postfix + 1] = {name=' ', propetry="func start"} end
elseif p.symbol_table[it] ~= nil and p.symbol_table[it].propetry == "op" then
local op_it = p.symbol_table[it]
local op_ls = p.symbol_table[mid_expr[i-1]]
local flag = mw.ustring.match(mid_expr[i-1] or '',"[%a%(]") if (mid_expr[i-1] or '娜娜奇') == '娜娜奇' then flag = false end
if ( op_ls or (i == 1) or flag ) and op_it.multp == true then
stack[#stack + 1] = {name=it .. ' ',elements=0,propetry='operator'}
else
while p.symbol_table[(stack[#stack]or{name=function()end}).name] and p.symbol_table[(stack[#stack]or{name=function()end}).name].priority and
p.symbol_table[stack[#stack].name].ppriority >= p.symbol_table[it].priority do
if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
if do_dbg == true then dbg_func("==operator ",stack[#stack].name, " need ",p.symbol_table[stack[#stack].name].count, " elements, but got ",stack[#stack].elements) end
return {}
end
postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
stack[#stack] = nil --pop
stack[#stack].elements = (stack[#stack].elements or 0) + 1
end
stack[#stack + 1] = {name=it,elements=1, propetry='operator'}
end
if do_dbg == true then dbg_func(it, "運算子",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
elseif mw.ustring.match(it,"%d+") then
postfix[#postfix + 1] = {name=num_list[tonumber(it)] or ("N" .. it), propetry="number"}
stack[#stack].elements = (stack[#stack].elements or 0) + 1
if do_dbg == true then dbg_func(it, "數字",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
elseif it == ')' then
local flag = mw.ustring.match(stack[#stack].name,"[%a%(]")
while flag == nil do --遇 ) 輸出至 (
if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
if do_dbg == true then dbg_func("==operator ",stack[#stack].name, " need ",p.symbol_table[stack[#stack].name].count, " elements, but got ",stack[#stack].elements) end
return {}
end
postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
stack[#stack] = nil --pop
stack[#stack].elements = (stack[#stack].elements or 0) + 1
flag = mw.ustring.match(stack[#stack].name,"[%a%(]")
end
if mw.ustring.match(stack[#stack].name,"%a") then
postfix[#postfix + 1] = {name=func_list[stack[#stack].name] or stack[#stack].name, propetry=stack[#stack].propetry}
end
stack[#stack] = nil --pop
if stack[#stack] then stack[#stack].elements = ((stack[#stack] or {}).elements or 0) + 1 end
if do_dbg == true then dbg_func(it, "結束括號",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack))end
end
end
return postfix
end
--表達式輸出為<math></math>支援
p.tagmath={
matheq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'=','=')
end,
mathneq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'≠','\\neq')
end,
mathdef=function(op1,op2)
local that, oper_id = p.tagmath.toTagMath(op2), ''
if op2.lowoperator ~= '(' and op2.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
return p.tagmath.apply_binary_operator(op1,that,'←','\\overset{\\underset{\\mathrm{def}}{}}{=}')
end,
mathmapsto=function(op1,op2)
local that_op1, oper_id = p.tagmath.toTagMath(op1), ''
if op1.lowoperator ~= '(' and op1.lowoperator ~= '' then that_op1.value = "\\left( " .. that_op1.value .. "\\right) "end
that_op1.lowoperator = oper_id
return p.tagmath.apply_binary_operator(that_op1,op2,'↦','\\mapsto')
end,
mathset=function(op1,op2)
local that_op1, oper_id, that = p.tagmath.toTagMath(op1), ''
if op1.lowoperator ~= '(' and op1.lowoperator ~= '' then that_op1.value = "\\left( " .. that_op1.value .. "\\right) "end
that_op1.lowoperator = oper_id
that, oper_id = p.tagmath.toTagMath(op2), ''
if op2.lowoperator ~= '(' and op2.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
return p.tagmath.apply_binary_operator(that_op1,that,'⇽','\\gets')
end,
mathcomma=function(...)
local get_all_arg = {...}
if #get_all_arg == 1 then return get_all_arg[1] end
if #get_all_arg == 0 then return '' end
local merge_data = ''
for itj=1,#get_all_arg do
if merge_data ~= '' then merge_data = merge_data .. ' ,\\, ' end
merge_data = merge_data .. tostring(get_all_arg[itj])
end
local that_op1, oper_id = p.tagmath.toTagMath(merge_data), ''
that_op1.value = "\\left( " .. that_op1.value .. "\\right) "
that_op1.lowoperator = oper_id
return that_op1
end,
mathsemicolon=function(op1,op2)
local check_empty = mw.ustring.gsub(tostring(op1),'%s','')
if check_empty =="{}" or check_empty == '' then return op2 end
return p.tagmath.apply_binary_operator(op1,op2,';',';\\,')
end,
mathtimes=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'⋅','\\, ')
end,
mathlt=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'<','<')
end,
mathgt=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'>','>')
end,
mathlteq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'≤','\\leq')
end,
mathgteq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'≥','\\geq')
end,
mathand=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'&','\\and')
end,
mathor=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'|','\\or')
end,
mathnot=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\lnot" .. that.value
return that
end,
pow=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'^','^',false,true)
end,
div=function(op1,op2)
local left, right = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
left.lowoperator = ''
left.value = "\\frac{ " .. left.value .. " }{ " .. right.value .. "}"
return left
end,
sqrt=function(op1,op2)
local left = p.tagmath.toTagMath(op1)
if op2 ~= nil then
local right = p.tagmath.toTagMath(op2)
left.value = "\\sqrt[ " .. right.value .. " ]{ " .. left.value .. "}"
else
left.value = "\\sqrt{ " .. left.value .. " }"
end
left.lowoperator = ''
return left
end,
log=function(op1,op2)
local left, right, vals, log_symbol
if op2 ~= nil then
right, left = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
vals = "_{" .. right.value .. "}"
log_symbol = "log "
else
left, vals = p.tagmath.toTagMath(op1), ''
log_symbol = "ln "
end
if left.lowoperator ~= '(' and left.lowoperator ~= '' then left.value = "\\left( " .. left.value .. "\\right) "end
left.lowoperator = ''
left.value = '\\' .. log_symbol .. vals .. left.value
return left
end,
abs=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\left\\vert " .. that.value .. "\\right\\vert "
return that
end,
conjugate=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\overline{ " .. that.value .. " } "
return that
end,
floor=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\left\\lfloor " .. that.value .. "\\right\\rfloor "
return that
end,
ceil=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\left\\lceil " .. that.value .. "\\right\\rceil "
return that
end,
binomial=function(n,k)
local that, oper_id = p.tagmath.toTagMath(n), ''
local that_k = p.tagmath.toTagMath(k)
that.lowoperator = oper_id
that.value = "\\binom {" .. that.value .. "}{" .. that_k.value .. '}'
return that
end,
min=function(...)
local this_list, oper_id = {...}, ''
local that = p.tagmath.toTagMath(this_list[1])
for i=2,#this_list do
local it_item = p.tagmath.toTagMath(this_list[i])
that.value = that.value .. ', \\,' .. it_item.value
end
that.value = "\\left( " .. that.value .. "\\right) "
that.lowoperator = oper_id
that.value = "\\min {" .. that.value .. '}'
return that
end,
factorial=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = that.value .. "!"
return that
end,
hide=function(this)return""end,
inverse=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = that.value .. "^{-1}"
return that
end,
re=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\operatorname{Re}" .. that.value
return that
end,
im=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\operatorname{Im}" .. that.value
return that
end,
apply_function=function(func_name, ...)
local para_info = {...}
local this = #para_info == 1 and para_info[1] or p.tagmath.mathcomma(...)
mw.log(para_info[1].lowoperator)
local that, oper_id = p.tagmath.toTagMath(this), '('
local math_ext_funcs={["minimum"]="\\min",["maximum"]="\\max",["sin"]="\\sin",["cos"]="\\cos",["tan"]="\\tan",["sec"]="\\sec",["csc"]="\\csc",["cot"]="\\cot",
["asin"]="\\arcsin",["acos"]="\\arccos",["atan"]="\\arctan",["asec"]="\\operatorname{arcsec}",["acsc"]="\\operatorname{arccsc}",["acot"]="\\operatorname{arccot}",
["sinh"]="\\sinh",["cosh"]="\\cosh",["tanh"]="\\tanh",["sech"]="\\operatorname{sech}",["csch"]="\\operatorname{csch}",["coth"]="\\coth",
["asinh"]="\\operatorname{arcsinh}",["acosh"]="\\operatorname{arccosh}",["atanh"]="\\operatorname{arctanh}",["asech"]="\\operatorname{arcsech}",["acsch"]="\\operatorname{arccsch}",["acoth"]="\\operatorname{arccoth}",
["sgn"]="\\sgn",["gamma"]="\\Gamma",["cis"]="\\operatorname{cis}"
}
local math_format_funcs={
["factorial"]="%s!"
}
if #para_info == 1 and this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
if math_format_funcs[func_name] then
that.value = mw.ustring.format(math_format_funcs[func_name], that.value)
else
that.value = (math_ext_funcs[func_name] or func_name) .. ' ' .. that.value
end
return that
end,
apply_binary_operator = function(op1, op2, oper_id, oper_math,left_no,right_no)
local left, right = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
if left.lowoperator ~= '(' and left.lowoperator ~= '' and
((p.symbol_table[left.lowoperator] and p.symbol_table[left.lowoperator].ppriority and
p.symbol_table[left.lowoperator].ppriority < p.symbol_table[oper_id].priority)) then
if not left_no then
left.value = "\\left( " .. left.value .. "\\right) "
end left.lowoperator = '('
end
if right.lowoperator ~= '(' and right.lowoperator ~= '' and
((p.symbol_table[right.lowoperator] and p.symbol_table[right.lowoperator].ppriority and
p.symbol_table[right.lowoperator].ppriority < p.symbol_table[oper_id].priority)) then
if not right_no then
right.value = "\\left( " .. right.value .. "\\right) "
end right.lowoperator = '('
end
local low_operator = oper_id
if ((p.symbol_table[left.lowoperator] or {ppriority=0}).ppriority or 0) ~= 0 then
if p.symbol_table[left.lowoperator].ppriority < p.symbol_table[low_operator].ppriority then
low_operator = left.lowoperator
end
end
if ((p.symbol_table[right.lowoperator] or {ppriority=0}).ppriority or 0) ~= 0 then
if p.symbol_table[right.lowoperator].ppriority < p.symbol_table[low_operator].ppriority then
low_operator = right.lowoperator
end
end
left.lowoperator = low_operator
left.value = "{ {" .. left.value .. '}' .. oper_math .. '{' .. right.value .. "} }"
return left
end,
TagMathMeta = {
__add = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'+','+')
end,
__sub = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'-','-')
end,
__mul = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'*',"\\times ")
end,
__div = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'/',"\\div ")
end,
__tostring = function (this) return this.value end,
__unm = function (this)
local that, oper_id = p.tagmath.toTagMath(this), "- "
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "-{ " .. that.value .. "}"
return that
end,
__eq = function (op1, op2)return p.tagmath.tagMathString(op1).value == p.tagmath.tagMathString(op2).value end,
},
toTagMath = function(tagMathString)
if type(tagMathString) == type(nil) then return nil end
local math_ext_const={["pi"]="\\pi",["π"]="\\pi",["°"]="{}^{\\circ}",["inf"]="\\infty"}
if (type(tagMathString) == type({})) and tagMathString.value ~= nil and tagMathString.lowoperator ~= nil then
TagMath = {value=tagMathString.value,lowoperator=tagMathString.lowoperator}
else
TagMath = {}
TagMath.value = math_ext_const[tagMathString] or tagMathString
TagMath.lowoperator = ''
end
setmetatable(TagMath,p.tagmath.TagMathMeta)
return TagMath
end,
init = function()
p.tagmath.zero = p.tagmath.toTagMath(0)
p.tagmath.one = p.tagmath.toTagMath(1)
p.tagmath.noncalculate=true
p.tagmath[0],p.tagmath[1] = p.tagmath.zero,p.tagmath.one
new_meta = getmetatable( p.tagmath ) or {}
new_meta.__index = function (this, func_name)
return function(...)return p.tagmath.apply_function(func_name, ...)end
end
setmetatable(p.tagmath,new_meta)
return p.tagmath
end
}
return p