\documentclass{article}
\usepackage{open-axiom}
\begin{document}
\title{\$SPAD/src/algebra mathml.spad}
\author{Arthur C. Ralfs}
\maketitle
\begin{abstract}
MathMLFormat is a package to produce presentation mathematical
markup language from OutputForm.
\end{abstract}
\eject
\tableofcontents
\eject
\section{Preface}
Both this code and documentation are still under development and
I don't pretend they are anywhere close to perfect or even finished.
However the code does work and I hope it might be useful to somebody
both for it's ability to output MathML from Axiom and as an example
of how to write a new output form.
\section{Introduction to Mathematical Markup Language}
MathML exists in two forms: presentation and content.
At this time (2007-02-11) the package only has a presentation
package. A content package is in the
works however it is more difficult. Unfortunately Axiom does
not make its semantics easily available. The \spadtype{OutputForm}
domain mediates between the individual Axiom domains and the
user visible output but \spadtype{OutputForm} does not provide full
semantic information. From my currently incomplete understanding
of Axiom it appears that remedying this would entail going back
to the individual domains and rewriting a lot of code.
However some semantics are conveyed directly by \spadtype{OutputForm} and other
things can be deduced from \spadtype{OutputForm} or from the original
user command.
\section{Displaying MathML}
The MathML string produced by ")set output mathml on" can be pasted
directly into an appropriate xhtml page and then viewed in Firefox
or some other MathML aware browser. The boiler plate code needed for
a test page, testmathml.xml, is:
\begin{verbatim}
]>
MathML Test
\end{verbatim}
Paste the MathML string into the body element and it should display
nicely in Firefox.
\section{Test Cases}
Here's a list of test cases that currently format correctly:
1. (x+y)**2
2. integrate(x**x,x)
3. integral(x**x,x)
4. (5 + sqrt 63 + sqrt 847)**(1/3)
5. set $[$1,2,3$]$
6. multiset $[$x rem 5 for x in primes(2,1000)$]$
7. series(sin(a*x),x=0)
8. matrix $[$ $[$x**i + y**j for i in 1..10$]$ for j in 1..10$]$
9. y := operator 'y
a. D(y(x,z),$[$x,x,z,x$]$)
b. D(y x,x,2)
10. x := series 'x
a. sin(1+x)
11. series(1/log(y),y=1)
12. y:UTS(FLOAT,'z,0) := exp(z)
13. a. c := continuedFraction(314159/100000)
b. c := continuedFraction(14159/100000)
c. c := continuedFraction(3,repeating [1], repeating [3,6])
14. F := operator F
x := operator x
y := operator y
a := F(x z,y z,z**2) + x y(z+1)
D(a,z)
The \spadtype{TexFormat} domain has the capability to format an object with
subscripts, superscripts, presubscripts and presuperscripts however
I don't know of any Axiom command that produces such an object. In
fact at present I see the case of "SUPERSUB" being used for putting
primes in the superscript position to denote ordinary differentiation.
I also only see the "SUB" case being used to denote partial
derivatives.
\section{)set output mathml on}
Making mathml appear as output during a normal Axiom session
by invoking ")set output mathml on" proved to be a bit tedious
and seems to be undocumented. I document my experience here
in case it proves useful to somebody else trying to get a new
output format from Axiom.
In \spadtype{MathMLFormat} the functions
\spadfun{coerce(expr : OutputForm) : String} and
\spadfun{display(s : String) : Void} provide the desired mathml output.
Note that this package was constructed by close examination of
Robert Sutor's \spadtype{TexFormat} domain and much remains from that source.
To have mathml displayed as output we need to get Axiom to
call display(coerce(expr)) at the appropriate place. Here's what
I did to get that to happen. Note that my starting point here was
an attempt by Andrey Grozin to do the same. To figure things out
I searched through files for "tex" to see what was done for the
\spadtype{TexFormat} domain, and used grep to find which files had mention of
\spadtype{TexFormat}.
\subsection{File src/interp/setvars.boot.pamphlet}
Create an output mathml section by analogy to the tex section.
Remember to add the code chunk "outputmathmlCode" at the end.
setvars.boot is a bootstrap file which means that it has to be
precompiled into lisp code and then that code has to be inserted
back into setvars.boot. To do this extract the boot code by running
"notangle" on it. I did this from the "tmp" directory.
From inside axiom run ")lisp (bbottran::boottocl "tmp/setvars.boot")
which put "setvars.clisp" into "int/interp/setvars.clisp". Then
replace the lisp in "setvars.boot.pamphlet" with that in the newly
generated "setvars.clisp".
The relevant code chunks appearing in "setvars.boot.pamphlet" are:
\begin{verbatim}
outputmathmlCode
setOutputMathml
describeSetOutputMathml
\end{verbatim}
and the relevant variables are:
\begin{verbatim}
setOutputMathml
$mathmlOutputStream
$mathmlOutputFile
$mathmlFormat
describeSetOutputMathml
\end{verbatim}
\subsection{File setvart.boot.pamphlet}
Create an output mathml section in "setvart.boot.pamphlet" again
patterned after the tex section. I changed the default file
extension from ".stex" to ".smml".
To the "section{output}" table I added the line
\begin{verbatim}
mathml created output in MathML style Off:CONSOLE
\end{verbatim}
Added the code chunk "outputmathml" to the code chunk "output"
in "section{output}".
Relevant code chunks:
\begin{verbatim}
outputmathml
\end{verbatim}
Relevant variables:
\begin{verbatim}
setOutputMathml
$mathmlFormat
$mathmlOutputFile
\end{verbatim}
Note when copying the tex stuff I changed occurrences of "tex"
to "mathml", "Tex" to "Mathml" and "TeX" to "MathML".
\subsection{File src/algebra/Makefile.pamphlet}
The file "src/algebra/tex.spad.pamphlet" contains
the domain \spadtype{TexFormat} (TEX) and the package
\spadtype{TexFormat1} (TEX1).
However the sole function of \spadtype{TexFormat1} is to \spadfun{coerce}
objects from a domain into \spadtype{OutputForm} and then apply
\spadtype{TexFormat}
to them. It is to save programmers the trouble of doing
the coercion themselves from inside spad code. It does
not appear to be used for the main purpose of delivering
Axiom output in TeX format. In order to keep the mathml
package as simple as possible, and because I didn't see much
use for this, I didn't copy the \spadtype{TexFormat1} package. So
no analog of the TEX1 entries in "Makefile.pamphlet" were
needed. One curiosity I don't understand is why TEX1
appears in layer 4 when it seems to depend on TEX which
appears in layer 14.
Initially I added "\${OUT}/MMLFORM.o" to layer 14 and
"mathml.spad.pamphlet" to completed spad files in layer 14.
When trying to compile the build failed at MMLFORM. It left
"MMLFORM.erlib" in "int/algebra" instead of "MMLFORM.NRLIB"
which confused me at first because mathml.spad compiled
under a running axiom. By examining the file "obj/tmp/trace"
I saw that a new dependency had been introduced, compared
to TexFormat, with the function eltName depending on the
domain FSAGG in layer 16. So the lines had to be moved
from layer 14 to layer 17.
Added appropriate lines to "SPADFILES" and "DOCFILES".
\subsection{File src/algebra/exposed.lsp.pamphlet}
Add the line "(|MathMLFormat| . MMLFORM)"
\subsection{File src/algebra/Lattice.pamphlet}
I don't see that this file is used anywhere but I made
the appropriate changes anyway by searching for "TEX" and
mimicing everything for MMLFORM.
\subsection{File src/doc/axiom.bib.pamphlet}
Added mathml.spad subsection to "src/doc/axiom.bib.pamphlet".
\subsection{File interp/i-output.boot.pamphlet}
This is where the \spadfun{coerce} and \spadfun{display} functions
from MathMLFormat
actually get called. The following was added:
\begin{verbatim}
mathmlFormat expr ==
mml := '(MathMLFormat)
mmlrep := '(String)
formatFn := getFunctionFromDomain("coerce",mml,[$OutputForm])
displayFn := getFunctionFromDomain("display",mml,[mmlrep])
SPADCALL(SPADCALL(expr,formatFn),displayFn)
writeNewline $mathmlOutputStream
flushOutput $mathmlOutputStream
NIL
\end{verbatim}
Note that compared to the texFormat function there are a couple
of differences. Since \spadtype{MathMLFormat} is currently a package rather
than a domain there is the "mmlrep" variable whereas in texFormat
the argument of the "display" function is an instance of the
domain. Also the \spadfun{coerce} function here only has one argument,
namely "\$OutputForm".
Also for the function "output(expr,domain)" add lines for mathml,
e.g. "if \$mathmlFormat then mathmlFormat expr".
After these changes Axiom compiled with mathml enabled under
)set output.
\section{package MMLFORM MathMLFormat}
\subsection{Public Declarations}
The declarations
\begin{verbatim}
E ==> OutputForm
I ==> Integer
L ==> List
S ==> String
US ==> UniversalSegment(Integer)
\end{verbatim}
provide abbreviations for domains used heavily in the code.
The publicly exposed functions are:
\spadfun{coerce: E -$>$ S} This function is the main one for converting
an expression in domain OutputForm into a MathML string.
\spadfun{coerceS: E -$>$ S} This function is for use from the command line.
It converts an OutputForm expression into a MathML string and does
some formatting so that the output is not one long line. If you take
the output from this function, stick it in an emacs buffer in
nxml-mode and then indent according to mode, you'll get something that's
nicer to look at than what comes from coerce. Note that coerceS returns
the same value as coerce but invokes a display function as well so that
the result will be printed twice in different formats. The need for this
is that the output from coerce is automatically formatted with line breaks
by Axiom's output routine that are not in the right place.
\spadfun{coerceL: E -$>$ S} Similar to coerceS except that the displayed result
is the MathML string in one long line. These functions can be used,
for instance, to get the MathML for the previous result by typing
coerceL(%)\$MMLFORM.
\spadfun{exprex: E -$>$ S} Converts \spadtype{OutputForm} to
\spadtype{String} with
the structure preserved with braces. This is useful in developing this
package. Actually this is not quite accurate. The function
\spadfun{precondition} is first applied to the \spadtype{OutputForm}
expression before \spadfun{exprex}. Raw \spadtype{OutputForm} and the nature
of the \spadfun{precondition} function is still obscure to me at the time of
this writing (2007-02-14), however I probably need to understand it to make
sure I'm not missing any semantics. The spad function \spadfun{precondition}
is just a wrapper for the lisp function outputTran\$Lisp, which I guess is
compiled from boot.
\spadfun{display: S -$>$ Void} This one prints the string returned by coerce as one
long line, adding "math" tags: $. Thus the output
from this can be stuck directly into an appropriate html/xhtml page and will
be displayed nicely by a MathML aware browser.
\spadfun{displayF: S -$>$ Void} This function doesn't exist
yet but it would be nice
to have a humanly readable formatted output as well. The basics do exist in
the coerceS function however the formatting still needs some work to be
really good.
<>=
)abbrev domain MMLFORM MathMLFormat
++ Author: Arthur C. Ralfs
++ Date: January 2007
++ This package is based on the TeXFormat domain by Robert S. Sutor
++ without which I wouldn't have known where to start.
++ Basic Operations: coerce, coerceS, coerceL, exprex, display
++ Description:
++ \spadtype{MathMLFormat} provides a coercion from \spadtype{OutputForm}
++ to MathML format.
MathMLFormat(): public == private where
E ==> OutputForm
I ==> Integer
L ==> List
S ==> String
US ==> UniversalSegment(Integer)
public == SetCategory with
coerce: E -> S
++ coerceS(o) changes o in the standard output format to MathML
++ format.
coerceS: E -> S
++ coerceS(o) changes o in the standard output format to MathML
++ format and displays formatted result.
coerceL: E -> S
++ coerceS(o) changes o in the standard output format to MathML
++ format and displays result as one long string.
exprex: E -> S
++ coverts \spadtype{OutputForm} to \spadtype{String} with the
++ structure preserved with braces. Actually this is not quite
++ accurate. The function \spadfun{precondition} is first
++ applied to the
++ \spadtype{OutputForm} expression before \spadfun{exprex}.
++ The raw \spadtype{OutputForm} and
++ the nature of the \spadfun{precondition} function is
++ still obscure to me
++ at the time of this writing (2007-02-14).
display: S -> Void
++ prints the string returned by coerce, adding