diff options
Diffstat (limited to 'src/algebra')
-rw-r--r-- | src/algebra/Makefile.in | 8 | ||||
-rw-r--r-- | src/algebra/Makefile.pamphlet | 9 | ||||
-rw-r--r-- | src/algebra/exposed.lsp.pamphlet | 1 | ||||
-rw-r--r-- | src/algebra/mathml.spad.pamphlet | 1463 |
4 files changed, 1475 insertions, 6 deletions
diff --git a/src/algebra/Makefile.in b/src/algebra/Makefile.in index dc5e3d24..f0eb327f 100644 --- a/src/algebra/Makefile.in +++ b/src/algebra/Makefile.in @@ -86,7 +86,8 @@ SPADFILES= \ ${OUTSRC}/list.spad ${OUTSRC}/lmdict.spad ${OUTSRC}/lodof.spad \ ${OUTSRC}/lodop.spad ${OUTSRC}/lodo.spad \ ${OUTSRC}/manip.spad ${OUTSRC}/mappkg.spad ${OUTSRC}/matcat.spad \ - ${OUTSRC}/matfuns.spad ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \ + ${OUTSRC}/matfuns.spad ${OUTSRC}/mathml.spad \ + ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \ ${OUTSRC}/mesh.spad ${OUTSRC}/mfinfact.spad ${OUTSRC}/misc.spad \ ${OUTSRC}/mkfunc.spad ${OUTSRC}/mkrecord.spad \ ${OUTSRC}/mlift.spad ${OUTSRC}/moddfact.spad ${OUTSRC}/modgcd.spad \ @@ -242,7 +243,8 @@ DOCFILES= \ ${DOC}/list.spad.dvi ${DOC}/lmdict.spad.dvi ${DOC}/lodof.spad.dvi \ ${DOC}/lodop.spad.dvi ${DOC}/lodo.spad.dvi \ ${DOC}/manip.spad.dvi ${DOC}/mappkg.spad.dvi ${DOC}/matcat.spad.dvi \ - ${DOC}/matfuns.spad.dvi ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \ + ${DOC}/matfuns.spad.dvi ${DOC}/mathml.spad.dvi \ + ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \ ${DOC}/mesh.spad.dvi ${DOC}/mfinfact.spad.dvi ${DOC}/misc.spad.dvi \ ${DOC}/mkfunc.spad.dvi ${DOC}/mkrecord.spad.dvi ${DOC}/mlift.spad.jhd.dvi \ ${DOC}/mlift.spad.dvi ${DOC}/moddfact.spad.dvi ${DOC}/modgcd.spad.dvi \ @@ -684,7 +686,7 @@ axiom_algebra_layer_16_objects = \ $(addsuffix .$(FASLEXT),$(axiom_algebra_layer_16))) axiom_algebra_layer_17 = \ CCLASS FSAGG2 GALFACT IALGFACT \ - IBACHIN NORMMA ODERED OMSAGG \ + IBACHIN MMLFORM NORMMA ODERED OMSAGG \ PERM PERMGRP PRIMES PWFFINTB \ RDIST SAE SAEFACT SAERFFC \ SGCF TBAGG TBAGG- VIEW3D diff --git a/src/algebra/Makefile.pamphlet b/src/algebra/Makefile.pamphlet index 835df3b3..451c934b 100644 --- a/src/algebra/Makefile.pamphlet +++ b/src/algebra/Makefile.pamphlet @@ -851,6 +851,7 @@ aggcat.spad.pamphlet (AGG HOAGG CLAGG BGAGG SKAGG QUAGG DQAGG PRQAGG DIOPS aggcat2.spad.pamphlet (FLAGG2 FSAGG2) galfact.spad.pamphlet (GALFACT) intfact.spad.pamphlet (PRIMES IROOT INTFACT) +mathml.spad.pamphlet (MMLFORM) padiclib.spad.pamphlet (IBPTOOLS IBACHIN PWFFINTB) perm.spad.pamphlet (PERMCAT PERM) permgrps.spad.pamphlet (PERMGRP PGE) @@ -863,7 +864,7 @@ view3D.spad.pamphlet (VIEW3D) <<layer17>>= axiom_algebra_layer_17 = \ CCLASS FSAGG2 GALFACT IALGFACT \ - IBACHIN NORMMA ODERED OMSAGG \ + IBACHIN MMLFORM NORMMA ODERED OMSAGG \ PERM PERMGRP PRIMES PWFFINTB \ RDIST SAE SAEFACT SAERFFC \ SGCF TBAGG TBAGG- VIEW3D @@ -1418,7 +1419,8 @@ SPADFILES= \ ${OUTSRC}/list.spad ${OUTSRC}/lmdict.spad ${OUTSRC}/lodof.spad \ ${OUTSRC}/lodop.spad ${OUTSRC}/lodo.spad \ ${OUTSRC}/manip.spad ${OUTSRC}/mappkg.spad ${OUTSRC}/matcat.spad \ - ${OUTSRC}/matfuns.spad ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \ + ${OUTSRC}/matfuns.spad ${OUTSRC}/mathml.spad \ + ${OUTSRC}/matrix.spad ${OUTSRC}/matstor.spad \ ${OUTSRC}/mesh.spad ${OUTSRC}/mfinfact.spad ${OUTSRC}/misc.spad \ ${OUTSRC}/mkfunc.spad ${OUTSRC}/mkrecord.spad \ ${OUTSRC}/mlift.spad ${OUTSRC}/moddfact.spad ${OUTSRC}/modgcd.spad \ @@ -1582,7 +1584,8 @@ DOCFILES= \ ${DOC}/list.spad.dvi ${DOC}/lmdict.spad.dvi ${DOC}/lodof.spad.dvi \ ${DOC}/lodop.spad.dvi ${DOC}/lodo.spad.dvi \ ${DOC}/manip.spad.dvi ${DOC}/mappkg.spad.dvi ${DOC}/matcat.spad.dvi \ - ${DOC}/matfuns.spad.dvi ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \ + ${DOC}/matfuns.spad.dvi ${DOC}/mathml.spad.dvi \ + ${DOC}/matrix.spad.dvi ${DOC}/matstor.spad.dvi \ ${DOC}/mesh.spad.dvi ${DOC}/mfinfact.spad.dvi ${DOC}/misc.spad.dvi \ ${DOC}/mkfunc.spad.dvi ${DOC}/mkrecord.spad.dvi ${DOC}/mlift.spad.jhd.dvi \ ${DOC}/mlift.spad.dvi ${DOC}/moddfact.spad.dvi ${DOC}/modgcd.spad.dvi \ diff --git a/src/algebra/exposed.lsp.pamphlet b/src/algebra/exposed.lsp.pamphlet index 3c12b66c..2492f004 100644 --- a/src/algebra/exposed.lsp.pamphlet +++ b/src/algebra/exposed.lsp.pamphlet @@ -213,6 +213,7 @@ (|MappingPackage1| . MAPPKG1) (|MappingPackage2| . MAPPKG2) (|MappingPackage3| . MAPPKG3) + (|MathMLFormat| . MMLFORM) (|Matrix| . MATRIX) (|MatrixCategoryFunctions2| . MATCAT2) (|MatrixCommonDenominator| . MCDEN) diff --git a/src/algebra/mathml.spad.pamphlet b/src/algebra/mathml.spad.pamphlet new file mode 100644 index 00000000..747dbfca --- /dev/null +++ b/src/algebra/mathml.spad.pamphlet @@ -0,0 +1,1463 @@ +\documentclass{article} +\usepackage{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} +<?xml version="1.0" ?> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" + "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd" [ +<!ENTITY mathml "http://www.w3.org/1998/Math/MathML"> +]> + +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink" > + + + <head> + <title>MathML Test </title> + </head> + + <body> + + </body> +</html> +\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) + TERPRI $mathmlOutputStream + FORCE_-OUTPUT $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: <math ...$>$ ... </math$>$. 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. + +<<public declarations>>= +)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 <math ...> tags. + +@ +\subsection{Private Constant Declarations} +<<private constant declarations>>= + private == add + import OutputForm + import Character + import Integer + import List OutputForm + import List String + + -- local variable declarations and definitions + + expr: E + prec,opPrec: I + str: S + blank : S := " \ " + + maxPrec : I := 1000000 + minPrec : I := 0 + + unaryOps : L S := ["-","^"]$(L S) + unaryPrecs : L I := [700,260]$(L I) + + -- the precedence of / in the following is relatively low because + -- the bar obviates the need for parentheses. + binaryOps : L S := ["+->","|","**","/","<",">","=","OVER"]$(L S) + binaryPrecs : L I := [0,0,900, 700,400,400,400, 700]$(L I) + + naryOps : L S := ["-","+","*",blank,",",";"," ","ROW","", + " \cr ","&","</mtd></mtr><mtr><mtd>"]$(L S) + naryPrecs : L I := [700,700,800, 800,110,110, 0, 0, 0, + 0, 0, 0]$(L I) + naryNGOps : L S := ["ROW","&"]$(L S) + + plexOps : L S := ["SIGMA","SIGMA2","PI","PI2","INTSIGN","INDEFINTEGRAL"]$(L S) + plexPrecs : L I := [ 700, 800, 700, 800 , 700, 700]$(L I) + + specialOps : L S := ["MATRIX","BRACKET","BRACE","CONCATB","VCONCAT", _ + "AGGLST","CONCAT","OVERBAR","ROOT","SUB","TAG", _ + "SUPERSUB","ZAG","AGGSET","SC","PAREN", _ + "SEGMENT","QUOTE","theMap" ] + + -- the next two lists provide translations for some strings for + -- which MML provides special macros. + + specialStrings : L S := + ["cos", "cot", "csc", "log", "sec", "sin", "tan", + "cosh", "coth", "csch", "sech", "sinh", "tanh", + "acos","asin","atan","erf","...","$","infinity","Gamma"] + specialStringsInMML : L S := + ["<mo>cos</mo>","<mo>cot</mo>","<mo>csc</mo>","<mo>log</mo>","<mo>sec</mo>","<mo>sin</mo>","<mo>tan</mo>", + "<mo>cosh</mo>","<mo>coth</mo>","<mo>csch</mo>","<mo>sech</mo>","<mo>sinh</mo>","<mo>tanh</mo>", + "<mo>arccos</mo>","<mo>arcsin</mo>","<mo>arctan</mo>","<mo>erf</mo>","<mo>…</mo>","<mo>$</mo>","<mo>∞</mo>","<mo>Г</mo>"] + +@ +\subsection{Private Function Declarations} + +These are the local functions: + + addBraces:S -$>$ S + + addBrackets:S -$>$ S + + atomize:E -$>$ L E + + displayElt:S -$>$ Void + function for recursively displaying mathml nicely formatted + + eltLimit:(S,I,S) -$>$ I + demarcates end postion of mathml element with name:S starting at + position i:I in mathml string s:S and returns end of end tag as + i:I position in mathml string, i.e. find start and end of + substring: <name ...$>$...</name$>$ + + eltName:(I,S) -$>$ S + find name of mathml element starting at position i:I in string s:S + + group:S -$>$ S + + formatBinary:(S,L E, I) -$>$ S + + formatFunction:(S,L E, I) -$>$ S + + formatMatrix:L E -$>$ S + + formatNary:(S,L E, I) -$>$ S + + formatNaryNoGroup:(S,L E, I) -$>$ S + + formatNullary:S -$>$ S + + formatPlex:(S,L E, I) -$>$ S + + formatSpecial:(S,L E, I) -$>$ S + + formatUnary:(S, E, I) -$>$ S + + formatMml:(E,I) -$>$ S + + newWithNum:I -$>$ \$ + this is a relic from tex.spad and is not used here so far. I'll + probably remove it. + + parenthesize:S -$>$ S + + precondition:E -$>$ E + this function is applied to the OutputForm expression before + doing anything else. + + postcondition:S -$>$ S + this function is applied after all other OutputForm -$>$ MathML + transformations. In the TexFormat domain the ungroup function + first peels off the outermost set of braces however I have + replaced braces with <mrow$>$s here and sometimes the outermost set + of <mrow$>$s is necessary to get proper display in Firefox. For instance + with getting the correct size of brackets on a matrix the whole + expression needs to be enclosed in a mrow element. It also checks + for +- and removes the +. + + stringify:E -$>$ S + + tagEnd:(S,I,S) -$>$ I + finds closing "$>$" of start or end tag for mathML element for formatting + MathML string for human readability. No analog in TexFormat. + + ungroup:S -$>$ S + +<<private function declarations>>= + -- local function signatures + + addBraces: S -> S + addBrackets: S -> S + atomize: E -> L E + displayElt: S -> Void + ++ function for recursively displaying mathml nicely formatted + eltLimit: (S,I,S) -> I + ++ demarcates end postion of mathml element with name:S starting at + ++ position i:I in mathml string s:S and returns end of end tag as + ++ i:I position in mathml string, i.e. find start and end of + ++ substring: <name ...>...</name> + eltName: (I,S) -> S + ++ find name of mathml element starting at position i:I in string s:S + group: S -> S + formatBinary: (S,L E, I) -> S + formatFunction: (S,L E, I) -> S + formatIntSign: (L E, I) -> S + formatMatrix: L E -> S + formatNary: (S,L E, I) -> S + formatNaryNoGroup: (S,L E, I) -> S + formatNullary: S -> S + formatPlex: (S,L E, I) -> S + formatSpecial: (S,L E, I) -> S + formatSub: (E, L E, I) -> S + formatSuperSub: (E, L E, I) -> S + formatSuperSub1: (E, L E, I) -> S + formatUnary: (S, E, I) -> S + formatMml: (E,I) -> S + formatZag: L E -> S + formatZag1: L E -> S + newWithNum: I -> $ + parenthesize: S -> S + precondition: E -> E + postcondition: S -> S + stringify: E -> S + tagEnd: (S,I,S) -> I + ++ finds closing ">" of start or end tag for mathML element + ungroup: S -> S + +@ +\subsection{Public Function Definitions} + +Note that I use the function sayTeX$Lisp much as I would printf in a +C program. I've noticed in grepping the code that there are other "say" +functions, sayBrightly and sayMessage for instance, but I have no idea +what the difference is between them at this point. sayTeX$Lisp does the +job so for the time being I'll use that until I learn more. + +The functions coerceS and coerceL should probably be changed to display +functions, {\it i.e.}\/ \spadfun{displayS} and \spadfun{display L}, +returning Void. I really only need the one coerce function. + +<<public function definitions>>= + -- public function definitions + + coerce(expr : E): S == + s : S := postcondition formatMml(precondition expr, minPrec) + s + + coerceS(expr : E): S == + s : S := postcondition formatMml(precondition expr, minPrec) + sayTeX$Lisp "<math xmlns=_"http://www.w3.org/1998/Math/MathML_" mathsize=_"big_" display=_"block_">" + displayElt(s) + sayTeX$Lisp "</math>" + s + + coerceL(expr : E): S == + s : S := postcondition formatMml(precondition expr, minPrec) + sayTeX$Lisp "<math xmlns=_"http://www.w3.org/1998/Math/MathML_" mathsize=_"big_" display=_"block_">" + sayTeX$Lisp s + sayTeX$Lisp "</math>" + s + + display(mathml : S): Void == + sayTeX$Lisp "<math xmlns=_"http://www.w3.org/1998/Math/MathML_" mathsize=_"big_" display=_"block_">" + sayTeX$Lisp mathml + sayTeX$Lisp "</math>" + void()$Void + + + + exprex(expr : E): S == + -- This breaks down an expression into atoms and returns it as + -- a string. It's for developmental purposes to help understand + -- the expressions. + a : E + expr := precondition expr +-- sayTeX$Lisp "0: "stringify expr + (ATOM(expr)$Lisp@Boolean) or (stringify expr = "NOTHING") => + concat ["{",stringify expr,"}"] + le : L E := (expr pretend L E) + op := first le + sop : S := exprex op + args : L E := rest le + nargs : I := #args +-- sayTeX$Lisp concat ["1: ",stringify first le," : ",string(nargs)$S] + s : S := concat ["{",sop] + if nargs > 0 then + for a in args repeat +-- sayTeX$Lisp concat ["2: ",stringify a] + s1 : S := exprex a + s := concat [s,s1] + s := concat [s,"}"] + +@ +\subsection{Private Function Definitions} + +\subsubsection{Display Functions} + + displayElt(mathml:S):Void + + eltName(pos:I,mathml:S):S + + eltLimit(name:S,pos:I,mathml:S):I + + tagEnd(name:S,pos:I,mathml:S):I + +<<display functions>>= + + displayElt(mathML:S): Void == + -- Takes a string of syntactically complete mathML + -- and formats it for display. +-- sayTeX$Lisp "****displayElt1****" +-- sayTeX$Lisp mathML + enT:I -- marks end of tag, e.g. "<name>" + enE:I -- marks end of element, e.g. "<name> ... </name>" + end:I -- marks end of mathML string + u:US + end := #mathML + length:I := 60 +-- sayTeX$Lisp "****displayElt1.1****" + name:S := eltName(1,mathML) +-- sayTeX$Lisp name +-- sayTeX$Lisp concat("****displayElt1.2****",name) + enE := eltLimit(name,2+#name,mathML) +-- sayTeX$Lisp "****displayElt2****" + if enE < length then +-- sayTeX$Lisp "****displayElt3****" + u := segment(1,enE)$US + sayTeX$Lisp mathML.u + else +-- sayTeX$Lisp "****displayElt4****" + enT := tagEnd(name,1,mathML) + u := segment(1,enT)$US + sayTeX$Lisp mathML.u + u := segment(enT+1,enE-#name-3)$US + displayElt(mathML.u) + u := segment(enE-#name-2,enE)$US + sayTeX$Lisp mathML.u + if end > enE then +-- sayTeX$Lisp "****displayElt5****" + u := segment(enE+1,end)$US + displayElt(mathML.u) + + void()$Void + + eltName(pos:I,mathML:S): S == + -- Assuming pos is the position of "<" for a start tag of a mathML + -- element finds and returns the element's name. + i:I := pos+1 + --sayTeX$Lisp "eltName:mathmML string: "mathML + while member?(mathML.i,lowerCase()$CharacterClass)$CharacterClass repeat + i := i+1 + u:US := segment(pos+1,i-1) + name:S := mathML.u + + eltLimit(name:S,pos:I,mathML:S): I == + -- Finds the end of a mathML element like "<name ...> ... </name>" + -- where pos is the position of the space after name in the start tag + -- although it could point to the closing ">". Returns the position + -- of the ">" in the end tag. + pI:I := pos + startI:I + endI:I + startS:S := concat ["<",name] + endS:S := concat ["</",name,">"] + level:I := 1 + --sayTeX$Lisp "eltLimit: element name: "name + while (level > 0) repeat + startI := position(startS,mathML,pI)$String + + endI := position(endS,mathML,pI)$String + + if (startI = 0) then + level := level-1 + --sayTeX$Lisp "****eltLimit 1******" + pI := tagEnd(name,endI,mathML) + else + if (startI < endI) then + level := level+1 + pI := tagEnd(name,startI,mathML) + else + level := level-1 + pI := tagEnd(name,endI,mathML) + pI + + + tagEnd(name:S,pos:I,mathML:S):I == + -- Finds the closing ">" for either a start or end tag of a mathML + -- element, so the return value is the position of ">" in mathML. + pI:I := pos + while (mathML.pI ^= char ">") repeat + pI := pI+1 + u:US := segment(pos,pI)$US + --sayTeX$Lisp "tagEnd: "mathML.u + pI + +@ +\subsubsection{Formatting Functions} + +Still need to format \\zag in formatSpecial! + +In formatPlex the case op = "INTSIGN" is now passed off to +formatIntSign which is a change from the TexFormat domain. +This is done here for presentation mark up to replace the +ugly bound variable that Axiom delivers. For content mark up +this has to be done anyway. + +The formatPlex function also allows for op = "INDEFINTEGRAL". +However I don't know what Axiom command gives rise to this case. +The INTSIGN case already allows for both definite and indefinite +integrals. + +In the function formatSpecial various cases are handled including +SUB and SUPERSUB. These cases are now caught in formatMml and so +the code in formatSpecial doesn't get executed. The only cases +I know of using these are partial derivatives for SUB and ordinary +derivatives or SUPERSUB however in TexFormat the capability is there +to handle multiscripts, i.e. an object with subscripts, superscripts, +pre-subscripts and pre-superscripts but I am so far unaware of any +Axiom command that produces such a multiscripted object. + +Another question is how to represent derivatives. At present I have +differential notation for partials and prime notation for ordinary +derivatives, +but it would be nice to allow for different derivative notations in +different circumstances, maybe some options to )set output mathml on. + +Ordinary derivatives are formatted in formatSuperSub and there are +2 versions, formatSuperSub and formatSuperSub1, which at this point +have to be switched by swapping names. + +<<formatting functions>>= + + atomize(expr : E): L E == + -- This breaks down an expression into a flat list of atomic expressions. + -- expr should be preconditioned. + le : L E := nil() + a : E + letmp : L E + (ATOM(expr)$Lisp@Boolean) or (stringify expr = "NOTHING") => + le := append(le,list(expr)) + letmp := expr pretend L E + for a in letmp repeat + le := append(le,atomize a) + le + + + ungroup(str: S): S == + len : I := #str + len < 14 => str + lrow : S := "<mrow>" + rrow : S := "</mrow>" + -- drop leading and trailing mrows + u1 : US := segment(1,6)$US + u2 : US := segment(len-6,len)$US + if (str.u1 =$S lrow) and (str.u2 =$S rrow) then + u : US := segment(7,len-7)$US + str := str.u + str + + postcondition(str: S): S == +-- str := ungroup str + len : I := #str + plusminus : S := "<mo>+</mo><mo>-</mo>" + pos : I := position(plusminus,str,1) + if pos > 0 then + ustart:US := segment(1,pos-1)$US + uend:US := segment(pos+20,len)$US + str := concat [str.ustart,"<mo>-</mo>",str.uend] + if pos < len-18 then + str := postcondition(str) + str + + + + stringify expr == (mathObject2String$Lisp expr)@S + + + + group str == + concat ["<mrow>",str,"</mrow>"] + + addBraces str == + concat ["<mo>{</mo>",str,"<mo>}</mo>"] + + addBrackets str == + concat ["<mo>[</mo>",str,"<mo>]</mo>"] + + parenthesize str == + concat ["<mo>(</mo>",str,"<mo>)</mo>"] + + precondition expr == + outputTran$Lisp expr + + formatSpecial(op : S, args : L E, prec : I) : S == + arg : E + prescript : Boolean := false + op = "theMap" => "<mtext>theMap(...)</mtext>" + op = "AGGLST" => + formatNary(",",args,prec) + op = "AGGSET" => + formatNary(";",args,prec) + op = "TAG" => + group concat [formatMml(first args,prec), + "<mo>→</mo>", + formatMml(second args,prec)] + --RightArrow + op = "VCONCAT" => + group concat("<mtable><mtr>", + concat(concat([concat("<mtd>",concat(formatMml(u, minPrec),"</mtd>")) + for u in args]::L S), + "</mtr></mtable>")) + op = "CONCATB" => + formatNary(" ",args,prec) + op = "CONCAT" => + formatNary("",args,minPrec) + op = "QUOTE" => + group concat("<mo>'</mo>",formatMml(first args, minPrec)) + op = "BRACKET" => + group addBrackets ungroup formatMml(first args, minPrec) + op = "BRACE" => + group addBraces ungroup formatMml(first args, minPrec) + op = "PAREN" => + group parenthesize ungroup formatMml(first args, minPrec) + op = "OVERBAR" => + null args => "" + group concat ["<mover accent='true'><mrow>",formatMml(first args,minPrec),"</mrow><mo stretchy='true'>¯</mo></mover>"] + --OverBar + op = "ROOT" => + null args => "" + tmp : S := group formatMml(first args, minPrec) + null rest args => concat ["<msqrt>",tmp,"</msqrt>"] + group concat + ["<mroot><mrow>",tmp,"</mrow>",formatMml(first rest args, minPrec),"</mroot>"] + op = "SEGMENT" => + tmp : S := concat [formatMml(first args, minPrec),"<mo>..</mo>"] + group + null rest args => tmp + concat [tmp,formatMml(first rest args, minPrec)] + -- SUB should now be diverted in formatMml although I'll leave + -- the code here for now. + op = "SUB" => + group concat ["<msub>",formatMml(first args, minPrec), + formatSpecial("AGGLST",rest args,minPrec),"</msub>"] + -- SUPERSUB should now be diverted in formatMml although I'll leave + -- the code here for now. + op = "SUPERSUB" => + base:S := formatMml(first args, minPrec) + args := rest args + if #args = 1 then + "<msub><mrow>"base"</mrow><mrow>"formatMml(first args, minPrec)"</mrow></msub>" + else if #args = 2 then + -- it would be nice to substitue ′ for , in the case of + -- an ordinary derivative, it looks a lot better. + "<msubsup><mrow>"base"</mrow><mrow>"formatMml(first args,minPrec)"</mrow><mrow>"formatMml(first rest args, minPrec)"</mrow></msubsup>" + else if #args = 3 then + "<mmultiscripts><mrow>"base"</mrow><mrow>"formatMml(first args,minPrec)"</mrow><mrow>"formatMml(first rest args,minPrec)"</mrow><mprescripts/><mrow>"formatMml(first rest rest args,minPrec)"</mrow><none/></mmultiscripts>" + else if #args = 4 then + "<mmultiscripts><mrow>"base"</mrow><mrow>"formatMml(first args,minPrec)"</mrow><mrow>"formatMml(first rest args,minPrec)"</mrow><mprescripts/><mrow>"formatMml(first rest rest args,minPrec)"</mrow><mrow>"formatMml(first rest rest rest args,minPrec)"</mrow></mmultiscripts>" + else + "<mtext>Problem with multiscript object</mtext>" + op = "SC" => + -- need to handle indentation someday + null args => "" + tmp := formatNaryNoGroup("</mtd></mtr><mtr><mtd>", args, minPrec) + group concat ["<mtable><mtr><mtd>",tmp,"</mtd></mtr></mtable>"] + op = "MATRIX" => formatMatrix rest args + op = "ZAG" => +-- {{+}{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}}{{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}} +-- to format continued fraction traditionally need to intercept it at the +-- formatNary of the "+" + concat [" \zag{",formatMml(first args, minPrec),"}{", + formatMml(first rest args,minPrec),"}"] + concat ["<mtext>not done yet for: ",op,"</mtext>"] + + formatSub(expr : E, args : L E, opPrec : I) : S == + -- This one produces differential notation partial derivatives. + -- It doesn't work in all cases and may not be workable, use + -- formatSub1 below for now. + -- At this time this is only to handle partial derivatives. + -- If the SUB case handles anything else I'm not aware of it. + -- This an example of the 4th partial of y(x,z) w.r.t. x,x,z,x + -- {{{SUB}{y}{{CONCAT}{{CONCAT}{{CONCAT}{{CONCAT}{,}{1}}{{CONCAT}{,}{1}}}{{CONCAT}{,}{2}}}{{CONCAT}{,}{1}}}}{x}{z}} + atomE : L E := atomize(expr) + op : S := stringify first atomE + op ^= "SUB" => "<mtext>Mistake in formatSub: no SUB</mtext>" + stringify first rest rest atomE ^= "CONCAT" => "<mtext>Mistake in formatSub: no CONCAT</mtext>" + -- expecting form for atomE like + --[{SUB}{func}{CONCAT}...{CONCAT}{,}{n}{CONCAT}{,}{n}...{CONCAT}{,}{n}], + --counting the first CONCATs before the comma gives the number of + --derivatives + ndiffs : I := 0 + tmpLE : L E := rest rest atomE + while stringify first tmpLE = "CONCAT" repeat + ndiffs := ndiffs+1 + tmpLE := rest tmpLE + numLS : L S := nil + i : I := 1 + while i < ndiffs repeat + numLS := append(numLS,list(stringify first rest tmpLE)) + tmpLE := rest rest rest tmpLE + i := i+1 + numLS := append(numLS,list(stringify first rest tmpLE)) + -- numLS contains the numbers of the bound variables as strings + -- for the differentiations, thus for the differentiation [x,x,z,x] + -- for y(x,z) numLS = ["1","1","2","1"] + posLS : L S := nil + i := 0 + -- sayTeX$Lisp "formatSub: nargs = "string(#args) + while i < #args repeat + posLS := append(posLS,list(string(i+1))) + i := i+1 + -- posLS contains the positions of the bound variables in args + -- as a list of strings, e.g. for the above example ["1","2"] + tmpS: S := stringify atomE.2 + if ndiffs = 1 then + s : S := "<mfrac><mo>∂</mo><mi>"tmpS"</mi><mrow>" + else + s : S := "<mfrac><mrow><msup><mo>∂</mo><mn>"string(ndiffs)"</mn></msup><mi>"tmpS"</mi></mrow><mrow>" + -- need to find the order of the differentiation w.r.t. the i-th + -- variable + i := 1 + j : I + k : I + tmpS: S + while i < #posLS+1 repeat + j := 0 + k := 1 + while k < #numLS + 1 repeat + if numLS.k = string i then j := j + 1 + k := k+1 + if j > 0 then + tmpS := stringify args.i + if j = 1 then + s := s"<mo>∂</mo><mi>"tmpS"</mi>" + else + s := s"<mo>∂</mo><msup><mi>"tmpS"</mi><mn>"string(j)"</mn></msup>" + i := i + 1 + s := s"</mrow></mfrac><mo>(</mo>" + i := 1 + while i < #posLS+1 repeat + tmpS := stringify args.i + s := s"<mi>"tmpS"</mi>" + if i < #posLS then s := s"<mo>,</mo>" + i := i+1 + s := s"<mo>)</mo>" + + formatSub1(expr : E, args : L E, opPrec : I) : S == + -- This one produces partial derivatives notated by ",n" as + -- subscripts. + -- At this time this is only to handle partial derivatives. + -- If the SUB case handles anything else I'm not aware of it. + -- This an example of the 4th partial of y(x,z) w.r.t. x,x,z,x + -- {{{SUB}{y}{{CONCAT}{{CONCAT}{{CONCAT}{{CONCAT}{,}{1}} + -- {{CONCAT}{,}{1}}}{{CONCAT}{,}{2}}}{{CONCAT}{,}{1}}}}{x}{z}}, + -- here expr is everything in the first set of braces and + -- args is {{x}{z}} + atomE : L E := atomize(expr) + op : S := stringify first atomE + op ^= "SUB" => "<mtext>Mistake in formatSub: no SUB</mtext>" + stringify first rest rest atomE ^= "CONCAT" => "<mtext>Mistake in formatSub: no CONCAT</mtext>" + -- expecting form for atomE like + --[{SUB}{func}{CONCAT}...{CONCAT}{,}{n}{CONCAT}{,}{n}...{CONCAT}{,}{n}], + --counting the first CONCATs before the comma gives the number of + --derivatives + ndiffs : I := 0 + tmpLE : L E := rest rest atomE + while stringify first tmpLE = "CONCAT" repeat + ndiffs := ndiffs+1 + tmpLE := rest tmpLE + numLS : L S := nil + i : I := 1 + while i < ndiffs repeat + numLS := append(numLS,list(stringify first rest tmpLE)) + tmpLE := rest rest rest tmpLE + i := i+1 + numLS := append(numLS,list(stringify first rest tmpLE)) + -- numLS contains the numbers of the bound variables as strings + -- for the differentiations, thus for the differentiation [x,x,z,x] + -- for y(x,z) numLS = ["1","1","2","1"] + posLS : L S := nil + i := 0 + -- sayTeX$Lisp "formatSub: nargs = "string(#args) + while i < #args repeat + posLS := append(posLS,list(string(i+1))) + i := i+1 + -- posLS contains the positions of the bound variables in args + -- as a list of strings, e.g. for the above example ["1","2"] + funcS: S := stringify atomE.2 + s : S := "<msub><mi>"funcS"</mi><mrow>" + i := 1 + while i < #numLS+1 repeat + s := s"<mo>,</mo><mn>"numLS.i"</mn>" + i := i + 1 + s := s"</mrow></msub><mo>(</mo>" + i := 1 + while i < #posLS+1 repeat +-- tmpS := stringify args.i + tmpS := formatMml(first args,minPrec) + args := rest args + s := s"<mi>"tmpS"</mi>" + if i < #posLS then s := s"<mo>,</mo>" + i := i+1 + s := s"<mo>)</mo>" + + formatSuperSub(expr : E, args : L E, opPrec : I) : S == + -- this produces prime notation ordinary derivatives. + -- first have to divine the semantics, add cases as needed + atomE : L E := atomize(expr) + op : S := stringify first atomE + op ^= "SUPERSUB" => "<mtext>Mistake in formatSuperSub: no SUPERSUB1</mtext>" + #args ^= 1 => "<mtext>Mistake in SuperSub1: #args <> 1</mtext>" + var : E := first args + -- should be looking at something like {{SUPERSUB}{var}{ }{,,...,}} for + -- example here's the second derivative of y w.r.t. x + -- {{{SUPERSUB}{y}{ }{,,}}{x}}, expr is the first {} and args is the + -- {x} + funcS : S := stringify first rest atomE + bvarS : S := stringify first args + -- count the number of commas + commaS : S := stringify first rest rest rest atomE + commaTest : S := "," + i : I := 0 + while position(commaTest,commaS,1) > 0 repeat + i := i+1 + commaTest := commaTest"," + s : S := "<msup><mi>"funcS"</mi><mrow>" + j : I := 0 + while j < i repeat + s := s"<mo>′</mo>" + j := j + 1 + s := s"</mrow></msup><mo>⁡</mo><mo>(</mo>"formatMml(first args,minPrec)"<mo>)</mo>" + + formatSuperSub1(expr : E, args : L E, opPrec : I) : S == + -- This one produces ordinary derivatives with differential notation, + -- it needs a little more work yet. + -- first have to divine the semantics, add cases as needed + atomE : L E := atomize(expr) + op : S := stringify first atomE + op ^= "SUPERSUB" => "<mtext>Mistake in formatSuperSub: no SUPERSUB</mtext>" + #args ^= 1 => "<mtext>Mistake in SuperSub: #args <> 1</mtext>" + var : E := first args + -- should be looking at something like {{SUPERSUB}{var}{ }{,,...,}} for + -- example here's the second derivative of y w.r.t. x + -- {{{SUPERSUB}{y}{ }{,,}}{x}}, expr is the first {} and args is the + -- {x} + funcS : S := stringify first rest atomE + bvarS : S := stringify first args + -- count the number of commas + commaS : S := stringify first rest rest rest atomE + commaTest : S := "," + ndiffs : I := 0 + while position(commaTest,commaS,1) > 0 repeat + ndiffs := ndiffs+1 + commaTest := commaTest"," + s : S := "<mfrac><mrow><msup><mo>ⅆ</mo><mn>"string(ndiffs)"</mn></msup><mi>"funcS"</mi></mrow><mrow><mo>ⅆ</mo><msup><mi>"formatMml(first args,minPrec)"</mi><mn>"string(ndiffs)"</mn></msup></mrow></mfrac><mo>⁡</mo><mo>(</mo><mi>"formatMml(first args,minPrec)"</mi><mo>)</mo>" + + formatPlex(op : S, args : L E, prec : I) : S == + checkarg:Boolean := false + hold : S + p : I := position(op,plexOps) + p < 1 => error "unknown plex op" + op = "INTSIGN" => formatIntSign(args,minPrec) + opPrec := plexPrecs.p + n : I := #args + (n ^= 2) and (n ^= 3) => error "wrong number of arguments for plex" + s : S := + op = "SIGMA" => + checkarg := true + "<mo>∑</mo>" + -- Sum + op = "SIGMA2" => + checkarg := true + "<mo>∑</mo>" + -- Sum + op = "PI" => + checkarg := true + "<mo>∏</mo>" + -- Product + op = "PI2" => + checkarg := true + "<mo>∏</mo>" + -- Product +-- op = "INTSIGN" => "<mo>∫</mo>" + -- Integral, int + op = "INDEFINTEGRAL" => "<mo>∫</mo>" + -- Integral, int + "????" + hold := formatMml(first args,minPrec) + args := rest args + if op ^= "INDEFINTEGRAL" then + if hold ^= "" then + s := concat ["<munderover>",s,group hold] + else + s := concat ["<munderover>",s,group " "] + if not null rest args then + hold := formatMml(first args,minPrec) + if hold ^= "" then + s := concat [s,group hold,"</munderover>"] + else + s := concat [s,group " ","</munderover>"] + args := rest args + -- if checkarg true need to test op arg for "+" at least + -- and wrap parentheses if so + if checkarg then + la : L E := (first args pretend L E) + opa : S := stringify first la + if opa = "+" then + s := concat [s,"<mo>(</mo>",formatMml(first args,minPrec),"<mo>)</mo>"] + else s := concat [s,formatMml(first args,minPrec)] + else s := concat [s,formatMml(first args,minPrec)] + else + hold := group concat [hold,formatMml(first args,minPrec)] + s := concat [s,hold] +-- if opPrec < prec then s := parenthesize s +-- getting ugly parentheses on fractions + group s + + formatIntSign(args : L E, opPrec : I) : S == + -- the original OutputForm expression looks something like this: + -- {{INTSIGN}{NOTHING or lower limit?} + -- {bvar or upper limit?}{{*}{integrand}{{CONCAT}{d}{axiom var}}}} + -- the args list passed here consists of the rest of this list, i.e. + -- starting at the NOTHING or ... + (stringify first args) = "NOTHING" => + -- the bound variable is the second one in the argument list + bvar : E := first rest args + bvarS : S := stringify bvar + tmpS : S + i : I := 0 + u1 : US + u2 : US + -- this next one atomizes the integrand plus differential + atomE : L E := atomize(first rest rest args) + -- pick out the bound variable used by axiom + varRS : S := stringify last(atomE) + tmpLE : L E := ((first rest rest args) pretend L E) + integrand : S := formatMml(first rest tmpLE,minPrec) + -- replace the bound variable, i.e. axiom uses someting of the form + -- %A for the bound variable and puts the original variable used + -- in the input command as a superscript on the integral sign. + -- I'm assuming that the axiom variable is 2 characters. + while (i := position(varRS,integrand,i+1)) > 0 repeat + u1 := segment(1,i-1)$US + u2 := segment(i+2,#integrand)$US + integrand := concat [integrand.u1,bvarS,integrand.u2] + concat ["<mrow><mo>∫</mo>" integrand "<mo>ⅆ</mo><mi>" bvarS "</mi></mrow>"] + + lowlim : S := stringify first args + highlim : S := stringify first rest args + bvar : E := last atomize(first rest rest args) + bvarS : S := stringify bvar + tmpLE : L E := ((first rest rest args) pretend L E) + integrand : S := formatMml(first rest tmpLE,minPrec) + concat ["<mrow><munderover><mo>∫</mo><mi>" lowlim "</mi><mi>" highlim "</mi></munderover>" integrand "<mo>ⅆ</mo><mi>" bvarS "</mi></mrow>"] + + + formatMatrix(args : L E) : S == + -- format for args is [[ROW ...],[ROW ...],[ROW ...]] + -- generate string for formatting columns (centered) + group addBrackets concat + ["<mtable><mtr><mtd>",formatNaryNoGroup("</mtd></mtr><mtr><mtd>",args,minPrec), + "</mtd></mtr></mtable>"] + + formatFunction(op : S, args : L E, prec : I) : S == + group concat ["<mo>",op,"</mo>",parenthesize formatNary(",",args,minPrec)] + + formatNullary(op : S) == + op = "NOTHING" => "" + group concat ["<mo>",op,"</mo><mo>(</mo><mo>)</mo>"] + + formatUnary(op : S, arg : E, prec : I) == + p : I := position(op,unaryOps) + p < 1 => error "unknown unary op" + opPrec := unaryPrecs.p + s : S := concat ["<mo>",op,"</mo>",formatMml(arg,opPrec)] + opPrec < prec => group parenthesize s + op = "-" => s + group s + + formatBinary(op : S, args : L E, prec : I) : S == + p : I := position(op,binaryOps) + p < 1 => error "unknown binary op" + opPrec := binaryPrecs.p + -- if base op is product or sum need to add parentheses + if ATOM(first args)$Lisp@Boolean then + opa:S := stringify first args + else + la : L E := (first args pretend L E) + opa : S := stringify first la + if (opa = "SIGMA" or opa = "SIGMA2" or opa = "PI" or opa = "PI2") and op = "**" then + s1 : S := concat ["<mo>(</mo>",formatMml(first args, opPrec),"<mo>)</mo>"] + else + s1 : S := formatMml(first args, opPrec) + s2 : S := formatMml(first rest args, opPrec) + op := + op = "|" => s := concat ["<mrow>",s1,"</mrow><mo>",op,"</mo><mrow>",s2,"</mrow>"] + op = "**" => s := concat ["<msup><mrow>",s1,"</mrow><mrow>",s2,"</mrow></msup>"] + op = "/" => s := concat ["<mfrac><mrow>",s1,"</mrow><mrow>",s2,"</mrow></mfrac>"] + op = "OVER" => s := concat ["<mfrac><mrow>",s1,"</mrow><mrow>",s2,"</mrow></mfrac>"] + op = "+->" => s := concat ["<mrow>",s1,"</mrow><mo>",op,"</mo><mrow>",s2,"</mrow>"] + s := concat ["<mrow>",s1,"</mrow><mo>",op,"</mo><mrow>",s2,"</mrow>"] + group + op = "OVER" => s +-- opPrec < prec => parenthesize s +-- ugly parentheses? + s + + formatNary(op : S, args : L E, prec : I) : S == + group formatNaryNoGroup(op, args, prec) + + formatNaryNoGroup(op : S, args : L E, prec : I) : S == + checkargs:Boolean := false + null args => "" + p : I := position(op,naryOps) + p < 1 => error "unknown nary op" + -- need to test for "ZAG" case and divert it here + -- ex 1. continuedFraction(314159/100000) + -- {{+}{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}} + -- {{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}} + -- this is the preconditioned output form + -- including "op", the args list would be the rest of this + -- i.e op = '+' and args = {{3}{{ZAG}{1}{7}}{{ZAG}{1}{15}} + -- {{ZAG}{1}{1}}{{ZAG}{1}{25}}{{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}} + -- ex 2. continuedFraction(14159/100000) + -- this one doesn't have the leading integer + -- {{+}{{ZAG}{1}{7}}{{ZAG}{1}{15}}{{ZAG}{1}{1}}{{ZAG}{1}{25}} + -- {{ZAG}{1}{1}}{{ZAG}{1}{7}}{{ZAG}{1}{4}}} + -- + -- ex 3. continuedFraction(3,repeating [1], repeating [3,6]) + -- {{+}{3}{{ZAG}{1}{3}}{{ZAG}{1}{6}}{{ZAG}{1}{3}}{{ZAG}{1}{6}} + -- {{ZAG}{1}{3}}{{ZAG}{1}{6}}{{ZAG}{1}{3}}{{ZAG}{1}{6}} + -- {{ZAG}{1}{3}}{{ZAG}{1}{6}}{...}} + -- In each of these examples the args list consists of the terms + -- following the '+' op + -- so the first arg could be a "ZAG" or something + -- else, but the second arg looks like it has to be "ZAG", so maybe + -- test for #args > 1 and args.2 contains "ZAG". + -- Note that since the resulting MathML <mfrac>s are nested we need + -- to handle the whole continued fraction at once, i.e. we can't + -- just look for, e.g., {{ZAG}{1}{6}} + (#args > 1) and (position("ZAG",stringify first rest args,1) > 0) => + tmpS : S := stringify first args + position("ZAG",tmpS,1) > 0 => formatZag(args) +-- position("ZAG",tmpS,1) > 0 => formatZag1(args) + concat [formatMml(first args,minPrec) "<mo>+</mo>" formatZag(rest args)] + -- At least for the ops "*","+","-" we need to test to see if a sigma or pi + -- is one of their arguments because we might need parentheses as indicated + -- by the problem with summation(operator(f)(i),i=1..n)+1 versus + -- summation(operator(f)(i)+1,i=1..n) having identical displays as of + -- 2007-12-21 + op := + op = "," => "<mo>,</mo>" --originally , \: + op = ";" => "<mo>;</mo>" --originally ; \: should figure these out + op = "*" => + checkargs := true + "<mo>⁢</mo>" + -- InvisibleTimes + op = " " => "<mspace width='0.5em'/>" + op = "ROW" => "</mtd><mtd>" + op = "+" => + checkargs := true + "<mo>+</mo>" + op = "-" => + checkargs := true + "<mo>-</mo>" + op + l : L S := nil + opPrec := naryPrecs.p + -- if checkargs is true check each arg except last one to see if it's + -- a sigma or pi and if so add parentheses. Other op's may have to be + -- checked for in future + count:I := 1 + for a in args repeat + if checkargs then + if count < #args then + -- check here for sum or product + if ATOM(a)$Lisp@Boolean then + opa:S := stringify a + else + la : L E := (a pretend L E) + opa : S := stringify first la + if opa = "SIGMA" or opa = "SIGMA2" or opa = "PI" or opa = "PI2" then + l := concat(op,concat(concat ["<mo>(</mo>",formatMml(a,opPrec),"<mo>)</mo>"],l)$L(S))$L(S) + else l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S) + else l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S) + else l := concat(op,concat(formatMml(a,opPrec),l)$L(S))$L(S) + count := count + 1 + s : S := concat reverse rest l + opPrec < prec => parenthesize s + s + + formatZag(args : L E) : S == + -- args will be a list of things like this {{ZAG}{1}{7}}, the ZAG + -- must be there, the '1' and '7' could conceivably be more complex + -- expressions + tmpZag : L E := first args pretend L E + -- may want to test that tmpZag contains 'ZAG' + #args > 1 => "<mfrac>"formatMml(first rest tmpZag,minPrec)"<mrow><mn>"formatMml(first rest rest tmpZag,minPrec)"</mn><mo>+</mo>"formatZag(rest args)"</mrow></mfrac>" + (first args = "...":: E)@Boolean => "<mo>…</mo>" + op:S := stringify first args + position("ZAG",op,1) > 0 => + "<mfrac>"formatMml(first rest tmpZag,minPrec)formatMml(first rest rest tmpZag,minPrec)"</mfrac>" + error "formatZag: Last argument in ZAG construct has unknown operator: "op + + formatZag1(args : L E) : S == + -- make alternative ZAG format without diminishing fonts, maybe + -- use a table + -- {{ZAG}{1}{7}} + tmpZag : L E := first args pretend L E + #args > 1 => "<mfrac>"formatMml(first rest tmpZag,minPrec)"<mrow><mn>"formatMml(first rest rest tmpZag,minPrec)"</mn><mo>+</mo>"formatZag(rest args)"</mrow></mfrac>" + (first args = "...":: E)@Boolean => "<mo>…</mo>" + error "formatZag1: Unexpected kind of ZAG" + + formatMml(expr : E,prec : I) == + i,len : Integer + intSplitLen : Integer := 20 + ATOM(expr)$Lisp@Boolean => + str := stringify expr + len := #str + -- this bit seems to deal with integers + FIXP$Lisp expr => + i := expr pretend Integer + if (i < 0) or (i > 9) + then + group + nstr : String := "" + -- insert some blanks into the string, if too long + while ((len := #str) > intSplitLen) repeat + nstr := concat [nstr," ", + elt(str,segment(1,intSplitLen)$US)] + str := elt(str,segment(intSplitLen+1)$US) + empty? nstr => concat ["<mn>",str,"</mn>"] + nstr := + empty? str => nstr + concat [nstr," ",str] + concat ["<mn>",elt(nstr,segment(2)$US),"</mn>"] + else str := concat ["<mn>",str,"</mn>"] + str = "%pi" => "<mi>π</mi>" + -- pi + str = "%e" => "<mi>ⅇ</mi>" + -- ExponentialE + str = "%i" => "<mi>ⅈ</mi>" + -- ImaginaryI + len > 0 and str.1 = char "%" => concat(concat("<mi>",str),"</mi>") + len > 1 and digit? str.1 => concat ["<mn>",str,"</mn>"] -- should handle floats + -- presumably this is a literal string + len > 0 and str.1 = char "_"" => + concat(concat("<mtext>",str),"</mtext>") + len = 1 and str.1 = char " " => " " + (i := position(str,specialStrings)) > 0 => + specialStringsInMML.i + (i := position(char " ",str)) > 0 => + -- We want to preserve spacing, so use a roman font. + -- What's this for? Leave the \rm in for now so I can see + -- where it arises. Removed 2007-02-14 + concat(concat("<mtext>",str),"</mtext>") + -- if we get to here does that mean it's a variable? + concat ["<mi>",str,"</mi>"] + l : L E := (expr pretend L E) + null l => blank + op : S := stringify first l + args : L E := rest l + nargs : I := #args + -- need to test here in case first l is SUPERSUB case and then + -- pass first l and args to formatSuperSub. + position("SUPERSUB",op,1) > 0 => + formatSuperSub(first l,args,minPrec) + -- now test for SUB + position("SUB",op,1) > 0 => + formatSub1(first l,args,minPrec) + + -- special cases + member?(op, specialOps) => formatSpecial(op,args,prec) + member?(op, plexOps) => formatPlex(op,args,prec) + + -- nullary case + 0 = nargs => formatNullary op + + -- unary case + (1 = nargs) and member?(op, unaryOps) => + formatUnary(op, first args, prec) + + -- binary case + (2 = nargs) and member?(op, binaryOps) => + formatBinary(op, args, prec) + + -- nary case + member?(op,naryNGOps) => formatNaryNoGroup(op,args, prec) + member?(op,naryOps) => formatNary(op,args, prec) + + op := formatMml(first l,minPrec) + formatFunction(op,args,prec) + +@ +\section{Mathematical Markup Language Form} +<<package MMLFORM MathMLForm>>= +<<public declarations>> +<<private constant declarations>> +<<private function declarations>> +<<public function definitions>> +<<display functions>> +<<formatting functions>> + +@ +\section{License} +<<license>>= +--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. +--All rights reserved. +-- +--Redistribution and use in source and binary forms, with or without +--modification, are permitted provided that the following conditions are +--met: +-- +-- - Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- +-- - Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in +-- the documentation and/or other materials provided with the +-- distribution. +-- +-- - Neither the name of The Numerical ALgorithms Group Ltd. nor the +-- names of its contributors may be used to endorse or promote products +-- derived from this software without specific prior written permission. +-- +--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +@ +<<*>>= +<<license>> +<<package MMLFORM MathMLForm>> +@ +\eject +\begin{thebibliography}{99} +\bibitem{1} nothing +\end{thebibliography} +\end{document} |