m-matrix.mkiv /size: 22 Kb    last modification: 2023-12-21 09:45
1%D \module
2%D   [       file=m-matrix,
3%D        version=2014.11.04, % already a year older
4%D          title=\CONTEXT\ Extra Modules,
5%D       subtitle=Matrices,
6%D         author={Jeong Dalyoung \& Hans Hagen},
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14%D This code is based on a post by Dalyoung on the context list. After that
15%D we turned it into a module and improved the code a bit. Feel free to ask
16%D us for more. Once we're satisfied, a more general helper l-matrix could
17%D be made. Dalyoung does the clever bits, and Hans only cleanes up and
18%D optimizes a bit.
19
20% \registerctxluafile{l-matrix}{} % not yet
21
22\startmodule[matrix]
23
24\startluacode
25
26local tonumber, type = tonumber, type
27
28local settings_to_hash = utilities.parsers.settings_to_hash
29local formatters       = string.formatters
30local copy             = table.copy
31local insert           = table.insert
32local remove           = table.remove
33local random           = math.random
34
35local context          = context
36
37local matrix      = { }
38moduledata.matrix = matrix
39
40local f_matrix_slot = formatters["%s_{%s%s}"]
41
42function matrix.symbolic(sym, x, y, nx ,ny) -- symMatrix("a", "m", "n")
43    local nx = nx or 2
44    local ny = ny or nx
45    local function filled(i,y)
46        local mrow = { }
47        for j=1,nx do
48            mrow[#mrow+1] = f_matrix_slot(sym,i,j)
49        end
50        mrow[#mrow+1] = "\\cdots"
51        mrow[#mrow+1] = f_matrix_slot(sym,i,y)
52        return mrow
53    end
54    local function dummy()
55        local mrow = { }
56        for j=1,nx do
57            mrow[#mrow+1] = "\\vdots"
58        end
59        mrow[#mrow+1] = "\\ddots"
60        mrow[#mrow+1] = "\\vdots"
61        return mrow
62    end
63    --
64    local mm = { }
65    for i=1,ny do
66        mm[i] = filled(i,y)
67    end
68    mm[#mm+1] = dummy()
69    mm[#mm+1] = filled(x,y)
70    return mm
71end
72
73-- todo: define a matrix at the tex end so that we have more control
74
75-- local fences = {
76--     parentheses = { left = "\\left(\\,", right = "\\,\\right)" },
77--     brackets    = { left = "\\left[\\,", right = "\\,\\right]" },
78--     bars        = { left = "\\left|\\,", right = "\\,\\right|" },
79-- }
80
81local fences = {
82    parentheses = { "matrix:parentheses" },
83    brackets    = { "matrix:brackets" },
84    bars        = { "matrix:bars" },
85}
86
87-- one can add more fences
88
89fences.bar         = fences.bars
90fences.parenthesis = fences.parentheses
91fences.bracket     = fences.brackets
92
93-- one can set the template
94
95matrix.template    = "%0.3F"
96
97function matrix.typeset(m,options)
98    if type(m) == "table" then
99        local options  = settings_to_hash(options or "")
100        local whatever = options.determinant == "yes" and fences.bars or fences.parentheses
101        if options.fences then
102            whatever = fences[options.fences] or whatever
103        elseif options.determinant then
104         -- whatever = fences.brackets
105            whatever = fences.bars
106        end
107        local template = options.template or matrix.template
108        if template == "yes" then
109            template = matrix.template
110        elseif template == "no" then
111            template = false
112        elseif tonumber(template) then
113            template = "%0." .. template .. "F"
114        end
115        context.startnamedmatrix(whatever)
116            if type(m[1]) ~= "table" then
117                m = { copy(m) }
118            end
119            for i=1,#m do
120                local mi = m[i]
121                for j=1,#mi do
122                    context.NC()
123                    local n = mi[j]
124                    if template and tonumber(n) then
125                        context(template,n)
126                    else
127                        context(mi[j])
128                    end
129                end
130                context.NR()
131            end
132        context.stopnamedmatrix()
133    elseif m then
134        context(m)
135    end
136end
137
138function matrix.swaprows(t,i,j)
139    local ti = t[i]
140    if not ti then
141        return "error: no row"
142    end
143    local tj = t[j]
144    if not tj then
145        return "error: no row"
146    end
147    t[i], t[j] = tj, ti
148    return t
149end
150
151-- interchange two columns (i-th, j-th)
152
153function matrix.swapcolumns(t, i, j)
154    local t1 = t[1]
155    if not t1 then
156        return "error: no rows"
157    end
158    local n = #t1
159    if i > n or j > n then
160        return "error: no column"
161    end
162    for k = 1, #t do
163        local tk = t[k]
164        tk[i], tk[j] = tk[j], tk[i]
165    end
166    return t
167end
168
169matrix.swapC       = matrix.swapcolumns
170matrix.swapR       = matrix.swaprows
171matrix.swapcolumns = matrix.swapcolumns
172matrix.swaprows    = matrix.swaprows
173matrix.swap        = matrix.swaprows
174
175-- replace i-th row with factor * (i-th row)
176
177function matrix.multiply(m,i,factor)
178    local mi = m[i]
179    for k=1,#mi do
180        mi[k] = factor * mi[k]
181    end
182    return m
183end
184
185-- scalar product "factor * m"
186
187function matrix.scalar(m, factor)
188    for i=1,#m do
189        local mi = m[i]
190        for j=1,#mi do
191            mi[j] = factor * mi[j]
192        end
193    end
194    return m
195end
196
197-- replace i-th row with i-th row + factor * (j-th row)
198
199function matrix.sumrow(m,i,j,factor)
200    local mi = m[i]
201    local mj = m[j]
202    for k=1,#mi do
203        mi[k] = mi[k] + factor * mj[k]
204    end
205end
206
207-- transpose of a matrix
208
209function matrix.transpose(m)
210    local t = { }
211    for j=1,#m[1] do
212        local r = { }
213        for i=1,#m do
214            r[i] = m[i][j]
215        end
216        t[j] = r
217    end
218    return t
219end
220
221-- inner product of two vectors
222
223function matrix.inner(u,v)
224    local nu = #u
225    if nu == 0 then
226        return 0
227    end
228    local nv = #v
229    if nv ~= nu then
230       return "error: size mismatch"
231    end
232    local result = 0
233    for i=1,nu do
234        result = result + u[i] * v[i]
235    end
236    return result
237end
238
239-- product of two matrices
240
241function matrix.product(m1,m2)
242    if #m1[1] == #m2 then
243        local product = { }
244        for i=1,#m1 do
245            local m1i  = m1[i]
246            local mrow = { }
247            for j=1,#m2[1] do
248                local temp = 0
249                for k=1,#m1[1] do
250                    temp = temp + m1i[k] * m2[k][j]
251                end
252                mrow[j] = temp
253            end
254            product[i] = mrow
255        end
256        return product
257    else
258        return "error: size mismatch"
259    end
260end
261
262local function uppertri(m,sign)
263    local temp = copy(m)
264    for i=1,#temp-1 do
265        local pivot = temp[i][i]
266        if pivot == 0 then
267            local pRow = i +1
268            while temp[pRow][i] == 0 do
269                pRow = pRow + 1
270                if pRow > #temp then -- if there is no nonzero number
271                    return temp
272                end
273            end
274            temp[i], temp[pRow] = temp[pRow], temp[i]
275            if sign then
276                sign = -sign
277            end
278        end
279        local mi = temp[i]
280        for k=i+1, #temp do
281            local factor = -temp[k][i]/mi[i]
282            local mk = temp[k]
283            for l=i,#mk do
284                mk[l] = mk[l] + factor * mi[l]
285            end
286        end
287    end
288    if sign then
289        return temp, sign
290    else
291        return temp
292    end
293end
294
295matrix.uppertri = uppertri
296
297local function determinant(m)
298    if #m == #m[1] then
299        local d = 1
300        local t, s = uppertri(m,1)
301        for i=1,#t do
302            d = d * t[i][i]
303        end
304        return s*d
305    else
306        return "error: not a square matrix"
307    end
308end
309
310matrix.determinant = determinant
311
312local function rowechelon(m,r)
313    local temp = copy(m)
314    local pRow = 1
315    local pCol = 1
316    while pRow <=  #temp  do
317        local pivot = temp[pRow][pCol]
318        if  pivot == 0 then
319            local i = pRow
320            local n = #temp
321            while temp[i][pCol] == 0 do
322                i = i + 1
323                if i > n then
324                    -- no nonzero number in a column
325                    pCol = pCol + 1
326                    if pCol > #temp[pRow] then
327                        -- there is no nonzero number in a row
328                        return temp
329                    end
330                    i = pRow
331                end
332            end
333            temp[pRow], temp[i] = temp[i], temp[pRow]
334        end
335        local row = temp[pRow]
336        pivot = row[pCol]
337        for l=pCol,#row do
338            row[l] = row[l]/pivot
339        end
340
341        if r == 1 then
342            -- make the "reduced row echelon form"
343            local row = temp[pRow]
344            for k=1,pRow-1 do
345                local current = temp[k]
346                local factor  = -current[pCol]
347                local mk      = current
348                for l=pCol,#mk do
349                    mk[l] = mk[l] + factor * row[l]
350                end
351            end
352        end
353        -- just make the row echelon form
354        local row = temp[pRow]
355        for k=pRow+1, #temp do
356            local current = temp[k]
357            local factor  = -current[pCol]
358            local mk      = current
359             for l=pCol,#mk do
360                mk[l] = mk[l] + factor * row[l]
361            end
362        end
363        pRow = pRow + 1
364        pCol = pCol + 1
365
366        if pRow > #temp or pCol > #temp[1] then
367            pRow = #temp + 1
368        end
369    end
370    return temp
371end
372
373matrix.rowechelon = rowechelon
374matrix.rowEchelon = rowechelon
375
376-- make matrices until its determinant is not 0
377
378local function make(m,n,low,high) -- m and n swapped
379    if not n then
380        n = 10
381    end
382    if not m then
383        m = 10
384    end
385    if not low then
386        low = 0
387    end
388    if not high then
389        high = 10
390    end
391    local t = { }
392    for i=1,m do
393        t[i] = { }
394    end
395    while true do
396        for i=1,m do
397            local ti = t[i]
398            for j=1,n do
399                ti[j] = random(low,high)
400            end
401        end
402        if n ~= m or determinant(t,1) ~= 0 then
403            return t
404        end
405    end
406end
407
408matrix.make  = make
409matrix.makeR = matrix.make
410
411-- extract submatrix by using
412
413local function submatrix(t,i,j)
414    local rows    = #t
415    local columns = #t[1]
416    local sign    = 1 -- not used
417    if i <= rows and j <= columns then
418        local c = copy(t)
419        remove(c,i)
420        for k=1,rows-1 do
421            remove(c[k],j)
422        end
423        return c
424    else
425        return "error: out of bound"
426    end
427end
428
429matrix.submatrix = submatrix
430matrix.subMatrix = submatrix
431
432-- calculating determinant using Laplace Expansion
433
434local function laplace(t) -- not sure if this is the most effient but
435    local factors = { 1 }  -- it's not used for number crunching anyway
436    local data    = copy(t)
437    local det     = 0
438    while #data > 0 do
439        local mat = { }
440        local siz = #data[1]
441        if siz == 0 then
442            return "error: no determinant"
443        elseif siz == 1 then
444            det = data[1][1]
445            return det
446        end
447        for i=1,siz do
448            mat[i] = data[1]
449            remove(data,1)
450        end
451        local factor = remove(factors,1)
452        local m1 = mat[1]
453        if siz == 2 then
454            local m2 = mat[2]
455            det = det + factor * (m1[1]*m2[2] - m1[2]*m2[1])
456        else
457            for j=1,#m1 do
458                local m1j = m1[j]
459                if m1j ~= 0 then
460                    insert(factors, (-1)^(j+1) * factor * m1j)
461                    local m = submatrix(mat,1,j)
462                    for k, v in next, m do
463                         insert(data,v)
464                    end
465                end
466            end
467        end
468    end
469    return det
470end
471
472matrix.laplace = laplace
473
474--  solve the linear equation m X = c
475
476local function solve(m,c)
477    local n = #m
478    if n ~= #c then
479     -- return "error: size mismatch"
480        return nil
481    end
482    local newm = copy(m)
483    local temp = copy(c)
484    local solution = copy(c)
485    for i=1,n do
486        insert(newm[i],temp[i])
487    end
488    newm = uppertri(newm, 0)
489    for k = n,1,-1 do
490        local val = 0
491        local new = newm[k]
492        for j = k+1, n do
493            val = val + new[j] * solution[j]
494        end
495        if new[k] == 0 then
496         -- return "error: no unique solution"
497            return nil
498        else
499            solution[k] =  (new[n+1] - val)/new[k]
500        end
501    end
502    return solution
503end
504
505matrix.solve = solve
506
507-- find the inverse matrix of m
508
509local function inverse(m)
510    local n = #m
511    local temp = copy(m)
512    if n ~= #m[1] then
513        return temp
514    end
515    for i=1,n do
516        for j=1,n do
517            insert(temp[i],j == i and 1 or 0)
518        end
519    end
520    temp = rowechelon(temp,1)
521    for i=1,n do
522        for j=1,n do
523            remove(temp[i], 1)
524        end
525    end
526    return temp
527end
528
529matrix.inverse = inverse
530
531-- create zero and identity matrix
532
533local function makeM(k,v)
534    local tt = { }
535    for i=1,k do
536        local temp = { }
537        for j=1,k do
538            temp[j] = 0
539        end
540        tt[i] = temp
541    end
542    if v and v > 0 then
543        for i=1,k do
544            tt[i][i] = 1
545        end
546    end
547    return tt
548end
549
550matrix.makeM        = makeM
551matrix.makeidentity = makeM
552matrix.makezero     = makeM
553
554-- append the rows of the second matrix  to the bottom of the first matrix
555
556local function joinrows(t1, t2)
557    local nt1 = #t1
558    local nt2 = #t2
559    if (nt1*nt2 > 0) and (#t1[1] ~= #t2[1]) then
560        return "error: different number of columns"
561    else
562        for i=1,nt2 do
563            t1[nt1+i] = t2[i]
564        end
565        return t1
566    end
567end
568
569matrix.joinrows = joinrows
570matrix.joinRows = joinrows
571
572-- append the columns of the second matrix  to the right of the first matrix
573
574local function joincolumns(t1, t2)
575    local nt1 = #t1
576    local nt2 = #t2
577    if nt1 == 0 then
578        return t2
579    end
580    if nt2 == 0 then
581        return t1
582    end
583    if nt1 ~= nt2 then
584        return "error: different number of rows"
585    end
586    nt3 = #t2[1]
587    for i=1,nt1 do
588        local temp = t2[i]
589        for j= 1, nt3 do
590            insert(t1[i],temp[j])
591        end
592    end
593    return t1
594end
595
596matrix.joincolumns = joincolumns
597matrix.joinColumns = joincolumns
598
599\stopluacode
600
601\stopmodule
602
603\unexpanded\def\ctxmodulematrix#1{\ctxlua{moduledata.matrix.#1}}
604
605\continueifinputfile{m-matrix.mkiv}
606
607\usemodule[m-matrix]
608\usemodule[art-01]
609
610\starttext
611
612\startluacode
613document.DemoMatrixA = {
614    { 0, 2,  4, -4, 1 },
615    { 0, 0,  2,  3, 4 },
616    { 2, 2, -6,  2, 4 },
617    { 2, 0, -6,  9, 7 },
618    { 2, 3,  4,  5, 6 },
619    { 6, 6, -6,  6, 6 },
620}
621
622document.DemoMatrixB = {
623    { 0, 2,  4, -4, 1 },
624    { 0, 0,  2,  3, 4 },
625    { 2, 2, -6,  3, 4 },
626    { 2, 0, -6,  9, 7 },
627    { 2, 2, -6,  2, 4 },
628}
629
630document.DemoMatrixC = {
631    {  3, 3, -1,  3 },
632    { -1, 4,  1,  3 },
633    {  5, 4,  0,  2 },
634    {  2, 4,  0, -1 },
635}
636\stopluacode
637
638\startbuffer[demo]
639\typebuffer
640\startalignment[middle]
641    \dontleavehmode\inlinebuffer
642\stopalignment
643\stopbuffer
644
645\setuphead[section][before={\testpage[5]\blank[2*big]}]
646
647\startsubject[title={A symbolic matrix}]
648
649\startbuffer
650\ctxmodulematrix{typeset(moduledata.matrix.symbolic("a", "m", "n"))}
651$\qquad\qquad$
652\ctxmodulematrix{typeset(moduledata.matrix.symbolic("a", "m", "n", 4, 8))}
653\stopbuffer
654
655\getbuffer[demo]
656
657\stopsubject
658
659\startsubject[title={Generate a new $m \times n$ matrix}]
660
661\startbuffer
662\startluacode
663    moduledata.matrix.typeset(moduledata.matrix.makeR(4,3, 0,5))
664    context.qquad()
665    context("\\qquad")
666    moduledata.matrix.typeset(moduledata.matrix.makeR(5,5,-1,5))
667\stopluacode
668\stopbuffer
669
670\getbuffer[demo]
671
672\stopsubject
673
674\startsubject[title={Swap two rows (ex: 2 and 4)}]
675
676\startbuffer
677\startluacode
678    moduledata.matrix.typeset(document.DemoMatrixA)
679    context("$\\qquad \\Rightarrow \\qquad$")
680    moduledata.matrix.typeset(moduledata.matrix.swaprows(document.DemoMatrixA,2,4))
681\stopluacode
682\stopbuffer
683
684\getbuffer[demo]
685
686\stopsubject
687
688\startsubject[title={Swap two columns (ex: 1 and 3)}]
689
690\startbuffer
691\startluacode
692    moduledata.matrix.typeset(document.DemoMatrixA)
693    context("$\\qquad \\Rightarrow \\qquad$")
694    moduledata.matrix.typeset(moduledata.matrix.swapcolumns(document.DemoMatrixA,1, 3))
695\stopluacode
696\stopbuffer
697
698\getbuffer[demo]
699
700\stopsubject
701
702\startsubject[title={Multiply 3 to row 2($3 \times r_2$)}]
703
704\startbuffer
705\startluacode
706    moduledata.matrix.typeset(document.DemoMatrixA)
707    context("$\\qquad \\Rightarrow \\qquad$")
708    moduledata.matrix.typeset(moduledata.matrix.multiply(document.DemoMatrixA,2,3))
709\stopluacode
710\stopbuffer
711
712\getbuffer[demo]
713
714\stopsubject
715
716\startsubject[title={Add 4 times of row 3 to row 2($r_2 + 4 \times r_3$)}]
717
718\startbuffer
719\startluacode
720    moduledata.matrix.typeset(document.DemoMatrixA)
721    context("$\\qquad \\Rightarrow \\qquad$")
722    moduledata.matrix.sumrow(document.DemoMatrixA,2,3,4)
723    moduledata.matrix.typeset(document.DemoMatrixA)
724\stopluacode
725\stopbuffer
726
727\getbuffer[demo]
728
729\stopsubject
730
731\startsubject[title={Transpose a matrix}]
732
733\startbuffer
734\startluacode
735    moduledata.matrix.typeset(document.DemoMatrixA)
736    context("$\\qquad \\Rightarrow \\qquad$")
737    moduledata.matrix.typeset(moduledata.matrix.transpose(document.DemoMatrixA))
738\stopluacode
739\stopbuffer
740
741\getbuffer[demo]
742
743\stopsubject
744
745\startsubject[title={The inner product of two vectors}]
746
747\startbuffer
748\startluacode
749    context("$<1,2,3> \\cdot <3,1,2> \\ =\\ $ ")
750    context( moduledata.matrix.inner({ 1, 2, 3 }, { 3, 1, 2 }))
751\stopluacode
752\stopbuffer
753
754\getbuffer[demo]
755
756\startbuffer
757\startluacode
758context("$<1,2,3> \\cdot <3,1,2, 4> \\ =\\ $ ")
759context(moduledata.matrix.inner({ 1, 2, 3 }, { 3, 1, 2, 4 }))
760\stopluacode
761\stopbuffer
762
763\getbuffer[demo]
764
765\stopsubject
766
767\startsubject[title={The product of two matrices}]
768
769\startbuffer
770\startluacode
771    context("$\\ $")
772    moduledata.matrix.typeset(document.DemoMatrixB)
773    context("$\\cdot$")
774    moduledata.matrix.typeset(document.DemoMatrixA)
775    context("$ = $")
776    moduledata.matrix.typeset(moduledata.matrix.product
777        (document.DemoMatrixB,document.DemoMatrixB))
778\stopluacode
779\stopbuffer
780
781\getbuffer[demo]
782
783\stopsubject
784
785\startsubject[title={An Upper Triangular Matrix}]
786
787\startbuffer
788\startluacode
789    moduledata.matrix.typeset(document.DemoMatrixB)
790    context("$\\qquad \\Rightarrow \\qquad$")
791    moduledata.matrix.typeset(moduledata.matrix.uppertri(document.DemoMatrixB))
792\stopluacode
793\stopbuffer
794
795\getbuffer[demo]
796
797\stopsubject
798
799\startsubject[title={Determinant: using triangulation}]
800
801\startbuffer
802\startluacode
803    local m = {
804        { 1, 2,  4 },
805        { 0, 0,  2 },
806        { 2, 2, -6 },
807        { 2, 2, -6 },
808    }
809    moduledata.matrix.typeset(m, {fences="bars"})
810    context("$\\qquad = \\qquad$")
811    context(moduledata.matrix.determinant(m))
812\stopluacode
813\stopbuffer
814
815\getbuffer[demo]
816
817\startbuffer
818\startluacode
819    moduledata.matrix.typeset(document.DemoMatrixC, { fences = "bars" })
820    context("$\\qquad = \\qquad$")
821    context(moduledata.matrix.determinant(document.DemoMatrixC))
822\stopluacode
823\stopbuffer
824
825\getbuffer[demo]
826
827\stopsubject
828
829\startsubject[title={Determinant: using Laplace Expansion}]
830
831\startbuffer
832\startluacode
833    moduledata.matrix.typeset(document.DemoMatrixC, { fences = "bars" })
834    context("$\\qquad = \\qquad$")
835    context(moduledata.matrix.laplace(document.DemoMatrixC))
836\stopluacode
837\stopbuffer
838
839\getbuffer[demo]
840
841\stopsubject
842
843\startsubject[title={Example of Laplace Expansion using submatrix function}]
844
845\startbuffer
846\startluacode
847    local m = {
848        { 1, 5, 4, 2 },
849        { 5, 2, 0, 4 },
850        { 2, 2, 1, 1 },
851        { 1, 0, 0, 5 },
852    }
853    local options = {fences = "bars"}
854
855    moduledata.matrix.typeset(m,options)
856    context("\\par $=$")
857    for j = 1, #m[1] do
858        local mm =  moduledata.matrix.submatrix(m, 1, j)
859        local factor = (-1)^(1+j) *(m[1][j])
860        context("\\ ($%d$) \\cdot ", factor)
861        moduledata.matrix.typeset(mm, options)
862        if j < #m[1] then
863            context("\\ $+$ ")
864        end
865    end
866\stopluacode
867\stopbuffer
868
869\getbuffer[demo]
870
871\stopsubject
872
873\startsubject[title={Row echelon form}]
874
875\startbuffer
876\startluacode
877    local m = {
878        { 1, 3, -2,  0, 2,  0,  0 },
879        { 2, 6, -5, -2, 4, -3, -1 },
880        { 0, 0,  5, 10, 0, 15,  5 },
881        { 2, 6,  0,  8, 4, 18,  6 },
882    }
883    moduledata.matrix.typeset(m)
884    context("$\\Rightarrow$")
885    moduledata.matrix.typeset(moduledata.matrix.rowechelon(m,1))
886\stopluacode
887\stopbuffer
888
889\getbuffer[demo]
890
891\stopsubject
892
893\startsubject[title={Solving linear equation}]
894
895\startbuffer
896\startluacode
897    local m = {
898        {  1,  3, -2,  0 },
899        {  2,  0,  1,  2 },
900        {  6, -5, -2,  4 },
901        { -3, -1,  5, 10 },
902    }
903
904    local c = { 5, 2, 6, 8 }
905
906    moduledata.matrix.typeset(moduledata.matrix.solve(m,c))
907    context.blank()
908    moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = 6 })
909    context.blank()
910    moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = "no" })
911    context.blank()
912    moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = "%0.3f" })
913    context.blank()
914    moduledata.matrix.typeset(moduledata.matrix.solve(m,c), { template = "%0.4F" })
915\stopluacode
916\stopbuffer
917
918\getbuffer[demo]
919
920\stopsubject
921
922\startsubject[title={Inverse matrix}]
923
924\startbuffer
925\startluacode
926    local m = {
927        { 1, 1, 1 },
928        { 0, 2, 3 },
929        { 3, 2, 1 },
930    }
931    context("$A =\\quad$")
932    moduledata.matrix.typeset(m)
933    context("$\\qquad A^{-1} = \\quad$")
934    moduledata.matrix.typeset(moduledata.matrix.inverse(m))
935    context("\\blank\\ ")
936    moduledata.matrix.typeset(m)
937    context("$\\cdot$")
938    moduledata.matrix.typeset(moduledata.matrix.inverse(m))
939    context("$ = $")
940    moduledata.matrix.typeset(moduledata.matrix.product(m, moduledata.matrix.inverse(m)))
941\stopluacode
942\stopbuffer
943
944\getbuffer[demo]
945
946\stopsubject
947
948\startsubject[title={make matrices(zero, identiry, random}]
949
950\startbuffer
951\startluacode
952    moduledata.matrix.typeset(moduledata.matrix.makeM(3, 0))
953    context.qquad()
954    moduledata.matrix.typeset(moduledata.matrix.makeM(3, 1))
955    context.qquad()
956    moduledata.matrix.typeset(moduledata.matrix.makeR(4,3))
957\stopluacode
958\stopbuffer
959
960\getbuffer[demo]
961
962\stopsubject
963
964\startsubject[title={join rows, join columns}]
965
966\startbuffer
967\startluacode
968    local mat1 = moduledata.matrix.makeR(3, 4)
969    local mat2 = moduledata.matrix.makeR(4, 3)
970
971    context("Appending as columns: ")
972    context.blank()
973    moduledata.matrix.typeset(mat1)
974    context("$\\&$")
975    moduledata.matrix.typeset(mat1)
976    context("\\quad $\\Rightarrow$ \\quad")
977    moduledata.matrix.joinColumns(mat1, mat1)
978    moduledata.matrix.typeset(mat1)
979    context.blank()
980    context("Appending as rows: ")
981    context.blank()
982    moduledata.matrix.typeset(mat2)
983    context("$\\&$")
984    moduledata.matrix.typeset(mat2)
985    context("\\quad $\\Rightarrow$ \\quad")
986    moduledata.matrix.joinRows(mat2, mat2)
987    moduledata.matrix.typeset(mat2)
988\stopluacode
989\stopbuffer
990
991\getbuffer[demo]
992
993\stoptext
994