diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/modules/mkxl/m-polynomial.mkxl')
-rw-r--r-- | Master/texmf-dist/tex/context/modules/mkxl/m-polynomial.mkxl | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/modules/mkxl/m-polynomial.mkxl b/Master/texmf-dist/tex/context/modules/mkxl/m-polynomial.mkxl new file mode 100644 index 00000000000..a62196ac837 --- /dev/null +++ b/Master/texmf-dist/tex/context/modules/mkxl/m-polynomial.mkxl @@ -0,0 +1,900 @@ +%D \module +%D [ file=m-polynomial, +%D version=2023.8.18, +%D title=\CONTEXT\ Math Module, +%D subtitle=Polynomials, +%D author={Mikael Sundqvist & Hans Hagen}, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% maybe just m-polynomial like m-matrix + +% built-in +% +% alternative=align:normal % uses align mechanism (carry over spacing) +% alternative=align:split % uses align mechanism +% alternative=text:normal % not aligned +% alternative=text:align % uses alignhere etc +% alternative=default % same as text:align (can be normal instead) +% alternative=none % only processing +% +% user: +% +% alternative=somename % \startsetups[math:polynomial:somename] + +\startluacode +if not tex.issetup then -- will become a faster helper + + function tex.issetup(n) -- will become a faster helper + return tex.isdefined(tokens.getters.macro("??setup") .. ":" .. n) + end + +end + +local tonumber = tonumber + +local context = context +local copytable = table.copy +local round = math.round + +local shows = { } +local helpers = { } + +local implement = interfaces.implement + +local v_none = interfaces.variables.none + +local ctx_NC = context.NC +local ctx_NR = context.NR +local ctx_startcolor = context.startcolor +local ctx_stopcolor = context.stopcolor + +local result = { + n = 0, + numerator = { }, + denominator = { }, + steps = { }, +} + +do + + local function show(t,split,symbol,mark) + local n = #t + local done = false + for i=n,1,-1 do + local tn = t[i] + ctx_NC() + if not tn or tn == 0 then + if split then + ctx_NC() + end + else + if mark then ctx_startcolor { mark } end + if done and tn > 0 then + context("+") + end + if tn < 0 then + context("-") + tn = - tn + end + if split then + if mark then ctx_stopcolor() end + ctx_NC() + if mark then ctx_startcolor { mark } end + end + if i > 1 then + if tn ~= 1 then + context("%.3N",tn) + end + context(symbol) + else + context("%.3N",tn) + end + if i > 2 then + context("^{%s}",i-1) + end + if mark then ctx_stopcolor() end + done = true + end + end + ctx_NR() + end + + local function default(settings) + local split = settings.split + local symbol = settings.symbol or "x" + context.startalign { + n = (split and 2 or 1) * result.n, + align = "all:right", + } + local steps = result.steps + local previous = result.numerator + show(result.denominator,split,symbol,"blue") + show(result.numerator,split,symbol) + for i=1,#steps do + local current = steps[i].numerator + if previous then + show(helpers.subtract(previous,current),split,symbol,"red") + end + show(current,split,symbol) + previous = current + end + show(result.quotient,split,symbol,"green") + -- inspect(result) + context.stopalign() + end + + shows["align:normal"] = function(settings) default(settings,false) end + shows["align:split"] = function(settings) default(settings,true) end + +end + +do + + local function show(t,symbol) + local n = #t + local done = false + for i=n,1,-1 do + local tn = t[i] + if not tn or tn == 0 then + -- ignore + else + if done and tn > 0 then + context("+") + end + if tn < 0 then + context("-") + tn = - tn + end + if i > 1 then + if tn ~= 1 then + context("%.3N",tn) + end + context(symbol) + else + context("%.3N",tn) + end + if i > 2 then + context("^{%s}",i-1) + end + done = true + end + end + end + + helpers.show = show + + local function show_n_over_d(n,d,index,symbol) + local colors = result.colors + local c = colors and colors[index] + local cn = c and (c.ns or c.n) + local cd = c and (c.ds or c.d) + context.frac( + function() + if cn then + ctx_startcolor { cn } + show(n,symbol) + ctx_stopcolor() + else + show(n,symbol) + end + end, + function() + if cd then + ctx_startcolor { cd } + show(d,symbol) + ctx_stopcolor() + else + show(d,symbol) + end + end + ) + end + + local function show_what(w,what,index,symbol) + local colors = result.colors + local c = colors and colors[index] + local cw = c and c[what] + if cw then + ctx_startcolor { cw } + show(w,symbol) + ctx_stopcolor() + else + show(w,symbol) + end + end + + local function show_n(n,index,symbol) show_what(n,"n",index,symbol) end + local function show_d(d,index,symbol) show_what(d,"d",index,symbol) end + local function show_q(q,index,symbol) show_what(q,"q",index,symbol) end + + helpers.show_n = show_n + helpers.show_d = show_d + helpers.show_q = show_q + helpers.show_n_over_d = show_n_over_d + + local function lines(settings,align) + local steps = result.steps + local nofsteps = #steps + local colors = result.colors + local symbol = result.symbol or "x" + show_n_over_d(result.numerator,result.denominator,0,symbol) + if nofsteps > 0 then + if align then + context.alignhere() + end + context(steps[1].clipped and "≈" or "=") + for i=1,nofsteps do + local step = steps[i] + show_q(step.quotient,i,symbol) + if not helpers.iszero(step.numerator) then + context("+") + show_n_over_d(step.numerator,result.denominator,i,symbol) + end + if i < nofsteps then + if align then + context.breakhere() + end + context(step.clipped and "≈" or "=",symbol) + end + end + else + -- context.quad() + -- context.mtext("(no quotient)") + end + end + + shows["text:normal"] = function(settings) lines(settings,false) end + shows["text:align"] = function(settings) lines(settings,true) end + +end + +do + + local function subtract(n,d) + local t = { } + for i=1,#d do + t[i] = n[i] - d[i] + end + return t + end + + local function negate(v) + local t = { } + for i=1,#v do + t[i] = -v[i] + end + return t + end + + local function iszero(t) + for i=1,#t do + if t[i] ~= 0 then + return false + end + end + return true + end + + local function last(t) + for i=#t,1,-1 do + local ti = t[i] + if ti ~= 0 then + return i + end + end + return false + end + + local meps <const> = -0.000001 + local peps <const> = 0.000001 + + local function solve(settings) + local numerator = settings.numerator + local denominator = settings.denominator + if type(numerator) == "string" then + numerator = utilities.parsers.settings_to_array(numerator) + settings.numerator = numerator + end + if type(denominator) == "string" then + denominator = utilities.parsers.settings_to_array(denominator) + settings.denominator = denominator + end + local n = #numerator + local d = #denominator + for i=1,n do numerator [i] = tonumber(numerator [i]) or 0 end + for i=1,d do denominator[i] = tonumber(denominator[i]) or 0 end -- proper numbers + for i=1,n do denominator[i] = tonumber(denominator[i]) or 0 end + -- + if d > n then + logs.report("polynomial","denominator has a higher degree") + -- kind of fatal error + end + -- + local nlast = last(numerator) + local dlast = last(denominator) + local steps = { } + local quotient = { } + result = { + n = n, + numerator = numerator, + denominator = denominator, + steps = steps, + colors = settings.colors, + symbol = settings.symbol or "x", + } + for i=1,n do + quotient[i] = 0 + end + while nlast and dlast and nlast >= dlast do + numerator = copytable(numerator) + local shift = nlast - dlast + local nvalue = numerator[nlast] + local dvalue = denominator[dlast] + -- local factor = nvalue // dvalue + local factor = nvalue / dvalue + local clipped = false + for i=1,n do + local ni = numerator[i] + local di = denominator[i-shift] or 0 + local ni = ni - factor * di + if ni ~= 0 and ni > meps and ni < peps then + ni = 0 + clipped = true + end + numerator[i] = ni + end + quotient[shift+1] = factor + steps[#steps+1] = { + numerator = numerator, + factor = factor, + nvalue = nvalue, + dvalue = dvalue, + shift = shift, + quotient = copytable(quotient), + clipped = clipped + } + local l = last(numerator) + if l == nlast then + break + end + nlast = l + end + return result + end + + helpers.last = last + helpers.subtract = subtract + helpers.negate = negate + helpers.iszero = iszero + helpers.solve = solve + + shows[v_none] = function(settings) + -- + end + + shows.default = shows["text:normal"] + + local function tocolors(colors) + if type(colors) == "string" then + local list = utilities.parsers.settings_to_hash(colors) + local done = { } + for k, v in next, list do + done[tonumber(k) or 0] = utilities.parsers.settings_to_hash(v) + end + return done + end + end + + implement { + name = "polynomial", + arguments = { + { + { "alternative" }, + { "numerator" }, + { "denominator" }, + { "split", "boolean" }, + { "colors" }, + { "symbol" }, + }, + }, + actions = function(settings) + settings.colors = tocolors(settings.colors) + result = solve(settings) + local alternative = settings.alternative or "default" + if shows[alternative] then + shows[alternative](settings) + else + local s = "math:polynomial:" .. alternative + if tex.issetup(s) then + context.formatted.directsetup(s) + else + shows.default(settings) + end + end + end + } + + local show = helpers.show + + local function getcolor(n,what) + local colors = result.colors + local c = colors and colors[n] + return c and c[what] + end + + implement { + name = "polynomialsteps", + usage = "value", + actions = function() + return tokens.values.integer, #result.steps + end + } + + implement { + name = "polynomialfactor", + arguments = "integer", + actions = function(n) + local s = result.steps[n] + if s and s.factor then + context(round(s.factor)) + else + context(0) + end + end, + } + + implement { + name = "polynomialshift", + arguments = "integer", + actions = function(n) + local s = result.steps[n] + if s and s.shift then + context(round(s.shift)) + else + context(0) + end + end, + } + + +-- tokens.converters = { } +-- +-- local getexpansion = token.getexpansion +-- +-- function tokens.converters.tonumber(s) +-- return tonumber(s and getexpansion([[\noexpand\the\numexpr ]] .. s)) or 0 +-- end +-- +-- interfaces.implement { +-- name = "demo", +-- public = true, +-- arguments = "optional", +-- actions = function(s) +-- context(tokens.converters.tonumber(s)) +-- end +-- } + + + local function whatever(kind,s) + if kind == "-" then + s = helpers.negate(s) + end + if kind == "+" or kind == '-' then + for i=#s,1,-1 do + if s[i] < 0 then + break + elseif s[i] > 0 then + context("+") + break + end + end + end + helpers.show(s,result.symbol) + end + + implement { + name = "polynomialnumerator", + arguments = { "string", "integer" }, + actions = function(kind,n) + if n > 0 then + local s = result.steps[n] + if s then + whatever(kind,s.numerator) + end + else + whatever(kind,result.numerator) + end + end + } + + implement { + name = "polynomialdenominator", + arguments = { "string", "integer" }, + actions = function(kind,n) + whatever(kind,result.denominator) + end, + } + + implement { + name = "polynomialquotient", + arguments = { "string", "integer" }, + actions = function(kind,n) + if n > 0 then + local s = result.steps[n] + if s then + whatever(kind,s.quotient) + end + end + end, + } + + implement { + name = "polynomialstep", + arguments = { "string", "integer" }, + actions = function(kind,n) + local s = n > 0 and result.steps[n] or result + if s then + helpers.show_n_over_d(s.numerator,result.denominator,n,result.symbol) + end + end + } + + implement { + name = "polynomialquotientstep", + arguments = { "string", "integer" }, + actions = function(kind,n) + local s = result.steps[n] + if s then + local f = s.factor + if n > 1 then + local p = result.steps[n-1] + s = helpers.subtract(s.quotient,p.quotient) + else + s = s.quotient + end + if kind == "-" then + if f > 0 then + context("-") + else + s = helpers.negate(s) + context("+") + end + elseif kind == "+" then + if f > 0 then + context("+") + end + end + helpers.show_q(s,n,result.symbol) + end + end, + } + + implement { + name = "ifpolynomialclipped", + arguments = "integer", + usage = "condition", + public = true, + actions = function(n) + local s = result.steps[n] + return tokens.values.boolean, s and s.quotient + end, + } + + implement { + name = "ifpolynomialnumerator", + arguments = "integer", + usage = "condition", + public = true, + actions = function(n) + local s + if n > 0 then + s = result.steps[n] + else + s = result + end + return tokens.values.boolean, s and not helpers.iszero(s.numerator) + end + } + + implement { + name = "polynomialsymbol", + public = true, + protected = true, + actions = function() + context(result.symbol) + end, + } + +end + +\stopluacode + +\unprotect + +\installcorenamespace {polynomial} + +\installparameterhandler\??polynomial {polynomial} +\installsetuphandler \??polynomial {polynomial} + +\setuppolynomial + [\c!split=\v!no, + \c!alternative=text:align, + \c!symbol=x] + +\tolerant\protected\def\polynomial[#S#1]#*[#2]#*[#3]% + {\begingroup + \ifhastok={#1}% + \setupcurrentpolynomial[#1]% + \donetrue + \else + \donefalse + \fi + \clf_polynomial { + numerator \ifdone{#2}\else{#1}\fi + denominator \ifdone{#3}\else{#2}\fi + alternative {\polynomialparameter\c!alternative} + colors {\polynomialparameter\c!color} + symbol {\polynomialparameter\c!symbol} + split \ifcstok{\polynomialparameter\c!split}\v!yes true \else false\fi + }% + \endgroup} + +\tolerant\protected\def\polynomialsteps {\the\clf_polynomialsteps} +\tolerant\protected\def\polynomialfactor [#1]{\clf_polynomialfactor \numexpr\ifparameter#1\or#1\else\zerocount\fi\relax} +\tolerant\protected\def\polynomialshift [#1]{\clf_polynomialshift \numexpr\ifparameter#1\or#1\else\zerocount\fi\relax} + +\tolerant\def\module_polynomial_component[#1]#*[#2]#*[#3]% + {\ifarguments + \or + #1{}\zerocount + \or + #1{}\numexpr\ifparameter#2\or#2\else\zerocount\fi\relax + \else + #1{#2}\numexpr\ifparameter#3\or#3\else\zerocount\fi\relax + \fi} + +\protected\def\polynomialnumerator {\module_polynomial_component[\clf_polynomialnumerator ]} +\protected\def\polynomialdenominator {\module_polynomial_component[\clf_polynomialdenominator ]} +\protected\def\polynomialquotient {\module_polynomial_component[\clf_polynomialquotient ]} +\protected\def\polynomialquotientstep{\module_polynomial_component[\clf_polynomialquotientstep]} +\protected\def\polynomialstep {\module_polynomial_component[\clf_polynomialstep ]} + +\startsetups math:polynomial:complete + \frac { + \polynomialnumerator + } { + \polynomialdenominator + } + \alignhere + \localcontrolledrepeat \polynomialsteps { + = + \ifnum\currentloopiterator>\plusone + \polynomialquotient[\currentloopiterator - 1] + + \fi + \frac { + \polynomialquotientstep[\currentloopiterator] + (\polynomialdenominator) + \polynomialnumerator[+][\currentloopiterator - 1] +% \polynomialnumerator[-][\currentloopiterator - 1] + \polynomialquotientstep[-][\currentloopiterator] +% \polynomialquotientstep[+][\currentloopiterator] + (\polynomialdenominator) + } { + \polynomialdenominator + } + \breakhere + = + \polynomialquotient[\currentloopiterator] + \ifpolynomialnumerator\currentloopiterator + + + \frac { + \polynomialnumerator[\currentloopiterator] + } { + \polynomialdenominator + } + \fi + \ifnum\currentloopiterator<\polynomialsteps + \breakhere + \fi + } +\stopsetups + +\protect + +\continueifinputfile{m-polynomial.mkxl} + +\setuplayout[tight] + +\setuppapersize[A4,landscape][A4,landscape] + +\starttext + +\setuppolynomial[symbol=z] + +% \def\TempHack +% {\scratchcounter\setmathoptions\mathbinarycode +% \bitwiseflip\scratchcounter-\lookaheadforendclassoptioncode +% \setmathoptions\mathbinarycode\scratchcounter} +% +% \startformula +% \TempHack +% \polynomial +% [-5, -3, 3, -1, 1, 0, 2, -3, -2, -1, 4] +% [-8, -7, -5, 2, 8, -9, 1] +% \stopformula + +% \startformula +% \TempHack +% \polynomial +% [split=yes] +% [-5, -3, 3, -1, 1, 0, 2, -3, -2, -1, 4] +% [-8, -7, -5, 2, 8, -9, 1] +% \stopformula + +\def\TestPolynomial#1#2#3% + {\startformula + \polynomial + [alternative=#1] + [#2] + [#3] + \stopformula} + +% \page + +% \def\TestPolynomials#1#2% +% {\page +% \TestPolynomial{text:normal} {#1}{#2} +% \TestPolynomial{text:align} {#1}{#2} +% \TestPolynomial{align:normal}{#1}{#2} +% \TestPolynomial{align:split} {#1}{#2} +% \page +% } +% +% \TestPolynomials +% {7, -5, 2, 3} +% {3, 0, 1} +% +% \TestPolynomials +% {7, -5, 2, 3} +% {3, 0, 2.7} +% +% \TestPolynomials +% {7, -5, 2, 3} +% {3, 0, 1} + +\startformula +\polynomial + [color={1={n=red,d=green,q=blue},2={n=cyan,d=magenta,q=orange}}] + [7, -5, 2, 3, 2] + [3, 0, 1] +\stopformula + +\polynomial + [alternative=none, + color={1={n=red,d=green,q=blue},2={n=cyan,d=magenta,q=orange,ds=darkgray}}] + [7, -5, 2, 3, 2] + [3, 0, 1] + +numerator + +\startformula + \polynomialnumerator +\stopformula + +numerator 2 + +\startformula + \polynomialnumerator[2] +\stopformula + +denominator + +\startformula + \polynomialdenominator +\stopformula + +quotient 1/2/3 + +\startformula + \polynomialquotient[1]/ + \polynomialquotient[2]/ + \polynomialquotient[3] +\stopformula + +quotientstep 1/2/3 + +\startformula + \polynomialquotientstep[1]/ + \polynomialquotientstep[2]/ + \polynomialquotientstep[3] +\stopformula + +steps + +\startformula + \polynomialsteps +\stopformula + +factor + +\startformula + \polynomialfactor[2] +\stopformula +a +shift + +\startformula + \polynomialshift[2] +\stopformula + + +\startformula + \frac {\polynomialnumerator}{\polynomialdenominator} + = + \polynomialquotient[1] + + + \frac {\polynomialnumerator[1]}{\polynomialdenominator} +\stopformula + +\startformula +\polynomial + [alternative=complete, + color={1={n=red,d=green,q=blue},2={n=cyan,d=magenta,q=orange,ds=darkgray}}] + [7, -5, 2, 3, 2] + [3, 0, 1] +\stopformula + +% \ifpolynomialclipped1 YES \else NOP \fi + +\dorecurse\polynomialsteps{ + \startformula + \polynomialstep[#1] + \stopformula +} + +% \input tufte + +% \startformula +% \denominator +% \numerator[2] +% \frac{3x^3+2x^2-5x+7}{x^2+3} +% \alignhere +% = 3x + \frac{2x^2 - 14x + 7}{x^2+3} +% \breakhere +% = 3x + 2 + \frac{-14x+1}{x^2+3} +% \stopformula + +% \input tufte + +% \startformula +% \frac{3x^3+2x^2-5x+7}{x^2+3} +% \alignhere +% = 3x + \frac{2x^2 - 14x + 7}{x^2+3} +% \breakhere +% = 3x + 2 + \frac{-14x+1}{x^2+3} +% \stopformula + +% \input tufte + +% \TestPolynomials +% {-5, -3, 3, -1, 1, 0, 2, -3, -2, -1, 4} +% {-8, -7, -5, 2, 8, -9, 1} + +% \TestPolynomials +% {-1, 0, 1} +% {-1, 1} + +% \input tufte + +% \TestPolynomials +% {-1, 1} +% {-1, 0, 1} + +% \input tufte + +\stoptext |