我希望能够创建一个宏来使用 lua 模块乘以矩阵。模块在这里:
https://raw.github.com/davidm/lua-matrix/master/lua/matrix.lua
正如我所建议的那样上一个问题 我把我的 lua 代码放在一个单独的 lua 文件中,dofiled
如下所示:
\documentclass{article}
\usepackage{xparse}
\usepackage{luacode}
\usepackage{fontspec}
\directlua{dofile("matrix.lua")}
\directlua{dofile("lua2.lua")}
\ExplSyntaxOn
\NewDocumentCommand{\matrixop}{ m m }
{
\luaexec{
matrop(#1,#2)
}
}
\ExplSyntaxOff
\begin{document}
\matrixop{{1,2,3},{4,5,6}}{{7,8,9},{10,11,12}}
\end{document}
该文件lua2.lua
包含以下内容:
function matrop (mat1, mat2)
local matrix = require 'matrix'
m1 = matrix {mat1}
m2 = matrix {mat2}
m3 = matrix.add(m1,m2)
a = matrix.latex(m3,c)
tex.print(a)
end
由此产生的问题是,在matrix.lua
矩阵中定义为例如
m = matrix{{1,2,3},{4,5,6}}
因此,我必须将其传递为mat1
类似于的内容{1,2,3},{4,5,6}
。但是,就目前情况而言,上面的代码matrop(#1,#2)
相当于
matrop({1,2,3},{4,5,6},{7,8,9},{10,11,12})
其中,分隔行的逗号mat1
对宏是可见的,因此matrop
可以看到 4 个逗号分隔的参数,而不是 2 个逗号分隔的参数。Lua 理解我在删除“额外”的两个参数后传递了一对单行矩阵(这花了很长时间才弄清楚)。在每个参数周围添加额外的括号来隐藏逗号是行不通的,因为它会搞乱matrix
预期的表。我的想法是用 替换分隔行的逗号*
,将其传递给matrop
,使用字符串在 lua 中将 恢复*
为逗号,将字符串转换回表,然后将其传递给矩阵命令(这需要大量阅读和摆弄,我根本不了解 lua)。结果如下:
\documentclass{article}
\usepackage{xparse}
\usepackage{luacode}
\usepackage{fontspec}
\directlua{dofile("matrix.lua")}
\directlua{dofile("lua2.lua")}
\ExplSyntaxOn
\NewDocumentCommand{\matrixop}{ m m }
{
% quotes are so that matrop sees args as strings
\luaexec{
matrop("{#1}","{#2}")
}
}
\ExplSyntaxOff
\begin{document}
% row separator now a *
\matrixop{{1,2,3}*{4,5,6}}{{7,8,9}*{10,11,12}}
\end{document}
其中lua2.lua
如下:
function matrop (mat1, mat2)
-- replace *'s with ,'s
s1 = string.gsub(mat1,"*",",")
s2 = string.gsub(mat2,"*",",")
-- functions that load resulting strings
f1 = assert(loadstring("return"..s1))
f2 = assert(loadstring("return"..s2))
-- t1 and t2 are now tables (as I understand it)
t1 = f1()
t2 = f2()
local matrix = require 'matrix'
-- pass table entries (rows) to matrix definers
m1 = matrix {t1[1],t1[2]}
m2 = matrix {t2[1],t2[2]}
m3 = matrix.add(m1,m2)
a = matrix.latex(m3,c)
tex.print(a)
end
我确信我上面做了很多不好/不恰当/可怕的事情。我的问题是:我到底应该怎么做?有没有一种简单的方法可以将定义矩阵所需的信息传递给 lua?欢迎提出任何建议、评论、提示、解决方案等。
答案1
如果您使用(IMHO)更用户友好的输入,类似于(a,b,c)(d,e,f),那么使用基本 lua 命令创建矩阵很容易,而无需知道矩阵的大小。
\documentclass{article}
\usepackage{xparse}
\usepackage{fontspec}
\usepackage{filecontents}
\begin{filecontents*}{luaFunctions.lua}
function matrop (mat1, mat2)
local matrix = require 'matrix'
m1 = matrix{unpack(CreateMatrix(mat1))}
m2 = matrix{unpack(CreateMatrix(mat2))}
m3 = matrix.add(m1,m2)
--tex.print("\\\\")
tex.sprint( matrix.latex(m1,c).."+")
tex.sprint( matrix.latex(m2,c).."=")
tex.sprint( matrix.latex(m3,c))
end
function CreateMatrix(str)
rows={}
-- get the elements between the braces
-- and execute the following function
string.gsub(str, "%((.-)%)",
function(sub)
-- for debugging
--tex.print("Row: "..sub.."\\\\")
-- split the string at ','
elements = string.explode(sub,",")
row={}
for i,e in ipairs(elements) do
-- remove spaces (not really necessary)
e = string.gsub(e," ","")
-- insert the element to the row-table
table.insert(row,e)
-- for debugging
--tex.print("Element :"..e.."\\\\")
end
-- insert the row-table to the rows-table
table.insert(rows,row)
end
)
return rows
end
\end{filecontents*}
\directlua{dofile("luaFunctions.lua")}
\ExplSyntaxOn
\NewDocumentCommand{\matrixop}{mm}{
\directlua{matrop("#1","#2")}}
\ExplSyntaxOff
\begin{document}\noindent
\matrixop{(-1)} {( 10)}\\[2ex]
%
\matrixop{(-1, -2, -3)} {( 10, 11, 12)}\\[2ex]
%
\matrixop{(-1, -2, -3)(4, 5, -6)}{(7, -98, 9) (10, 11, 12)}\\[2ex]
%
\matrixop{(-1, -2, -3, 4, 5, -6)(8, 4, 1, 6, 8, 3)} {(7, -98, 9, 10, 11, 12)(8, 4, 1, 6, 8, 3)}\\[2ex]
%
\matrixop{(-1, -2, -3)(4, 5, -6)(8, 4, 1)(6, 8, 3)} {(7, -98, 9) (10, 11, 12)(8, 4, 1)(6, 8, 3)}\\[2ex]
%
\matrixop{(-1, -2)( -3, 4)( 5, -6)(8, 4)( 1, 6)( 8, 3)} {(7, -98)( 9, 10)( 11, 12)(8, 4)( 1, 6)( 8, 3)}\\[2ex]
%
\matrixop{(-1)( -3)( 5)} {(7)( 9)( 11)}\\[2ex]
\end{document}
编辑 Matlab 样式:
如果您想使用类似于 Matlab 的矩阵输入,则可以使用以下函数。这里不需要使用包xparse
,也不需要知道用户为函数提供了多少个矩阵(及其维度)。
\documentclass{article}
\usepackage{fontspec}
\usepackage{filecontents}
\begin{filecontents*}{luaFunctions.lua}
function matropMatlab (mat)
local matrix = require 'matrix'
matrices = CreateMatrixMatlab(mat)
m1 = matrix{unpack(matrices[1])}
m2 = matrix{unpack(matrices[2])}
m3 = matrix.add(m1,m2)
tex.sprint( matrix.latex(m1,c).."+")
tex.sprint( matrix.latex(m2,c).."=")
tex.sprint( matrix.latex(m3,c))
end
function CreateMatrixMatlab(str)
matrices={}
string.gsub(str, "%[(.-)%]",
function(sub)
splitedRows = string.explode(sub,";")
rows={}
for i,sr in ipairs(splitedRows) do
elements = string.explode(sr)
row={}
for k,e in ipairs(elements) do
table.insert(row,e)
end
table.insert(rows,row)
end
table.insert(matrices,rows)
end
)
return matrices
end
\end{filecontents*}
\directlua{dofile("luaFunctions.lua")}
\def\matrixopMatlab#1{%
\directlua{matropMatlab("#1")}}
\begin{document}
\matrixopMatlab{
[16 3 2 13; 5 -10 11 8; 19 65 7 12; 41 15 -14 1]
[4 3 21 17; 5 14 11 23; 18 1 71 12; 24 15 44 14]}\\[2ex]
\matrixopMatlab{
[16 3 2 13 1; 5 -10 11 8 2; 19 65 7 12 3]
[4 3 21 17 1; 5 14 11 23 2; 18 1 71 12 3]}
\end{document}
答案2
这不是一个真正的答案(因为你已经分析了这个问题),而只是我的想法:
我认为你做得很好!如果你将宏扩展视为文本替换,问题可能会更加明显:
\NewDocumentCommand{\matrixop}{ m m }
{
\luaexec{
matrop(#1,#2)
}
}
本质上等同于
\def\matrixop#1#2{\luaexec{matrop(#1,#2)}
对吧?所以当你调用 时\matrixop{{1,2,3},{4,5,6}}{{7,8,9},{10,11,12}}
,#1
会得到{1,2,3},{4,5,6}
和#2
{7,8,9},{10,11,12}
(这就是你写的)。所以上面的替换文本\def
是:\luaexec{matrop(#1,#2)
-> ,一个带有四个参数的函数调用。如果你知道你总是用逗号分隔宏,那么你可以定义带有四个参数的\luaexec{matrop({1,2,3},{4,5,6},{7,8,9},{10,11,12})
函数:matrop()
function matrop (_1, _2, _3, _4)
m1 = matrix {_1,_2}
m2 = matrix {_3,_4}
m3 = matrix.add(m1,m2)
a = matrix.latex(m3,c)
tex.print(a)
end
我认为事实就是如此。
我不会选择你的第二种解决方案,因为它可能不安全(loadstring("return"..s1)
。如果它不能解析,你的代码就会崩溃。而且仅仅用一个分隔符替换另一个分隔符是不值得的(IMHO)。
答案3
感谢 Holle 和 Gundla 先生,这就是最终的结果。我想在这里分享它,因为我认为人们会发现它很有用:
以下是一个经过修改的 LaTeX 接口,用于 lua 矩阵计算模块。结果是可以在“文档中”执行矩阵计算。Matrixop.sty 提供了两个宏:\matrixop<args>
和\formatmatrix{matrix}
。其基本形式之一:
\matrixop{operation}{matrix1}{matrix2}
执行计算并排版操作和结果。例如,左侧的输入产生右侧的输出:
该模块提供的大多数操作matrix
都支持数字和符号形式:加法、减法、乘法、求逆、“除法”、行列式、向量标量和交叉积。有关详细信息,请将文件matrixop.sty
、matrix.lua
和matrixop.lua
放在matrixop-test.tex
同一目录中(或安装.sty
并将 lua 文件放在同一目录中)并matrixop-test.tex
使用进行编译lualatex
。
文件:matrixop.sty
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{matrixop}[2012/09/26 ver 1.0]
\RequirePackage{xparse}
\RequirePackage{fontspec}
\RequirePackage{mathtools}
\RequirePackage{geometry}
\DeclareMathOperator{\rref}{rref}
\directlua{dofile(kpse.find_file("matrixop.lua"))}
\directlua{dofile(kpse.find_file("matrix.lua"))}
\ExplSyntaxOn
\seq_new:N \g__matrop_symbops_seq
\seq_gset_split:Nnn \g__matrop_symbops_seq {,}{add,sub,mul,det,transpose,scalar,cross,add*,sub*,mul*,transpose*,cross*}
% Main Document Command: \matrixop
% - starred gives symbolic output
% - operation is first mandatory argument
% - operations are: add, sub, mul, div, invert, pow, root, det, dogauss, scalar and cross
% - starring the operation name, e.g \matrixop{mul*}... doesn't typeset operation but returns
% - the resulting matrix (not in useable form) in the macro \mout
% - root and pow require a numeric argument after the operation name giving the power/root, e.g. \matrixop{pow}[3]{matrix}
% - the final, optional, argument is the number of digits to round the output to
\NewDocumentCommand{\matrixop}{ s m o m g o }
{
\IfBooleanTF{#1}
{ % if star
\seq_if_in:NnTF \g__matrop_symbops_seq {#2}
{
\IfNoValueTF{#5}
{ % if unary
\directlua{matropsymb("#2","#4")}
}
{ % if binary
\directlua{matropsymb("#2","#4","#5")}
}
}
{
\msg_error:nnx {matrop} {Operation~not~compatible~with~symbolic} {#2}
}
}
{ % if no star
% if not root or pow
\IfNoValueTF{#3}
{ % if not binary
\IfNoValueTF{#5}
{ % if unary
% if not round
\IfNoValueTF{#6}
% then unary op, no round
{\directlua{matrop("#2","#4")}}
% then unary op, with round
{\directlua{matrop("#2","#4","#6")}}
}
{ % if binary
% if not round
\IfNoValueTF{#6}
% then binary, no round
{\directlua{matrop("#2","#4","#5")}}
% then binary, with round
{\directlua{matrop("#2","#4","#5","#6")}}
}
}
{ % root or pow
% if not round
\IfNoValueTF{#6}
% then root or pow, no round
{\directlua{matrop("#2","#3","#4")}}
% then root or pow, with round
{\directlua{matrop("#2","#3","#4","#6")}}
}
}
}
% This takes a macro that contains a matrix, and typesets the result.
% - first arg is optional to specify column justification
\NewDocumentCommand{\formatmatrix}{ O{r} m}
{
\matrixop_format:nn {#1}{#2}
}
% helper macro for the above
\cs_new:Npn \matrixop_format:nn #1#2
{
\tl_set:NV \l_tmpa_tl {#2}
\tl_replace_all:Nnn \l_tmpa_tl {)(}{\\}
\tl_replace_all:Nnn \l_tmpa_tl {,}{&}
\tl_set:Nx \l_tmpa_tl {\tl_tail:N \l_tmpa_tl}
\tl_replace_all:Nnn \l_tmpa_tl {)}{}
\begin{bmatrix*}[#1]
\tl_use:N \l_tmpa_tl
\end{bmatrix*}
}
\ExplSyntaxOff
文件:matrixop.lua
function matropsymb (...)
-- desired operation is passed as first arg
local op = arg[1]
local matrix = require 'matrix'
local symbol = matrix.symbol
local m1, m2, mout
-- determine whether starred
local test = op
if string.match(test,"*") then
-- if so, then set flag and drop star
op = string.sub(op,1,-2)
star = true
else
star = false
end -- if string
-- if 2 args, must be unary
if #arg == 2 then
m1 = matrix{unpack(CreateMatrix(arg[2]))}:replace(symbol)
mout = matrix[op](m1)
-- if 3 args, must be binary
elseif #arg == 3 then
m1 = matrix{unpack(CreateMatrix(arg[2]))}:replace(symbol)
m2 = matrix{unpack(CreateMatrix(arg[3]))}:replace(symbol)
mout = matrix[op](m1,m2)--:replace(symbol)
end
-- if no star, then typeset operation and result
if not star then
if op == "mul" then
tex.sprint( matrix.latex(m1,"r").."\\cdot")
tex.sprint( matrix.latex(m2,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "add" then
tex.sprint( matrix.latex(m1,"r").."+")
tex.sprint( matrix.latex(m2,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "sub" then
tex.sprint( matrix.latex(m1,"r").."-")
tex.sprint( matrix.latex(m2,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "det" then
tex.sprint( "\\det"..matrix.latex(m1,"r").."=")
tex.sprint(mout)
elseif op == "transpose" then
tex.sprint(matrix.latex(m1,"r").."^{T}".."\\mkern -8mu=")
tex.sprint(matrix.latex(mout,"r"))
elseif op == "scalar" then
m1 = matrix.transpose(m1)
m2 = matrix.transpose(m2)
tex.sprint(matrix.latex(m1,"r").."\\cdot"..matrix.latex(m2,"r").."=")
tex.sprint(mout)
elseif op == "cross" then
tex.sprint(matrix.latex(m1,"r").."\\times"..matrix.latex(m2,"r").."=")
tex.sprint(matrix.latex(mout,"r"))
end -- if
end -- if not star
-- store output matrix in macro.
-- tex.print("\\gdef\\matout{"..ReturnMatrix(mout).."}")
if op ~= "det" then
if op ~="scalar" then
tex.print("\\gdef\\matout{"..ReturnMatrix(mout).."}")
end
end
end -- function
function matrop (...)
-- desired operation is passed as first arg
local op = arg[1]
local matrix = require 'matrix'
local m1, m2, m3, mout
-- determine whether starred
local test = op
if string.match(test,"*") then
op = string.sub(op,1,-2)
star = true
else
star = false
end
-- to test whether args are numbers or matrices
local test2 = tonumber(arg[2])
local test3 = tonumber(arg[3])
if #arg == 2 then
-- if 2 args, then unary
-- dogauss, alters original matrix so handled differently
m1 = matrix{unpack(CreateMatrix(arg[2]))}
if op == "dogauss" then
mout = matrix.copy(m1)
matrix[op](mout)
else
mout = matrix[op](m1)
end -- if gauss
-- several cases for 3 args
elseif #arg == 3 then
-- if second arg is a number-> root or pow
if test2 then
m1 = matrix{unpack(CreateMatrix(arg[3]))}
mout = matrix[op](m1,tonumber(arg[2]))
else
-- if not then if arg 3 is a number-> unary with round
-- as above, dogauss handled differently
if test3 then
m1 = matrix{unpack(CreateMatrix(arg[2]))}
if op == "dogauss" then
mout = matrix.copy(m1)
matrix[op](mout)
mout = matrix.round(mout,arg[3])
else
m2 = matrix[op](m1)
mout = matrix.round(m2,arg[3])
end -- if dogauss
-- if arg 3 is nan-> binary no round
else
m1 = matrix{unpack(CreateMatrix(arg[2]))}
m2 = matrix{unpack(CreateMatrix(arg[3]))}
mout = matrix[op](m1,m2)
end -- if test3
end -- if test2
else -- pow or root with round or binary with round
if test2 then
m1 = matrix{unpack(CreateMatrix(arg[3]))}
m2 = matrix[op](m1,tonumber(arg[2]))
mout = matrix.round(m2,arg[4])
else
m1 = matrix{unpack(CreateMatrix(arg[2]))}
m2 = matrix{unpack(CreateMatrix(arg[3]))}
m3 = matrix[op](m1,m2)
mout = matrix.round(m3,arg[4])
end -- if test2
end -- if #arg
-- no star-> typeset operation and result
if not star then
if op == "mul" then
tex.sprint( matrix.latex(m1,"r").."\\cdot")
tex.sprint( matrix.latex(m2,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "add" then
tex.sprint( matrix.latex(m1,"r").."+")
tex.sprint( matrix.latex(m2,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "div" then
tex.sprint( matrix.latex(m1,"r").."\\cdot")
tex.sprint( matrix.latex(m2,"r").."^{-1}".."\\mkern -8mu=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "sub" then
tex.sprint( matrix.latex(m1,"r").."-")
tex.sprint( matrix.latex(m2,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "invert" then
tex.sprint( matrix.latex(m1,"r").."^{-1}".."\\mkern -8mu=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "det" then
tex.sprint( "\\det"..matrix.latex(m1,"r").."=")
tex.sprint(mout)
elseif op == "dogauss" then
tex.sprint("\\rref"..matrix.latex(m1,"r").."=")
tex.sprint( matrix.latex(mout,"r"))
elseif op == "root" then
tex.sprint(matrix.latex(m1,"r").."^{\\frac{1}{"..arg[2].."}}".."\\mkern -8mu=")
tex.sprint(matrix.latex(mout,"r"))
elseif op == "transpose" then
tex.sprint(matrix.latex(m1,"r").."^{T}".."\\mkern -8mu=")
tex.sprint(matrix.latex(mout,"r"))
elseif op == "pow" then
tex.sprint(matrix.latex(m1,"r").."^{"..arg[2].."}".."\\mkern -8mu=")
tex.sprint(matrix.latex(mout,"r"))
elseif op == "scalar" then
m1 = matrix.transpose(m1)
m2 = matrix.transpose(m2)
tex.sprint(matrix.latex(m1,"r").."\\cdot"..matrix.latex(m2,"r").."=")
tex.sprint(mout)
elseif op == "cross" then
tex.sprint(matrix.latex(m1,"r").."\\times"..matrix.latex(m2,"r").."=")
tex.sprint(matrix.latex(mout,"r"))
end -- if op
end -- if not star
tex.print("\\gdef\\matout{"..ReturnMatrix(mout).."}")
end -- function
-- builds matrix table from input passed by tex
function CreateMatrix(str)
rows={}
-- get the elements between the braces
-- and execute the following function
string.gsub(str, "%((.-)%)",
function(sub)
-- for debugging
-- tex.print("Row: "..sub.."\\\\")
-- split the string at ','
elements = string.explode(sub,",")
row={}
for i,e in ipairs(elements) do
-- remove spaces (not really necessary)
e = string.gsub(e," ","")
-- insert the element to the row-table
table.insert(row,e)
-- for debugging
-- tex.print("Element :"..e.."\\\\")
end
-- insert the row-table to the rows-table
table.insert(rows,row)
end
)
return rows
end
-- returns output matrix in format that can be passed back
function ReturnMatrix(t)
if not (type(t)=="table") then
return t
else
local str = ""
for i=1,#t do
str=str.."("..t[i][1]
for j=2,#t[1] do
str=str..","..t[i][j]
end
str=str..")"
end
return str
end
end
文件:matrix.lua
该文件可以在这里找到:https://github.com/davidm/lua-matrix
我稍微修改了文件matrix.lua
。特别是,我改变了matrix.latex
函数。 为了使宏正常工作,您需要在源代码中将该函数编辑为以下内容(第 898-918 行):
--// matrix.latex ( mtx [, align] )
-- LaTeX output
function matrix.latex( mtx, align )
-- align : option to align the elements
-- c = center; l = left; r = right
-- \usepackage{dcolumn}; D{.}{,}{-1}; aligns number by . replaces it with ,
local align = align or "c"
local str = "\\begin{bmatrix*}[r]"
local getstr = matrix.type( mtx ) == "tensor" and tensor_tostring or number_tostring
for i = 1,#mtx do
str = str.."\t"..getstr(mtx[i][1])
for j = 2,#mtx[1] do
str = str.." & "..getstr(mtx[i][j])
end
-- close line
if i == #mtx then
str = str.."\n"
else
str = str.." \\\\\n"
end
end
return str.."\\end{bmatrix*}"
end
文件:matrixop-test.tex
\documentclass{article}
\usepackage{matrixop}
\usepackage{showexpl}
\setlength{\parindent}{0pt}
\begin{document}
\begin{center}{\Huge Matrix operations in \TeX}\end{center}
\textbf{matrixop.sty} provides two commands: \verb=\matrixop= and \verb=\formatmatrix=. The package requires that the document be compiled with Lua\LaTeX. Matrices are passed to the macro either directly or in macros. A matrix is passed as bracket delimited rows with comma separated entries, e.g. $(1,2,3)(4,5,6)$ would represent a $2\times 3$ matrix. The \verb=\matrixop= macro itself takes a variety of forms.
\begin{enumerate}
\item \verb=\matrixop<args>= Performs the operation and typesets the operation and result.
\item \verb=\matrixop*<args>= Produces symbolic rather than calculated results.
\item \verb=\matrixop<args>[n]= Rounds the entries of the resulting matrix to $n$ decimal places.
\item \verb=\matrixop{op*}<args>= Performs the operation, but does not typeset the operation or result.
\end{enumerate}
In all cases, excluding symbolic determinant or symbolic dot product, the resulting matrix is stored in the macro \verb=\matout= in the same format as input. Thus, \verb=\matout= can be reused as input. Since \verb=\matout= is overwritten after each operation, it may be necessary to save it via, e.g. \verb=\let\mymat\matout=, so that it can be used later. The supported operations are
\begin{itemize}
\item Binary:
\begin{itemize}
\item add
\item sub
\item mul
\item div
\item scalar (dot product)
\item cross (cross product)
\end{itemize}
\item Unary:
\begin{itemize}
\item det
\item invert
\item dogauss (returns $\rref$)
\item root
\item pow
\item transpose
\end{itemize}
\end{itemize}
The operations that support symbolic output are: add, mul, sub, det, transpose, scalar, and cross.
\section{Usage}
\def\matA{(1,2,3)(4,5,6)(7,0,9)}
\def\matB{(1,2,-1)(2,2,4)(1,3,-3)}
\def\matC{(1,1,2)(2,3,4)(5,6,7)}
\def\vA{(1)(2)(3)}
\def\vB{(4)(5)(6)}
\def\vC{(a)(b)(c)}
\def\matD{(a,b,c)(d,e,f)(g,h,i)}
\def\matE{(r,s,t)(u,v,w)(x,y,z)}
\begin{LTXexample}[pos=r]
\def\matA{(1,2,3)(4,5,6)(7,0,9)}
\def\matB{(1,2,-1)(2,2,4)(1,3,-3)}
\[\matrixop{mul}{\matA}{\matB}\]
\end{LTXexample}
For symbolic output, we may use (symbolic can be used with numeric input as well)
\begin{LTXexample}[pos=b, wide=true]
\def\matD{(a,b,c)(d,e,f)(g,h,i)}
\def\matE{(r,s,t)(u,v,w)(x,y,z)}
\[\matrixop*{mul}{\matD}{\matE}\]
\end{LTXexample}
If we prefer that the output is not typeset, then a star can be appended to the operation name within the first argument. In this case the matrix (or number) resulting from the operation is stored in the \verb=\matout= macro and can be invoked as such before the next operation is executed, or stored for later use. With the following code:
\begin{LTXexample}[pos=r,rframe=]
\matrixop{invert*}{\matA} % output stored in \matout
\let\ainv\matout % save for later
\matrixop{invert*}{\matB} % etc.
\let\binv\matout
\matrixop{mul*}{\binv}{\ainv}[5]
\let\bainv\matout
\matrixop{mul*}{\matA}{\matB}
\let\abprod\matout
\matrixop{mul*}{\abprod}{\bainv}[3]
\end{LTXexample}
% this is just here because of grouping introduced by showexpl, ie. the definitions
% above don't leave the scope of the environment
\matrixop{invert*}{\matA}
\let\ainv\matout
\matrixop{invert*}{\matB}
\let\binv\matout
\matrixop{mul*}{\binv}{\ainv}[5]
\let\bainv\matout
\matrixop{mul*}{\matA}{\matB}
\let\abprod\matout
\matrixop{mul*}{\abprod}{\bainv}[3]
We could then type,
\begin{LTXexample}[pos=b]
If $A$ and $B$ are as given below,
\[
A=\formatmatrix{\matA}\qquad B=\formatmatrix{\matB}
\]
Then the product $AB$
\[
AB=\formatmatrix{\abprod}
\]
when multiplied (on the right) by the matrix $B^{-1}A^{-1}$
\[
B^{-1}A^{-1}=\formatmatrix{\bainv}
\]
should produce the identity matrix,
\[
AB(B^{-1}A^{-1})=\formatmatrix{\abprod}\cdot\formatmatrix{\bainv}=\formatmatrix{\matout}
\]
\end{LTXexample}
Some more examples below
\begin{LTXexample}[pos=b]
$\matrixop*{add}{\matD}{\matE}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{mul}{\matA}{\matB}$
\end{LTXexample}
\begin{LTXexample}[pos=b,wide=true]
$\matrixop*{mul}{\matD}{\matE}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{div}{\matA}{\matB}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{sub}{\matA}{\matB}$
\end{LTXexample}
\begin{LTXexample}[pos=b]
$\matrixop*{sub}{\matD}{\matE}$
\end{LTXexample}
\begin{LTXexample}[pos=b]
$\matrixop{invert}{\matA}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{invert}{\matA}[4]$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{det}{\matA}$
\end{LTXexample}
\begin{LTXexample}[pos=b]
$\matrixop*{det}{\matE}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{dogauss}{\matA}$
\end{LTXexample}
\begin{LTXexample}[pos=b]
$\matrixop{root}[5]{\matA}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{root}[5]{\matA}[4]$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{transpose}{\matA}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{pow}[3]{\matA}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{scalar}{\vA}{\vB}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop*{scalar}{\vA}{\vC}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop{cross}{\vA}{\vB}$
\end{LTXexample}
\begin{LTXexample}[pos=r]
$\matrixop*{cross}{\vA}{\vC}$
\end{LTXexample}
\end{document}