math-ali.lmt /size: 8692 b    last modification: 2024-01-16 10:22
1if not modules then modules = { } end modules ['math-ali'] = {
2    version   = 1.001,
3    comment   = "companion to math-ali.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local unpack = unpack
10local gsub = string.gsub
11local sort, keys = table.sort, table.keys
12local settings_to_array = utilities.parsers.settings_to_array
13local P, R, S, C, Cc, Ct, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cs
14local lpegmatch = lpeg.match
15
16local context = context
17
18do
19
20    local rows = utilities.parsers.groupedsplitat(";")
21    local cols = utilities.parsers.groupedsplitat(",")
22
23    local actions = {
24        transpose = function(m)
25            local t = { }
26            for j=1,#m[1] do
27                local r = { }
28                for i=1,#m do
29                    r[i] = m[i][j]
30                end
31                t[j] = r
32            end
33            return t
34        end,
35        negate = function(m)
36            for i=1,#m do
37                local mi = m[i]
38                for j=1,#mi do
39                    mi[j] = - mi[j]
40                end
41            end
42            return m
43        end,
44        scale = function(m,s)
45            s = tonumber(s)
46            if s then
47                for i=1,#m do
48                    local mi = m[i]
49                    for j=1,#mi do
50                        mi[j] = s*mi[j]
51                    end
52                end
53            end
54            return m
55        end,
56    }
57
58    local useractions = {
59    }
60
61    interfaces.implement {
62        name      = "simplematrix",
63        arguments = "2 strings",
64        actions   = function(method,data)
65            local m = lpegmatch(rows,(gsub(data,"%s+"," ")))
66            for i=1,#m do
67                m[i] = lpegmatch(cols,m[i])
68            end
69            local methods = settings_to_array(method)
70            for i=1,#methods do
71                local detail = settings_to_array(methods[i])
72                local method = detail[1]
73                local action = actions[method] or useractions[method]
74                if action then
75                    m = action(m,unpack(detail,2)) or m
76                end
77            end
78            for i=1,#m do
79                context("\\NC %{ \\NC }t \\NR",m[i])
80            end
81        end
82    }
83
84    function mathematics.registersimplematrix(name,action)
85        if type(action) == "function" then
86            useractions[name] = action
87        end
88    end
89
90    -- \cases{1, x>0 ; -1, x<0 }
91
92    interfaces.implement {
93        name      = "simplecases",
94        arguments = "2 strings",
95        actions   = function(method,data)
96            -- no methods yet
97            local m = lpegmatch(rows,(gsub(data,"%s+"," ")))
98            for i=1,#m do
99                m[i] = lpegmatch(cols,m[i])
100            end
101            for i=1,#m do
102                context("\\NC %{ \\NC }t \\NR",m[i])
103            end
104        end
105    }
106
107end
108
109do
110
111    local relations = {
112        ["<"]   = "<", [">"]   = ">",
113        ["!<"]  = "", ["!>"]  = "",
114        ["<<"]  = "", [">>"] = "",
115        ["="]   = "=", ["=="]  = "=",
116        ["<>"]  = "", ["!="]  = "",
117        ["<="]  = "", [">="]  = "",
118        ["=<"]  = "", ["=>"]  = "",
119        ["!=<"] = "", ["!=>"] = "",
120        ["~"]   = "", ["~~"]  = "",
121    }
122
123    for k, v in next, table.copy(relations) do relations[v] = v end
124
125 -- local binaries = {
126 --     ["+"] = "+",
127 --     ["-"] = "-",
128 --     ["/"] = "/",
129 --     ["*"] = "",
130 -- }
131
132    local separators = {
133        [","] = true,
134        [";"] = true,
135    }
136
137    local alternatives = {
138        -- not that many
139    }
140
141    local p_sign     = S("-+")
142    local p_script   = S("^")^1
143    local p_number   = R("09","..")^1 + lpeg.patterns.nestedbraces
144    local p_alpha    = R("az","AZ")^1
145    local p_variable = p_alpha * (P("_") * (p_number + p_alpha))^-1
146
147    local spacing    = P(" ")^0
148    local script     = Cs(p_script * Cc("{") * p_sign^0 * (p_number + p_variable) * Cc("}"))
149    local sign       = C(p_sign) + Cc("+")
150    local number     = C(p_number)
151    local variable   = C(p_variable)
152 -- local binary     = lpeg.utfchartabletopattern(binaries) / binaries
153    local relation   = lpeg.utfchartabletopattern(relations) / relations
154    local separator  = lpeg.utfchartabletopattern(separators)
155
156    local snippet = Ct (
157        (
158              spacing * sign * spacing * number    * spacing * variable
159            + spacing * sign * spacing * number    * spacing * Cc(false)
160            + spacing * sign * spacing * Cc(false) * spacing * variable
161        ) * (script + Cc(false))
162    )
163
164    local parser = Ct ( Ct (
165        ( Ct ( snippet^1 ) * spacing * relation    )^1
166      * ( Ct ( snippet^1 ) * spacing * separator^0 )
167    )^1 )
168
169    local num = "!"
170
171    local ctx_NC, ctx_NR = context.NC, context.NR
172    local ctx_typ = context.typ
173    local ctx_ord, ctx_rel = context.mathord, context.mathrel
174
175    local clean = table.setmetatableindex(function(t,k)
176        local v = gsub(k,"[{}]","")
177        t[k] = v
178        return v
179    end)
180
181    alternatives.equationsystem = function(action,str)
182        local rows = lpegmatch(parser,str)
183        if not rows then
184            ctx_typ("bad system, case 1: %s",1,str)
185            return
186        end
187        local nrow = #rows
188        local all = table.setmetatableindex("table")
189        for r=1,nrow do
190            local row = rows[r]
191            for s=1,#row,2 do
192                local set = row[s]
193                for v=1,#set do
194                    local vvv = set[v]
195                    local var = vvv[3]
196                    if not var then
197                        var = num
198                    end
199                    if set[var] then
200                        print("bad system, two constants")
201                    end
202                    set[var] = set[v]
203                    all[s][var] = true
204                    set[v] = nil
205                end
206            end
207        end
208        --
209        local cnt = #rows[1]
210        for r=1,nrow do
211            if #rows[r] ~= cnt then
212                ctx_typ("bad system, case %i: %s",2,str)
213                return
214            end
215        end
216        for r=1,#rows[1] do
217            local a = keys(all[r])
218            sort(a,function(a,b)
219                return clean[a] < clean[b]
220            end)
221            all[r] = a
222        end
223        --
224        for r=1,nrow do
225            local row = rows[r]
226            for r=1,#row do
227                local set = row[r]
228                local how = all[r]
229                if #how > 0 then
230                 -- local done = false
231                    for i=1,#how do
232                        local k = how[i]
233                        local e = set[k]
234                        if e then
235                            ctx_NC()
236                         -- if not done and e[1] == "+" then
237                            if i == 1 and e[1] == "+" then
238                             -- ctx_ord("")
239                             -- ctx_hphantom(e[1])
240                             -- ctx_ord("")
241                            else
242                                ctx_ord("")
243                                context(e[1])
244                                ctx_ord("")
245                             -- done = true
246                            end
247                            ctx_NC()
248                            if e[2] then
249                                context(e[2])
250                             -- done = true
251                            end
252                            if e[3] then
253                                context(e[3])
254                             -- done = true
255                            end
256                            if e[4] then
257                                context(e[4])
258                             -- done = true
259                            end
260                        else
261                            ctx_NC()
262                         -- ctx_mathord("")
263                            ctx_NC()
264                        end
265                    end
266                else
267                    ctx_NC()
268                    ctx_ord("")
269                    context(set)
270                    ctx_ord("")
271                end
272            end
273            ctx_NR()
274        end
275    end
276
277    interfaces.implement {
278        name      = "simplealign",
279     -- public    = true,
280        protected = true,
281        arguments = "3 strings",
282        actions   = function(alternative,action,str)
283            local a = alternatives[alternative]
284            if a then
285                a(action,str)
286            else
287                context(str)
288            end
289        end
290    }
291
292end
293