diff --git a/apps/app_analyze_fn.lua b/apps/app_analyze_fn.lua deleted file mode 100644 index 2991818..0000000 --- a/apps/app_analyze_fn.lua +++ /dev/null @@ -1,81 +0,0 @@ -local apps = require 'apps.apps' -local choice = require('dialog.choice').display_sync -local ask_n = require('dialog.input').display_sync_n -local sym = require('ti.sym') -local ui = require('ui.shared') -local lexer = require 'ti.lexer' -local expr = require 'expressiontree' -local sym = require 'ti.sym' - -local function each_result(str, fn) - local tokens = lexer.tokenize(str) - local e = tokens and expr.from_infix(tokens) - if e then - if e.text == '{' or e.text == 'or' or e.text == 'and' then - for _, arg in ipairs(e:collect_operands_recursive()) do - fn(arg) - end - else - fn(e) - end - end -end - -local function run_analyze(stack) - local fn, low, high = table.unpack(ask_n(3, { title = "Analyze ..." })) - local var = "x" - - local with_str = nil - if low:len() ~= 0 then - with_str = (with_str and with_str .. " and ") or "|" - with_str = with_str .. low .. ">=" .. var - end - if high:len() ~= 0 then - with_str = (with_str and with_str .. " and ") or "|" - with_str = with_str .. var .. "<=" .. high - end - - local function get_zeros(fn, bounds) - local tab = {} - each_result(math.evalStr(string.format("zeros(%s,%s)%s", fn, var, bounds or "")), - function(z) - table.insert(tab, z) - end) - return tab - end - - local function is_zero(fn, at) - return math.evalStr(string.format("(%s|%s=%s)=0", fn, var, at)) == "true" - end - - local function has_sign_change(fn, at, delta) - local delta = "0.000001" - local is_neg_0 = math.evalStr(string.format("(%s|%s=%s-%s)<0", fn, var, at, delta)) == "true" - local is_neg_1 = math.evalStr(string.format("(%s|%s=%s+%s)<0", fn, var, at, delta)) == "true" - if is_neg_0 ~= is_neg_1 then - return (not is_neg_0 and is_neg_1) and -1 or 1 - end - return 0 - end - - local results = {} - - local zeros = get_zeros(fn, with_str) - if zeros and #zeros > 0 then - table.insert(results, {title="Zeros", result="*zeros"}) - - for _, v in ipairs(zeros) do - local x = v:infix_string() - local y = math.evalStr(string.format("%s|%s=%s", fn, var, x)) - table.insert(results, {title=string.format("%s=%s (%s|%s)", var, x, x, y), result=x}) - end - end - - - local r = choice({ - title = 'Results', - items = results - }) -end - -apps.add('analyze', 'Analyze function', run_analyze) diff --git a/apps/app_binom.lua b/apps/app_binom.lua deleted file mode 100644 index 39fd12f..0000000 --- a/apps/app_binom.lua +++ /dev/null @@ -1,97 +0,0 @@ -local apps = require 'apps.apps' -local ask = require('dialog.input').display_sync -local choice = require('dialog.choice').display_sync - -local function run_find_n(stack) - local p = "0.50" - local op = ">=" - local limit = "1" - local low = "0" - local high = "100" - local r_op = ">=" - local r = "0.50" - - while true do - local action = choice({ - title = 'Binom - Find n - ' .. string.format('P(X%s%s)%s%s', op, limit, r_op, r), - items = { - {align = -1, title = 'p = ' .. p, result = 'p'}, - {align = -1, title = 'X', result = 'x'}, - {align = -1, title = op, result = 'o'}, - {align = -1, title = limit, result = 'l'}, - {align = -1, title = r_op, result = 'r_op'}, - {align = -1, title = r, result = 'r'}, - {align = -1, title = 'n low = ' .. low, result = 'low'}, - {align = -1, title = 'n high = ' .. high, result = 'high'}, - {align = 0, title = 'Find... ', result = 'e'}, - } - }) - if action == 'p' then - p = ask {title = 'p', text = p} or p - elseif action == 'l' or action == 'x' then - limit = ask {title = 'Limit', text = limit} or limit - elseif action == 'o' then - op = choice { - title = "Operator", - items = { - { title = "=", result = "=" }, - { title = ">=", result = ">=" }, - { title = "<=", result = "<=" }, - } - } or op - elseif action == 'r_op' then - r_op = choice { - title = "Operator", - items = { - { title = "=", result = "=" }, - { title = ">", result = ">" }, - { title = ">=", result = ">=" }, - { title = "<", result = "<" }, - { title = "<=", result = "<=" }, - } - } or r_op - elseif action == 'r' then - r = ask {title = 'r', text = r} or r - elseif action == 'low' then - low = ask {title = 'Lower bound (n)', text = low} or low - elseif action == 'high' then - high = ask {title = 'Upper bound (n)', text = high} or high - elseif action == 'e' then - break - else - return - end - end - - local function eval(n) - local fn - if op == '=' then - fn = string.format('binomPdf(%s,%s,%s)', n, p, limit) - elseif op == '<=' then - fn = string.format('binomCdf(%s,%s,%s,%s)', n, p, 0, limit) - elseif op == '>=' then - fn = string.format('binomCdf(%s,%s,%s,%s)', n, p, limit, n) - end - return math.evalStr(fn .. r_op .. r) - end - - low = tonumber(low) or 0 - high = tonumber(high) or 100 - for n = low, high do - local res = eval(n) - if res == 'true' then - choice{ - title = "Results", - items = { - { title = "n = " .. tostring(n - 2) .. "; " .. eval(n - 2) }, - { title = "n = " .. tostring(n - 1) .. "; " .. eval(n - 1) }, - { title = "n = " .. tostring(n + 0) .. "; " .. res }, - { title = "n = " .. tostring(n + 1) .. "; " .. eval(n + 1) }, - { title = "n = " .. tostring(n + 2) .. "; " .. eval(n + 2) }, - } - } - end - end -end - -apps.add('binom - find n', 'Binom - Find n', run_find_n) diff --git a/apps/app_punktsteigung.lua b/apps/app_punktsteigung.lua deleted file mode 100644 index 60b4392..0000000 --- a/apps/app_punktsteigung.lua +++ /dev/null @@ -1,86 +0,0 @@ -local apps = require 'apps.apps' -local lexer = require 'ti.lexer' -local expr = require 'expressiontree' -local ask = require('dialog.input').display_sync -local choice = require('dialog.choice').display_sync - -local function eval(str, fallback) - return select(1, math.evalStr(str)) or fallback -end - -local function each_result(str, fn) - local tokens = lexer.tokenize(eval(str)) - local e = tokens and expr.from_infix(tokens) - if e then - if e.text == '{' or e.text == 'or' or e.text == 'and' then - for _, arg in ipairs(e:collect_operands_recursive()) do - fn(arg) - end - else - fn(e) - end - end -end - -local function eval_bool(str) - local res = eval(str) - if res == 'false' then return false end - if res == 'true' then return true end -end - -local function run_tangent(stack) - local fx = ask { title = 'f(x)', text = eval('f1(x)') } - - local x = ask { title = 'x' } - local y = eval(string.format('(%s)|x=%s', fx, x)) - local m = eval(string.format('derivative(%s,x)|x=%s', fx, x)) - if not m then m = ask { title = 'm' } end - - stack:push_infix(string.format('%s*(x-%s)+%s', m, x, y)) -end -apps.add('tangent t(x)', 'Tangent', run_tangent) - -local function run_tangent_pt(stack) - local fx = ask { title = 'f(x)', text = eval('f1(x)') } - if not fx then return end - local pt = { x = ask { title = 'x' }, y = ask { title = 'y' } } - if not (pt.x and pt.y) then return end - - local store = choice { title = 'Store results?', items = { - { title = 'As t1(x) ...', result = 'tx', seq = {'t'} }, - { title = 'As f2(x) ...', result = 'fx', seq = {'f'} }, - { title = 'No', result = false, seq = {'n'} }, - }} - - local fd = eval(string.format('derivative(%s,x)', fx)) - - local n = 1 - each_result(string.format('solve((%s)-(%s)=(%s)*(x-(%s)),x)', fx, pt.y, fd, pt.x), - function(e) - local x = eval('right('..e:infix_string()..')') - local y = eval(string.format('(%s)|x=%s', fx, x)) - local m = eval(string.format('derivative(%s,x)|x=%s', fx, x)) - if not m then return end - - local tx = string.format('%s*(x-%s)+%s', m, x, y) - if eval_bool(string.format('((%s)=%s)|x=%s', tx, pt.y, pt.x)) ~= false then - stack:push_expr(e) - stack:push_infix(string.format('%s*(x-%s)+%s', m, x, y)) - if store then - local fn - if store == 'tx' then - fn = string.format('t%d(x)', n) - elseif store == 'fx' then - fn = string.format('f%d(x)', n+1) - end - - stack:push_infix(fn) - stack:push_rstore() - end - n = n + 1 - else - print('Skipping function') - end - end) -end -apps.add('tangent t(x) p(x,y)', 'Tangent through p(x,y)', run_tangent_pt) diff --git a/apps/app_trassierung.lua b/apps/app_trassierung.lua deleted file mode 100644 index a104bfb..0000000 --- a/apps/app_trassierung.lua +++ /dev/null @@ -1,55 +0,0 @@ -local apps = require 'apps.apps' -local ask = require('dialog.input').display_sync -local choice = require('dialog.choice').display_sync - --- Generate polynom prototype of specified degree ----@param deg number Polynom degree ----@return string -local function gen_fn_prototype(deg, _c) - local alpha = { 'a', 'b', 'c', 'd', 'e', 'f' } - _c = _c or deg - if _c == 0 then return alpha[deg + 1] end - return alpha[deg - _c + 1] .. '*x^' .. tostring(_c) .. '+' .. gen_fn_prototype(deg, _c - 1) -end - -local function run_trassierung(stack) - local deg = tonumber(ask { title = 'deg(g)', text = '3' }) - if not deg then return end - - local proto = ask { title = 'g(x)', text = gen_fn_prototype(deg) } - if not proto then return end - - math.evalStr('delvar g') - math.evalStr(string.format('%s=:g(x)', proto)) - - local lo, hi = '0', '0' - lo = ask { title = 'low x' } - if not lo then return end - hi = ask { title = 'high x' } - if not hi then return end - - local lofn, hifn = 'f1', 'f2' - lofn = ask { title = 'low fn', text = lofn } - if not lofn then return end - hifn = ask { title = 'high fn', text = hifn } - if not lofn then return end - - local eqs = {} - table.insert(eqs, 'g(x)=' .. lofn .. '(x)|x=' .. lo) - table.insert(eqs, 'g(x)=' .. hifn .. '(x)|x=' .. hi) - table.insert(eqs, 'derivative(g(x),x)=' .. 'derivative(' .. lofn .. '(x),x)|x=' .. lo) - table.insert(eqs, 'derivative(g(x),x)=' .. 'derivative(' .. hifn .. '(x),x)|x=' .. hi) - - if choice { title = '2nd diff?', items = dlg_choice.yesno } then - table.insert(eqs, 'derivative(derivative(g(x),x),x)=' .. 'derivative(derivative(' .. lofn .. '(x),x),x)|x=' .. lo) - table.insert(eqs, 'derivative(derivative(g(x),x),x)=' .. 'derivative(derivative(' .. hifn .. '(x),x),x)|x=' .. hi) - end - - stack:push_infix('system(' .. table.concat(eqs, ',') .. ')') - - if choice { title = 'solve?', items = dlg_choice.yesno } then - -- TODO: ... - end -end - -apps.add('trassierung g(x)', 'Smooth join fns', run_trassierung) diff --git a/apps/app_triangle.lua b/apps/app_triangle.lua deleted file mode 100644 index 708072a..0000000 --- a/apps/app_triangle.lua +++ /dev/null @@ -1,147 +0,0 @@ -local apps = require 'apps.apps' -local ask = require('dialog.input').display_sync -local choice = require('dialog.choice').display_sync -local formsolver = require 'apps.formsolver' - -local vars_default = { - { 'Side a', 'a' }, - { 'Side b', 'b' }, - { 'Side c', 'c' }, - { 'Alpha', 'alpha' }, - { 'Beta', 'beta' }, - { 'Gamma', 'gamma' }, - { 'Perimeter', 'p' }, - { 'Area', 'area' }, -} - -local vars_full = { - { 'Side a', 'a' }, - { 'Side b', 'b' }, - { 'Side c', 'c' }, - { 'Alpha', 'alpha' }, - { 'Beta', 'beta' }, - { 'Gamma', 'gamma' }, - { 'Perimeter', 'p' }, - { 'Semiperimeter', 's' }, - { 'Area', 'area' }, - { 'Height a', 'ha' }, - { 'Height b', 'hb' }, - { 'Height c', 'hc' }, - { 'Inradius', 'inrad' }, - { 'Circumradius', 'circumrad' }, -} - -local function run_triangle(stack) - local vars = vars_default - local formulas = { - -- Law of sine - '{a}/sin({alpha})={b}/sin({beta})', - '{b}/sin({beta})={c}/sin({gamma})', - '{c}/sin({gamma})={a}/sin({alpha})', - -- Law of cosine - '{a}^2={b}^2+{c}^2-2*{b}*{c}*cos({alpha})', - '{b}^2={a}^2+{c}^2-2*{a}*{c}*cos({beta})', - '{c}^2={a}^2+{b}^2-2*{a}*{b}*cos({gamma})', - -- Perimeter - '{p}={a}+{b}+{c}', - '{s}={p}/2', - -- Area - '{area}=1/2*{a}*{b}*sin({gamma})', - '{area}=1/2*{b}*{c}*sin({alpha})', - '{area}=1/2*{c}*{a}*sin({beta})', - '{area}=sqrt({s}*({s}-{a})*({s}-{b})*({s}-{c}))', - -- Height - '{ha}=2*{area}/{a}', - '{hb}=2*{area}/{b}', - '{hc}=2*{area}/{c}', - -- Inradius - '{inrad}={area}/{s}', - -- Circumradius - '{circumrad}={a}/(2*sin({alpha}))', - '{circumrad}={b}/(2*sin({beta}))', - '{circumrad}={c}/(2*sin({gamma}))', - } - - local mode = math.getEvalSettings()[2][1] - if mode == 'Radian' then - table.insert(formulas, '{alpha}+{beta}+{gamma}=pi') - else - table.insert(formulas, '{alpha}+{beta}+{gamma}=180') - end - - local set = {} - - local sel = 1 -- Dialog selection index - while true do - local actions = {} - for _, v in ipairs(vars) do - local name, var = v[1], v[2] - table.insert(actions, { name, set[var] or '', result = var }) - end - - --table.insert(actions, {'Set ABC...', '', result = 'points'}) - if vars == vars_default then - table.insert(actions, { 'Show all...', '', result = 'full' }) - end - table.insert(actions, { 'Solve...', '', result = 'done' }) - - local action - action, sel = choice { title = 'Triangle', items = actions, selection = sel } - if not action then return end - if action == 'done' then - break - elseif action == 'full' then - vars = vars_full - elseif action then - set[action] = ask { title = 'Set ' .. action, text = set[action] or '' } - end - end - - local unsolved = {} - for _, k in ipairs(vars) do - k = k[2] - if not set[k] then - table.insert(unsolved, k) - end - end - - -- Solve all unsolved variables - local steps - set, steps = formsolver.solve_for(unsolved, set, formulas) - - sel = 1 - while true do - local actions = {} - for _, v in ipairs(vars) do - local name, var = v[1], v[2] - table.insert(actions, { name, set[var] or '?', result = var }) - end - - table.insert(actions, { 'Steps...', '', result = 'explain' }) - table.insert(actions, { 'Done...', '[esc]', result = 'done' }) - - local action - action, sel = choice { title = 'Result', items = actions, selection = sel } - if not action then return end - if action == 'done' then - break - elseif action == 'explain' then - local step_items = {} - for _, v in ipairs(steps) do - table.insert(step_items, { title = v.formula..' for '..v.var, result = v.formula }) - end - - while true do - action = choice { title = 'Steps', items = step_items, font_size = 9, row_size = 16 } - if not action then break end - stack:push_infix(action) - end - elseif action ~= nil then - stack:push_infix(set[action]) - stack:push_infix(action) - stack:push_rstore() - end - end -end - -apps.add('triangle', 'Triangle solver', run_triangle) diff --git a/apps/ask_vars.lua b/apps/ask_vars.lua deleted file mode 100644 index 77fc745..0000000 --- a/apps/ask_vars.lua +++ /dev/null @@ -1,79 +0,0 @@ -local choice = require('dialog.choice').display_sync -local ask = require('dialog.input').display_sync - -local t = {} - -local function prepare_vars(vars) - local new = {} - for k, v in pairs(vars) do - if type(v) ~= "table" then - new[k] = {value = tostring(v)} - else - new[k] = v - end - - local item = new[k] - item.kind = item.kind or "text" - item.options = item.options - item.value = item.value or "0" - end - return new -end - -function t.ask_vars(vars, title) - title = title or "Variables" - vars = prepare_vars(vars) - - -- Result table - local r = {} - for k, v in pairs(vars) do - r[k] = r[k] or v.value - end - - -- Ask for a single value - local function ask_value(key) - local is_choice = vars[key].options ~= nil - if is_choice then - local items = {} - for _, v in ipairs(vars[key].options) do - if type(v) == "table" then - table.insert(items, {title = v.title, result = v.result or v.title}) - else - table.insert(items, {title = tostring(v), result = tostring(v)}) - end - end - - return choice{ - title = key .. "...", - items = items, - } or r[key] - else - return ask{ - title = key .. "...", - text = r[key] or "", - } or r[key] - end - end - - while true do - local items = {} - for k, v in pairs(vars) do - table.insert(items, {title = string.format("%s = %s", k, tostring(r[k])), result = k, align = -1}) - end - table.insert(items, {title = "Done", result = "DONE", align = 0}) - - local action = choice{ - title = title, - items = items, - } - if action == "DONE" then - break - else - r[action] = ask_value(action) - end - end - - return r -end - -return t \ No newline at end of file diff --git a/apps/formsolver.lua b/apps/formsolver.lua deleted file mode 100644 index cb53a85..0000000 --- a/apps/formsolver.lua +++ /dev/null @@ -1,126 +0,0 @@ -local m = {} - -local function formula_get_vars(str) - local res = {} - for v in str:gmatch('%{%w+%}') do - table.insert(res, v:sub(2, -2)) - end - return res -end - -local function formula_replace_vars(str, tab) - return str and str:gsub('%{%w+%}', function(key) - key = key:sub(2, -2) - return tab[key] and '(' .. tab[key] .. ')' or key - end) -end - --- Mask variables for symbolic solve/isolation -local function formula_mask_vars(str) - return str and str:gsub('%{%w+%}', function(key) - return '(m_' .. key:sub(2, -2) .. '_m)' - end) -end - --- Unmask masked variables -local function formula_unmask_vars(str) - return str and str:gsub('m_%w+_m', function(key) - return key:sub(3, -3) - end) -end - -local function build_formula_solve_queue(want_var, set, formulas) - local var_to_formula = {} - - if type(want_var) == 'string' then - want_var = { want_var } - end - - -- Insert all given arguments as pseudo formulas - for name, value in pairs(set) do - var_to_formula[name] = name.."=("..value..")" - end - - -- Returns a variable name the formula is solvable for - -- with the current set of known variables - local function get_solvable_for(formula) - local missing = nil - for _, v in ipairs(formula_get_vars(formula)) do - if not var_to_formula[v] then - if missing then - return nil - end - missing = v - end - end - return missing - end - - for _ = 1, 50 do -- Artificial search limit - local found = false - for _, v in ipairs(formulas) do - local var = get_solvable_for(v) - if var then - var_to_formula[var] = v - found = true - end - end - if not found then - break - end - end - - -- Build list of formulas that need to be solved - ---@type string[][] - local solve_queue = {} - - local function add_formula_to_queue(formula, solve_for) - if not formula then return end - - -- Remove prev element - for i, v in ipairs(solve_queue) do - if v[1] == solve_for and v[2] == formula then - table.remove(solve_queue, i) - break - end - end - - -- Insert at top - table.insert(solve_queue, 1, { solve_for, formula }) - - for _, v in ipairs(formula_get_vars(formula)) do - if v ~= solve_for then - add_formula_to_queue(var_to_formula[v], v) - end - end - end - - for _, v in ipairs(want_var) do - print('info: adding wanted var ' .. v .. ' to queue') - add_formula_to_queue(var_to_formula[v], v) - end - - return solve_queue -end - -function m.solve_for(var, set, formulas, fn) - fn = fn or 'nsolve' - local q = build_formula_solve_queue(var, set, formulas) - local steps = {} - for _, v in ipairs(q) do - local variable, formula = v[1], v[2] - - -- Solve numeric - local numeric = math.evalStr(string.format('%s(%s,%s)', fn, formula_replace_vars(formula, set), variable)) - set[variable] = numeric - - -- Solve symbolic (for steps) - local symbolic = formula_replace_vars(formula, {}) - if symbolic then - table.insert(steps, { formula = symbolic, var = variable }) - end - end - return set, steps -end - -return m diff --git a/apps/init.lua b/apps/init.lua index 1b0bfc3..b5f79c2 100644 --- a/apps/init.lua +++ b/apps/init.lua @@ -1,10 +1,3 @@ require 'apps.apps' ---require 'apps.app_formulas' -require 'apps.app_trassierung' -require 'apps.app_punktsteigung' -require 'apps.app_triangle' require 'apps.app_constants' -require 'apps.app_binom' ---require 'apps.app_analyze_fn' - -require 'apps.AnaGeo' \ No newline at end of file +require 'apps.AnaGeo'