|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://anggtwu.net/LUA/Maxima2.lua.html
-- http://anggtwu.net/LUA/Maxima2.lua
-- (find-angg "LUA/Maxima2.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- Long story short: I found emaxima.sty too limited and too hard to
-- modify, and I wrote this Lpeg-based tool to convert the output of
-- Maxima with "display2d:'emaxima" to LaTeX code.
--
-- The "too limited" above means: emaxima.sty changes catcodes
-- temporarily, and because of that it was super hard to use
-- emaxima.sty to put Maxima code in "\vbox"es.
--
-- An example of input (in the .tex, in the "%M" lines) and output:
--
-- http://anggtwu.net/LATEX/2023-2-C2-edovs.tex.html#4-inversas-maxima
-- http://anggtwu.net/LATEX/2023-2-C2-Tudo.pdf#page=221
-- 2hT221 (c2m232edovsp 13 "4-inversas-maxima")
-- (c2m232edovsa "4-inversas-maxima")
-- (find-es "maxima" "qdraw-4-inverses")
--
-- See: (find-es "maxima" "Maxima2.lua")
-- (defun o () (interactive) (find-angg "LUA/Maxima1.lua"))
-- (defun e () (interactive) (find-angg "LUA/Maxima2.lua"))
-- «.MaximaLine» (to "MaximaLine")
-- «.MaximaLine-tests» (to "MaximaLine-tests")
-- «.MaximaIO» (to "MaximaIO")
-- «.MaximaIO-tests» (to "MaximaIO-tests")
-- «.MaximaIOs» (to "MaximaIOs")
-- «.MaximaIOs-tests» (to "MaximaIOs-tests")
-- «.grammar» (to "grammar")
-- «.grammar-tests» (to "grammar-tests")
-- «.MaximaHead» (to "MaximaHead")
-- «.MaximaHead-tests» (to "MaximaHead-tests")
-- «.head» (to "head")
-- «.show2» (to "show2")
-- «.show2-tests» (to "show2-tests")
-- «.show2-tests-head» (to "show2-tests-head")
-- «.show2-tests-prep» (to "show2-tests-prep")
require "ELpeg1" -- (find-angg "LUA/ELpeg1.lua")
require "Show2" -- (find-angg "LUA/Show2.lua")
require "Co1" -- (find-angg "LUA/Co1.lua")
require "DeleteComments2" -- (find-angg "LUA/DeleteComments2.lua")
deletecomments = deletecomments_2023
-- __ __ _ _ _
-- | \/ | __ ___ _(_)_ __ ___ __ _| | (_)_ __ ___
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` | | | | '_ \ / _ \
-- | | | | (_| |> <| | | | | | | (_| | |___| | | | | __/
-- |_| |_|\__,_/_/\_\_|_| |_| |_|\__,_|_____|_|_| |_|\___|
--
-- «MaximaLine» (to ".MaximaLine")
-- See: (find-LATEX "edrx21.sty" "maximablue-red")
MaximaLine = Class {
type = "MaximaLine",
ify = function (tbl) return MaximaLine(tbl) end,
__tostring = function (ml) return mytostring(ml) end,
__index = {
co = Co.new(" \\%{}$_", "^~"),
cot = function (ml, str) return ml.co:translate(str) end,
blue0 = function (ml, a) return format("\\maximablue{%s}", a) end,
red0 = function (ml, a,b) return format("\\maximared{%s}{%s}", a,b) end,
type1tex = function (ml) return ml:blue0(ml:cot(ml.c .. ml.d)) end,
type2tex = function (ml, c)
local spaces = c:gsub(".", " ")
return ml:blue0(ml:cot(spaces .. ml.d))
end,
type3tex = function (ml)
--local fmt = "$\displaystyle %s$"
local fmt = "%s"
return ml:red0(ml:cot(ml.c), ""),
ml:red0("", format(fmt, ml.d)),
ml:red0("", "")
end,
},
}
-- «MaximaLine-tests» (to ".MaximaLine-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
ml1 = MaximaLine.ify {a="i", b="42", c="(%i42) ", d="2+"}
ml2 = MaximaLine.ify { d="3;"}
ml3 = MaximaLine.ify {a="o", b="42", c="(%o42) ", d="5"}
= ml1
= ml2
= ml3
= ml1:type1tex()
= ml2:type2tex("(%i42) ")
= ml3:type3tex()
--]]
-- __ __ _ ___ ___
-- | \/ | __ ___ _(_)_ __ ___ __ _|_ _/ _ \
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` || | | | |
-- | | | | (_| |> <| | | | | | | (_| || | |_| |
-- |_| |_|\__,_/_/\_\_|_| |_| |_|\__,_|___\___/
--
-- In the first version of this program an object of the class
-- MaximaIO (a "mio") was always a list made of an "(%i<n>)" line and
-- an "(%o<n>)" line associated to it. A mio could represent something
-- like this:
--
-- (%i42) 2+3;
-- (%o42) 5
--
-- Then I realized the in my logs of Maxima sessions I could have mios
-- like this one:
--
-- (%i1) a+
-- b+
-- 42; c+d; e+f;
-- (%o1) b + a + 42
-- (%o2) d + c
-- (%o3) f + e
--
-- each "(%i<n>)" line can be followed by some continuation lines, and
-- this can be followed by zero or more "(%o<n>)" lines. See the test
-- block for the details.
--
-- «MaximaIO» (to ".MaximaIO")
MaximaIO = Class {
type = "MaximaIO",
ify = function (tbl) return MaximaIO(tbl) end,
__tostring = function (mio) return mio:totyped() end,
__index = {
tovtable = function (mio)
local vt = VTable {mio[1]}
for _,ml in ipairs(mio[2]) do table.insert(vt, ml) end
for _,ml in ipairs(mio[3]) do table.insert(vt, ml) end
return vt
end,
totyped = function (mio)
local prefix = (mio[1].c):gsub(".", " ")
local vt = VTable {}
local add = function (str) table.insert(vt, str) end
local addtype1 = function (ml) add("type 1: "..ml.c ..ml.d) end
local addtype2 = function (ml) add("type 2: "..prefix..ml.d) end
local addtype3 = function (ml) add("type 3: "..ml.c ..ml.d) end
addtype1(mio[1])
for _,ml in ipairs(mio[2]) do addtype2(ml) end
for _,ml in ipairs(mio[3]) do addtype3(ml) end
return table.concat(vt, "\n")
end,
toboxes = function (mio)
local prefix = (mio[1].c):gsub(".", " ")
local vt = VTable {}
local add = function (str) table.insert(vt, str) end
local adds = function (...) for _,o in ipairs({...}) do add(o) end end
local addtype1 = function (ml) add(ml:type1tex()) end
local addtype2 = function (ml) add(ml:type2tex(prefix)) end
local addtype3 = function (ml) adds(ml:type3tex()) end
addtype1(mio[1])
for _,ml in ipairs(mio[2]) do addtype2(ml) end
for _,ml in ipairs(mio[3]) do addtype3(ml) end
return vt
end,
toboxesconcat = function (mio, sep)
return table.concat(mio:toboxes(), sep or "\n")
end,
a = function (mio) return mio:totyped() end,
b = function (mio,sep) return mio:toboxesconcat(sep) end,
ab = function (mio,sep) return mio:a().."\n"..mio:b(sep) end,
},
}
-- «MaximaIO-tests» (to ".MaximaIO-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
mio = MaximaIO.ify {"a", {"b", "c"}, {"d", "e"}}
= mio:tovtable()
mio = MaximaIO.ify {
MaximaLine_parse "(%i1) a+", -- type 1: (%i<n>)
{ MaximaLine_parse "b+", -- type 2: continuation
MaximaLine_parse "42; c+d; e+f;", -- type 2: continuation
},
{ MaximaLine_parse "(%o1) b + a + 42", -- type 3: (%o<n>)
MaximaLine_parse "(%o2) d + c", -- type 3: (%o<n>)
MaximaLine_parse "(%o3) f + e", -- type 3: (%o<n>)
}
}
= mio:tovtable()
= mio:totyped()
= mio:toboxes()
= mio:toboxesconcat()
= mio:toboxesconcat(" \\\\\n")
= mio:a ()
= mio: b()
= mio: b(" \\\\\n")
= mio:ab()
= mio:ab(" \\\\\n")
bigstr = [[
(%i1) a+
b+
42; c+d; e+f;
(%o1) b + a + 42
(%o2) d + c
(%o3) f + e
(%i4)
]]
mios = MaximaIOs_parse(bigstr)
= mios[1]
= mios[2]
= otype(mios[1])
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
a+
b+
42; c+d; e+f;
--]==]
-- __ __ _ ___ ___
-- | \/ | __ ___ _(_)_ __ ___ __ _|_ _/ _ \ ___
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` || | | | / __|
-- | | | | (_| |> <| | | | | | | (_| || | |_| \__ \
-- |_| |_|\__,_/_/\_\_|_| |_| |_|\__,_|___\___/|___/
--
-- An object of the class MaximaIOs (a "mios") is essentially just a
-- list of objects of the class MaximaIO (a list of "mio"s).
--
-- «MaximaIOs» (to ".MaximaIOs")
MaximaIOs = Class {
type = "MaximaIOs",
__tostring = function (mios) return mios:ias() end,
__index = {
a = function (mios,i) return mios[i]:a() end,
b = function (mios,i,sep) return mios[i]:b(sep) end,
ab = function (mios,i,sep) return mios[i]:a().."\n"..mios[i]:b(sep) end,
ias = function (mios)
local f = function (i) return i..":\n"..mios:a(i) end
return mapconcat(f, seq(1, #mios), "\n")
end,
iabs = function (mios,sep)
local f = function (i) return i..":\n"..mios:ab(i,sep) end
return mapconcat(f, seq(1, #mios), "\n")
end,
bs = function (mios, sep)
local f = function (i) return mios:b(i,sep) end
return mapconcat(f, seq(1, #mios), sep or "\n")
end,
debug = function (mios,sep) return mios:iabs(sep) end,
totex = function (mios,sep) return mios:bs(sep) end,
show = function (mios, opts)
opts = opts or {}
scale = opts.scale or 1
texbody = "\\vbox{\n"..mios:totex().."}"
return Show.try(tostring(outertexbody))
end,
--
show00 = function (mios,...)
local texbody0 = "\\vbox{\n"..mios:totex().."}"
return texbody0:show00(...)
end,
show0 = function (mios,...) return mios:show00(...):show0(...) end,
show = function (mios,...) return mios:show00(...):show (...) end,
},
}
-- «MaximaIOs-tests» (to ".MaximaIOs-tests")
--[==[
* (show2-use "$SHOW2LATEXDIR/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
bigstr = [[
(%i1) a+
b+
42; c+d; e+f;
(%o1) b + a + 42
(%o2) d + c
(%o2) f + e
(%i3)
]]
mios = MaximaIOs_parse(bigstr)
= mios
= mios[1]
= mios[2]
= mios:debug()
= mios:debug(" \\\\\n")
= mios:totex()
= mios:totex(" \\\\\n")
= mios:show00({scale=0.8})
= mios:show0 ({scale=0.8})
= mios:show ({scale=0.8})
= Show.log
= Show.bigstr
* (etv)
--]==]
-- __ _ _ __ __ _ _ __ ___ _ __ ___ __ _ _ __
-- / _` | '__/ _` | '_ ` _ \| '_ ` _ \ / _` | '__|
-- | (_| | | | (_| | | | | | | | | | | | (_| | |
-- \__, |_| \__,_|_| |_| |_|_| |_| |_|\__,_|_|
-- |___/
--
-- «grammar» (to ".grammar")
-- See: (find-es "lpeg" "lpeg.Cfromthere")
-- (find-es "lpeg" "lpeg.Cobeying")
-- gr,V,VAST,VEXPECT,PEXPECT = Gram.new()
local gr,V,VAST,VEXPECT,PEXPECT = Gram.new()
V.a = S"io":Cg"a"
V.b = (R"09"^1):Cg"b"
V.c0 = Cp():Cg"c" -- store the initial position in "c"
V.c1 = Cb"c":Cfromthere():Cg"c" -- replace "c" by its :Cfromthere()
V.abc = V.c0 * P"(%" * V.a * V.b * P")" * P" "^-1 * V.c1
V.d = ((1-S"\n")^0):C():Cg"d"
V.abcd = V.abc^-1 * V.d
V.abct = V.abc:Ct()
V.abcdt = V.abcd:Ct()
V.mline = V.abcd:Ct() / MaximaLine.ify
V.mline1 = V.mline:Cobeying(function (ml) return ml.a == "i" end)
V.mline2 = V.mline:Cobeying(function (ml) return ml.a == nil end)
V.mline3 = V.mline:Cobeying(function (ml) return ml.a == "o" end)
V.mio = (V.mline1 *
((P"\n" * V.mline2)^0):Ct() *
((P"\n" * V.mline3)^0):Ct()
):Ct() / MaximaIO.ify
V.mios = (V.mio * (P"\n" * V.mio)^0) :Ct()
Maxima_gr = gr
MaximaLine_pat = gr:compile("mline")
MaximaLine_parse = function (str) return MaximaLine_pat:match(str) end
MaximaIOs_pat = gr:compile("mios")
MaximaIOs_parse = function (str)
local mios = MaximaIOs_pat:match(str)
if type(mios) ~= "table" then
print("MaximaIOs_pat:match failed! Input:")
print(str)
end
return MaximaIOs(mios)
end
-- «grammar-tests» (to ".grammar-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
= Maxima_gr:cm ("abc", "(%i42)")
= Maxima_gr:cm ("abct", "(%i42)")
= Maxima_gr:cm ("abcd", "(%i42)")
= Maxima_gr:cmp("abcd", "(%i42)")
PP(Maxima_gr:cm0("abct", "(%i42) foo"))
PP(Maxima_gr:cm0("abcdt", "(%i42) foo"))
Maxima_gr:cmp("abcdt", "(%i42) foo")
PP(Maxima_gr:cm0("abcdt", "blarpy foo"))
= Maxima_gr:cm0("mline", "(%i3) foo")
= Maxima_gr:cm0("mline", "(%o42) foo")
= Maxima_gr:cm0("mline", "blarpy foo")
= Maxima_gr:cm0("mline1", "(%i3) foo")
= Maxima_gr:cm0("mline1", "(%o42) foo")
= Maxima_gr:cm0("mline1", "blarpy foo")
= Maxima_gr:cm0("mline2", "(%i3) foo")
= Maxima_gr:cm0("mline2", "(%o42) foo")
= Maxima_gr:cm0("mline2", "blarpy foo")
bigstr = [[
(%i1) a+
b+
42; c+d; e+f;
(%o1) b + a + 42
(%o2) d + c
(%o3) f + e
(%i4)
]]
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
a+
b+
42; c+d; e+f;
--]==]
-- __ __ _ _ _ _
-- | \/ | __ ___ _(_)_ __ ___ __ _| | | | ___ __ _ __| |
-- | |\/| |/ _` \ \/ / | '_ ` _ \ / _` | |_| |/ _ \/ _` |/ _` |
-- | | | | (_| |> <| | | | | | | (_| | _ | __/ (_| | (_| |
-- |_| |_|\__,_/_/\_\_|_| |_| |_|\__,_|_| |_|\___|\__,_|\__,_|
--
-- The code below tells Dednat6 how to handle blocks of comments
-- in which each line starts with "%M".
--
-- «MaximaHead» (to ".MaximaHead")
MaximaHead = Class {
type = "MaximaHead",
__index = {
set_maxima_lines = function (mh, origlines, delchars)
local mtrim = function (li)
if not delchars then return (li:gsub("^%%M ?", "")) end
return li:sub(delchars+1)
end
if type(origlines) == "string" then origlines = splitlines(origlines) end
maxima_lines00 = VTable(copy(origlines))
maxima_lines0 = VTable(map(mtrim, maxima_lines00))
maxima_lines = bitrim(table.concat(maxima_lines0, "\n"))
return maxima_lines
end,
mios = function (mh) return MaximaIOs_parse(maxima_lines) end,
sa000 = function (mh, sep) return maximahead:mios():totex(sep) end,
sa00 = function (mh, sep) return "\\vbox{"..mh:sa000(sep).."}" end,
sa0 = function (mh, name, sep)
return format("\\sa{%s}{%%\n%s%%\n}", name, mh:sa00(sep))
end,
sa = function (mh, name, sep) output(mh:sa0(name, sep)) end,
--
M0 = function (mh)
local addM = function (li) return "%M "..li end
return VTable(map(addM, maxima_lines0))
end,
M1 = function (mh) return bitrim(table.concat(mh:M0(), "\n")) end,
M2 = function (mh,name) return '%L maximahead:sa("'..name..'", "")' end,
M12 = function (mh,name) return mh:M1().."\n"..mh:M2(name).."\n\\pu" end,
M3 = function (mh,name) return "\\ga{"..name.."}" end,
show00 = function (mh,...) return mh:M12("foo").."\n\n"..mh:M3("foo"):show00(...) end,
show0 = function (mh,...) return mh:show00(...):show0() end,
show = function (mh,...) return mh:show00(...):show () end,
},
}
maximahead = MaximaHead {}
-- «MaximaHead-tests» (to ".MaximaHead-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
bigstr = [[
%M (%i1) a+
%M b+
%M 42; c+d; e+f;
%M (%o1) b + a + 42
%M (%o2) d + c
%M (%o3) f + e
%M (%i4)
%M
]]
= maximahead:set_maxima_lines(bigstr, 0) -- delete 0 chars
= maximahead:set_maxima_lines(bigstr, 3) -- delete 3 chars
= maximahead:set_maxima_lines(bigstr) -- delete the "%M "s
= maxima_lines00
= maxima_lines0
= maxima_lines
= maximahead:sa000()
= maximahead:sa00 ()
= maximahead:sa0 ("foo")
= maximahead:M0()
= maximahead:M1()
= maximahead:M2 ("bar")
= maximahead:M12("bar")
= maximahead:M3 ("bar")
= maximahead:show00 {scale=0.9}
= maximahead:show0 {scale=0.9}
= maximahead:show {scale=0.9}
* (etv)
= Show.log
= Show.bigstr
= maximahead:mios()
= maximahead:mios():totex()
= maximahead:mios():totex("%\n")
= maximahead:mios():totex(" \\\\\n")
= maximahead:sa00()
= maximahead:sa00( " \\\\\n")
= maximahead:sa0("foo")
= maximahead:sa0("foo", " \\\\\n")
output = print
maximahead:sa ("foo")
maximahead:sa ("foo", " \\\\\n")
--]==]
-- _ _
-- | |__ ___ __ _ __| |
-- | '_ \ / _ \/ _` |/ _` |
-- | | | | __/ (_| | (_| |
-- |_| |_|\___|\__,_|\__,_|
--
-- See: http://angg.twu.net/dednat6/tug-slides.pdf#page=17
-- http://angg.twu.net/dednat6/tugboat-rev2.pdf#page=4
-- https://tug.org/TUGboat/tb39-3/tb123ochs-dednat.pdf#page=4
--
-- «head» (to ".head")
-- (find-angg "LUA/Verbatim1.lua" "vbt-head")
registerhead = registerhead or function () return nop end
registerhead "%M" {
name = "maxima",
action = function ()
local i,j,origlines = tf:getblock(0)
maximahead:set_maxima_lines(origlines)
end,
}
-- «show2» (to ".show2")
-- (find-angg "LUA/Show2.lua" "dednat6" "dednat6_Maxima2")
-- (find-LATEX "edrx21.sty" "maximablue-red")
dednat6_Maxima2 = [==[
% (find-Deps1-cps "Maxima2")
%L dofile "Maxima2.lua" -- (find-angg "LUA/Maxima2.lua")
\pu
]==]
usepackages.edrx21 = true
dednat6["0"] = true
dednat6.Maxima2 = true
-- «show2-tests» (to ".show2-tests")
--[==[
** (find-Deps1-cps "Maxima2")
* (show2-use "$SHOW2LATEXDIR/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
= outertexbody
= ([=[
% A low-level test without Dednat6.
% See: (find-LATEX "edrx21.sty" "maximablue-red")
\def\hboxthreewidth{4cm}
\vbox{%
\maximablue{(\%i1)\ 2*3;}%
\maximared{(\%o1)\ }{}%
\maximared{}{5}%
}
]=]) :show {scale=1.5}
= Show.log
= Show.bigstr
* (etv)
--]==]
-- «show2-tests-head» (to ".show2-tests-head")
--[==[
** (find-Deps1-cps "Maxima2")
* (show2-use "$SHOW2LATEXDIR/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Maxima2.lua"
= outertexbody
dednat6.Maxima2_test = [=[
% A test with Dednat6.
%
%M (%i1) 2*3;
%M (%o1) 5
%L maximahead:sa("2 + 3", "")
\pu
\def\hboxthreewidth {6cm}
]=]
= ([=[ \vbox{\ga{2 + 3}}
]=]) :show {scale=1.5}
= Show.log
= Show.bigstr
* (etv)
--]==]
-- «show2-tests-prep» (to ".show2-tests-prep")
--[[
** (find-Maxima2-links "maxima-subst1")
* (eepitch-maxima)
* (eepitch-kill)
* (eepitch-maxima)
load("/usr/share/emacs/site-lisp/maxima/emaxima.lisp")$
load("~/MAXIMA/barematrix1.lisp")$
display2d:'emaxima$
linenum:0;
/* PR: power rule
* PRW: power rule, wrong version
*/
PR : 'diff(x^n,x) = n*x^(n-1);
PRW : 'diff(x^n,x) = n*x^(n-1) + 10*n;
subst([n=4], PR);
subst([n=4], PRW);
--]]
-- Local Variables:
-- coding: utf-8-unix
-- End: