diff --git a/books/bookvol10.3.pamphlet b/books/bookvol10.3.pamphlet index 00a3e2a..905a439 100644 --- a/books/bookvol10.3.pamphlet +++ b/books/bookvol10.3.pamphlet @@ -58281,6 +58281,1600 @@ MakeCachableSet(S:SetCategory): Exports == Implementation where @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{domain MMLFORM MathMLFormat} + +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. + +\subsection{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. + +\subsection{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. + +\subsection{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(314159/100000) + +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. + +\subsection{)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 (boottran::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 "($\vert{}$MathMLFormat$\vert$ . 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. + +\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. + +<>= +)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 tags. + +@ +\subsection{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 ","&",""]$(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","SLASH" ] + + -- 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"] + specialStringsInMML : L S := + ["cos","cot","csc","log","sec","sin","tan", + "cosh","coth","csch","sech","sinh","tanh", + "arccos","arcsin","arctan","erf","","$",""] + +@ +\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 + +<>= + -- 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: ... + 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 + + 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 "" + displayElt(s) + sayTeX$Lisp "" + s + + coerceL(expr : E): S == + s : S := postcondition formatMml(precondition expr, minPrec) + sayTeX$Lisp "" + sayTeX$Lisp s + sayTeX$Lisp "" + s + + display(mathml : S): Void == + sayTeX$Lisp "" + sayTeX$Lisp mathml + sayTeX$Lisp "" + 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 + +<>= + + 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. "" + enE:I -- marks end of element, e.g. " ... " + 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 " ... " + -- 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 [""] + 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 \verb+\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. + +<>= + + 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 := "" + rrow : S := "" + -- 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 := "+-" + 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,"-",str.uend] + if pos < len-18 then + str := postcondition(str) + str + + stringify expr == (mathObject2String$Lisp expr)@S + + group str == + concat ["",str,""] + + addBraces str == + concat ["{",str,"}"] + + addBrackets str == + concat ["[",str,"]"] + + parenthesize str == + concat ["(",str,")"] + + precondition expr == + outputTran$Lisp expr + + formatSpecial(op : S, args : L E, prec : I) : S == + arg : E + prescript : Boolean := false + op = "theMap" => "theMap(...)" + op = "AGGLST" => + formatNary(",",args,prec) + op = "AGGSET" => + formatNary(";",args,prec) + op = "TAG" => + group concat [formatMml(first args,prec), + "", + formatMml(second args,prec)] + --RightArrow + op = "SLASH" => + group concat [formatMml(first args,prec), + "/",formatMml(second args,prec)] + op = "VCONCAT" => + group concat("", + concat(concat([concat("",concat(formatMml(u, minPrec),"")) + for u in args]::L S), + "")) + op = "CONCATB" => + formatNary(" ",args,prec) + op = "CONCAT" => + formatNary("",args,minPrec) + op = "QUOTE" => + group concat("'",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 ["",formatMml(first args,minPrec),"¯"] + --OverBar + op = "ROOT" => + null args => "" + tmp : S := group formatMml(first args, minPrec) + null rest args => concat ["",tmp,""] + group concat + ["",tmp,"",formatMml(first rest args, minPrec),""] + op = "SEGMENT" => + tmp : S := concat [formatMml(first args, minPrec),".."] + 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 ["",formatMml(first args, minPrec), + formatSpecial("AGGLST",rest args,minPrec),""] + -- 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 + ""base""formatMml(first args, minPrec)"" + else if #args = 2 then + -- it would be nice to substitue ′ for , in the case of + -- an ordinary derivative, it looks a lot better. + ""base""formatMml(first args,minPrec)""formatMml(first rest args, minPrec)"" + else if #args = 3 then + ""base""formatMml(first args,minPrec)""formatMml(first rest args,minPrec)""formatMml(first rest rest args,minPrec)"" + else if #args = 4 then + ""base""formatMml(first args,minPrec)""formatMml(first rest args,minPrec)""formatMml(first rest rest args,minPrec)""formatMml(first rest rest rest args,minPrec)"" + else + "Problem with multiscript object" + op = "SC" => + -- need to handle indentation someday + null args => "" + tmp := formatNaryNoGroup("", args, minPrec) + group concat ["",tmp,""] + 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 ["not done yet for: ",op,""] + + 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" => "Mistake in formatSub: no SUB" + stringify first rest rest atomE ^= "CONCAT" => "Mistake in formatSub: no CONCAT" + -- 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 := ""tmpS"" + else + s : S := ""string(ndiffs)""tmpS"" + -- 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""tmpS"" + else + s := s""tmpS""string(j)"" + i := i + 1 + s := s"(" + i := 1 + while i < #posLS+1 repeat + tmpS := stringify args.i + s := s""tmpS"" + if i < #posLS then s := s"," + i := i+1 + s := s")" + + 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" => "Mistake in formatSub: no SUB" + stringify first rest rest atomE ^= "CONCAT" => "Mistake in formatSub: no CONCAT" + -- 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 := ""funcS"" + i := 1 + while i < #numLS+1 repeat + s := s","numLS.i"" + i := i + 1 + s := s"(" + i := 1 + while i < #posLS+1 repeat +-- tmpS := stringify args.i + tmpS := formatMml(first args,minPrec) + args := rest args + s := s""tmpS"" + if i < #posLS then s := s"," + i := i+1 + s := s")" + + 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 +-- WriteLine$Lisp "SuperSub1 begin" + atomE : L E := atomize(expr) + op : S := stringify first atomE +-- WriteLine$Lisp "op: "op + op ^= "SUPERSUB" => _ + "Mistake in formatSuperSub: no SUPERSUB1" + #args ^= 1 => "Mistake in SuperSub1: #args <> 1" + 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 +-- WriteLine$Lisp "funcS: "funcS + bvarS : S := stringify first args +-- WriteLine$Lisp "bvarS: "bvarS + -- 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 := ""funcS"" +-- WriteLine$Lisp "s: "s + j : I := 0 + while j < i repeat + s := s"" + j := j + 1 + s := s"("formatMml(first args,minPrec)")" + + 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 +-- WriteLine$Lisp "SuperSub begin" + atomE : L E := atomize(expr) + op : S := stringify first atomE + op ^= "SUPERSUB" => _ + "Mistake in formatSuperSub: no SUPERSUB" + #args ^= 1 => "Mistake in SuperSub: #args <> 1" + 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 := ""string(ndiffs)""funcS""formatMml(first args,minPrec)""string(ndiffs)"("formatMml(first args,minPrec)")" + + 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 + "" + -- Sum + op = "SIGMA2" => + checkarg := true + "" + -- Sum + op = "PI" => + checkarg := true + "" + -- Product + op = "PI2" => + checkarg := true + "" + -- Product +-- op = "INTSIGN" => "" + -- Integral, int + op = "INDEFINTEGRAL" => "" + -- Integral, int + "????" + hold := formatMml(first args,minPrec) + args := rest args + if op ^= "INDEFINTEGRAL" then + if hold ^= "" then + s := concat ["",s,group hold] + else + s := concat ["",s,group " "] + if not null rest args then + hold := formatMml(first args,minPrec) + if hold ^= "" then + s := concat [s,group hold,""] + else + s := concat [s,group " ",""] + 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,"(",formatMml(first args,minPrec),")"] + 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 ["" integrand "" bvarS ""] + + 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 ["" lowlim "" highlim "" integrand "" bvarS ""] + + + formatMatrix(args : L E) : S == + -- format for args is [[ROW ...],[ROW ...],[ROW ...]] + -- generate string for formatting columns (centered) + group addBrackets concat + ["",formatNaryNoGroup("",args,minPrec), + ""] + + formatFunction(op : S, args : L E, prec : I) : S == + group concat ["",op,"",parenthesize formatNary(",",args,minPrec)] + + formatNullary(op : S) == + op = "NOTHING" => "" + group concat ["",op,"()"] + + formatUnary(op : S, arg : E, prec : I) == + p : I := position(op,unaryOps) + p < 1 => error "unknown unary op" + opPrec := unaryPrecs.p + s : S := concat ["",op,"",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 ["(",formatMml(first args, opPrec),")"] + else + s1 : S := formatMml(first args, opPrec) + s2 : S := formatMml(first rest args, opPrec) + op := + op = "|" => s := concat ["",s1,"",op,"",s2,""] + op = "**" => s := concat ["",s1,"",s2,""] + op = "/" => s := concat ["",s1,"",s2,""] + op = "OVER" => s := concat ["",s1,"",s2,""] + op = "+->" => s := concat ["",s1,"",op,"",s2,""] + s := concat ["",s1,"",op,"",s2,""] + 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 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) "+" 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-21-21 + op := + op = "," => "," --originally , \: + op = ";" => ";" --originally ; \: should figure these out + op = "*" => "" + -- InvisibleTimes + op = " " => "" + op = "ROW" => "" + op = "+" => + checkargs := true + "+" + op = "-" => + checkargs := true + "-" + 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 +-- WriteLine$Lisp "checking args" + 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 ["(",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) + 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 => ""formatMml(first rest tmpZag,minPrec)""formatMml(first rest rest tmpZag,minPrec)"+"formatZag(rest args)"" + -- EQUAL(tmpZag, "...")$Lisp => "" + (first args = "..."::E)@Boolean => "" + position("ZAG",stringify first args,1) > 0 => + ""formatMml(first rest tmpZag,minPrec)formatMml(first rest rest tmpZag,minPrec)"" + "formatZag: Unexpected kind of ZAG" + + + 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 => ""formatMml(first rest tmpZag,minPrec)""formatMml(first rest rest tmpZag,minPrec)"+"formatZag(rest args)"" + (first args = "...":: E)@Boolean => "" + 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 ["",str,""] + nstr := + empty? str => nstr + concat [nstr," ",str] + concat ["",elt(nstr,segment(2)$US),""] + else str := concat ["",str,""] + str = "%pi" => "π" + -- pi + str = "%e" => "" + -- ExponentialE + str = "%i" => "" + -- ImaginaryI + len > 0 and str.1 = char "%" => concat(concat("",str),"") + -- should handle floats + len > 1 and digit? str.1 => concat ["",str,""] + -- presumably this is a literal string + len > 0 and str.1 = char "_"" => + concat(concat("",str),"") + 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("",str),"") + -- if we get to here does that mean it's a variable? + concat ["",str,""] + 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) + +@ +\subsection{Mathematical Markup Language Form} +<>= +)set break resume +)spool MathMLFormat.output +)set message test on +)set message auto off +)clear all + +--S 1 of 5 +)set output mathml on + +--R +--E 1 + +--S 2 of 5 +1/2 +--R +--R +--R 1 +--R (1) - +--R 2 +--R +--R12 +--R +--R +--R Type: Fraction Integer +--E 2 + +--S 3 of 5 +1/(x+5) +--R +--R +--R 1 +--R (2) ----- +--R x + 5 +--R +--R1x+5 +--R +--R +--R Type: Fraction Polynomial Integer +--E 3 + +--S 4 of 5 +(x+3)/(y-5) +--R +--R +--R x + 3 +--R (3) ----- +--R y - 5 +--R +--Rx+3y-5 +--R +--R +--R Type: Fraction Polynomial Integer +--E 4 + +--S 5 of 5 +)show MathMLFormat +--R MathMLFormat is a domain constructor +--R Abbreviation for MathMLFormat is MMLFORM +--R This constructor is exposed in this frame. +--R Issue )edit bookvol10.3.spad.pamphlet to see algebra source code for MMLFORM +--R +--R------------------------------- Operations -------------------------------- +--R ?=? : (%,%) -> Boolean coerce : OutputForm -> String +--R coerce : % -> OutputForm coerceL : OutputForm -> String +--R coerceS : OutputForm -> String display : String -> Void +--R exprex : OutputForm -> String hash : % -> SingleInteger +--R latex : % -> String ?~=? : (%,%) -> Boolean +--R +--E 5 + +)spool +)lisp (bye) + +@ +<>= +==================================================================== +MathMLFormat examples +==================================================================== + +MathML is an HTML-like markup language for mathematics. It uses the +"knuckle" syntax of HTML such as "" to introduce a math operator +and "" to mark the end of the operator. Axiom can generate +MathML output and does so when it communicates to the browser front end. + +This output is enabled by + + )set output mathml on + +after which you'll see the MathML markup as well as the algebra. +Note that you can turn off the algebra output with + + )set output algebra off + +but we don't do that here so you can compare the output. + + 1/2 + + 1/2 + + + + 1 + / + 2 + + + + + 1/(x+5) + + 1/(x + 5) + + + + 1 + / + + ( + x + + + 5 + ) + + + + + (x+3)/(y-5) + + (x + 3)/(y - 5) + + + + + ( + x + + + 3 + ) + + / + + ( + y + - + 5 + ) + + + R + +See Also: +o )show MathMLFormat + +@ +\pagehead{MathMLForm}{MMLFORM} +\pagepic{ps/v104mathmlform.ps}{MMLFORM}{1.00} + +{\bf Exports:}\\ +\begin{tabular}{lllll} +\cross{MMLFORM}{coerce} & +\cross{MMLFORM}{coerceL} & +\cross{MMLFORM}{coerceS} & +\cross{MMLFORM}{display} & +\cross{MMLFORM}{exprex} \\ +\cross{MMLFORM}{hash} & +\cross{MMLFORM}{latex} & +\cross{MMLFORM}{?=?} & +\cross{MMLFORM}{?\~{}=?} & +\end{tabular} + +<>= +<> +<> +<> +<> +<> +<> + +@ +<>= +"MMLFORM" [color="#FF4488",href="bookvol10.4.pdf#nameddest=MMLFORM"] +"FSAGG" [color="#4488FF",href="bookvol10.2.pdf#nameddest=FSAGG"] +"MMLFORM" -> "FSAGG" + +@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{domain MATRIX Matrix} <>= )set break resume @@ -99187,6 +100781,169 @@ in addition we need to add a line defining [[PI2]] in [[formatPlex]]: <>= op = "PI2" => "\prod" @ +<>= +)set break resume +)sys rm -f TexFormat.output +)spool TexFormat.output +)set message test on +)set message auto off +)clear all + +--S 1 of 11 +(1/2)::TEX +--R +--R +--R (1) ["$$","\frac{1}{2} ","$$"] +--R Type: TexFormat +--E 1 + +--S 2 of 11 +(1/(x+5))::TEX +--R +--R +--R (2) ["$$","\frac{1}{{x+5}} ","$$"] +--R Type: TexFormat +--E 2 + +--S 3 of 11 +((x+3)/(y-5))::TEX +--R +--R +--R (3) ["$$","\frac{{x+3}}{{y -5}} ","$$"] +--R Type: TexFormat +--E 3 + +--S 4 of 11 +)set output fraction horizontal +--R +--E 4 + +--S 5 of 11 +(1/2)::TEX +--R +--R +--R (4) ["$$","SLASH ","\left(","{1, \: 2} ","\right)","$$"] +--R Type: TexFormat +--E 5 + +--S 6 of 11 +(1/(x+5))::TEX +--R +--R +--R (5) +--R ["$$","SLASH ","\left(","{1, \: {\left( x+5 ","\right)}}","\right)","$$"] +--R Type: TexFormat +--E 6 + +--S 7 of 11 +)set output mathml on +--R +--E 7 + +--S 8 of 11 +1/2 +--R +--R +--R (6) 1/2 +--R +--R1/2 +--R +--R +--R Type: Fraction Integer +--E 8 + +--S 9 of 11 +1/(x+5) +--R +--R +--R (7) 1/(x + 5) +--R +--R1/(x+5) +--R +--R +--R Type: Fraction Polynomial Integer +--E 9 + +--S 10 of 11 +(x+3)/(y-5) +--R +--R +--R (8) (x + 3)/(y - 5) +--R +--R(x+3)/(y-5) +--R +--R +--R Type: Fraction Polynomial Integer +--E 10 + +--S 11 of 11 +)show TexFormat +--R +--R TexFormat is a domain constructor +--R Abbreviation for TexFormat is TEX +--R This constructor is exposed in this frame. +--R Issue )edit bookvol10.3.spad.pamphlet to see algebra source code for TEX +--R +--R------------------------------- Operations -------------------------------- +--R ?=? : (%,%) -> Boolean coerce : OutputForm -> % +--R coerce : % -> OutputForm display : % -> Void +--R display : (%,Integer) -> Void epilogue : % -> List String +--R hash : % -> SingleInteger latex : % -> String +--R new : () -> % prologue : % -> List String +--R tex : % -> List String ?~=? : (%,%) -> Boolean +--R convert : (OutputForm,Integer,OutputForm) -> % +--R convert : (OutputForm,Integer) -> % +--R setEpilogue! : (%,List String) -> List String +--R setPrologue! : (%,List String) -> List String +--R setTex! : (%,List String) -> List String +--R +--E 11 + +)spool +)lisp (bye) +@ +<>= +==================================================================== +TexFormat examples +==================================================================== + +You can ask Axiom to show latex output. In particular, this can be +used for complex output. + +(1/2)::TEX + + ["$$","\frac{1}{2} ","$$"] + +(1/(x+5))::TEX + + ["$$","\frac{1}{{x+5}} ","$$"] + +((x+3)/(y-5))::TEX + + ["$$","\frac{{x+3}}{{y -5}} ","$$"] + + +We can change the fraction display so it is horizontal: + +)set output fraction horizontal + +(1/2)::TEX + + ["$$","SLASH ","\left(","{1, \: 2} ","\right)","$$"] + +(1/(x+5))::TEX + + ["$$","SLASH ","\left(","{1, \: {x+5}} ","\right)","$$"] + +((x+3)/(y-5))::TEX + + ["$$","SLASH ","\left(","{{x+3}, \: {y -5}} ","\right)","$$"] + + +See Also: +o )show TexFormat + +@ \pagehead{TexFormat}{TEX} \pagepic{ps/v103texformat.ps}{TEX}{1.00} @@ -99286,11 +101043,13 @@ TexFormat(): public == private where prologue: $ -> L S ++ prologue(t) extracts the prologue section of a TeX form t. setEpilogue!: ($, L S) -> L S - ++ setEpilogue!(t,strings) sets the epilogue section of a TeX form t to strings. + ++ setEpilogue!(t,strings) sets the epilogue section of a TeX form t + ++ to strings. setTex!: ($, L S) -> L S ++ setTex!(t,strings) sets the TeX section of a TeX form t to strings. setPrologue!: ($, L S) -> L S - ++ setPrologue!(t,strings) sets the prologue section of a TeX form t to strings. + ++ setPrologue!(t,strings) sets the prologue section of a TeX form t + ++ to strings. private == add import OutputForm @@ -117310,6 +119069,7 @@ Note that this code is not included in the generated catdef.spad file. <> <> <> +<> <> <> <> diff --git a/books/bookvol10.4.pamphlet b/books/bookvol10.4.pamphlet index a05a486..5f0db1e 100644 --- a/books/bookvol10.4.pamphlet +++ b/books/bookvol10.4.pamphlet @@ -57408,1438 +57408,6 @@ MappingPackage4(A:SetCategory, B:Ring): @ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{package MMLFORM MathMLFormat} - -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. - -\subsection{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. - -\subsection{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. - -\subsection{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(314159/100000) - -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. - -\subsection{)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 (boottran::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 "($\vert{}$MathMLFormat$\vert$ . 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. - -\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. - -<>= -)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 tags. - -@ -\subsection{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 ","&",""]$(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"] - specialStringsInMML : L S := - ["cos","cot","csc","log","sec","sin","tan", - "cosh","coth","csch","sech","sinh","tanh", - "arccos","arcsin","arctan","erf","","$",""] - -@ -\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 - -<>= - -- 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: ... - 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 - - 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 "" - displayElt(s) - sayTeX$Lisp "" - s - - coerceL(expr : E): S == - s : S := postcondition formatMml(precondition expr, minPrec) - sayTeX$Lisp "" - sayTeX$Lisp s - sayTeX$Lisp "" - s - - display(mathml : S): Void == - sayTeX$Lisp "" - sayTeX$Lisp mathml - sayTeX$Lisp "" - 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 - -<>= - - 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. "" - enE:I -- marks end of element, e.g. " ... " - 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 " ... " - -- 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 [""] - 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 \verb+\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. - -<>= - - 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 := "" - rrow : S := "" - -- 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 := "+-" - 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,"-",str.uend] - if pos < len-18 then - str := postcondition(str) - str - - stringify expr == (mathObject2String$Lisp expr)@S - - group str == - concat ["",str,""] - - addBraces str == - concat ["{",str,"}"] - - addBrackets str == - concat ["[",str,"]"] - - parenthesize str == - concat ["(",str,")"] - - precondition expr == - outputTran$Lisp expr - - formatSpecial(op : S, args : L E, prec : I) : S == - arg : E - prescript : Boolean := false - op = "theMap" => "theMap(...)" - op = "AGGLST" => - formatNary(",",args,prec) - op = "AGGSET" => - formatNary(";",args,prec) - op = "TAG" => - group concat [formatMml(first args,prec), - "", - formatMml(second args,prec)] - --RightArrow - op = "VCONCAT" => - group concat("", - concat(concat([concat("",concat(formatMml(u, minPrec),"")) - for u in args]::L S), - "")) - op = "CONCATB" => - formatNary(" ",args,prec) - op = "CONCAT" => - formatNary("",args,minPrec) - op = "QUOTE" => - group concat("'",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 ["",formatMml(first args,minPrec),"¯"] - --OverBar - op = "ROOT" => - null args => "" - tmp : S := group formatMml(first args, minPrec) - null rest args => concat ["",tmp,""] - group concat - ["",tmp,"",formatMml(first rest args, minPrec),""] - op = "SEGMENT" => - tmp : S := concat [formatMml(first args, minPrec),".."] - 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 ["",formatMml(first args, minPrec), - formatSpecial("AGGLST",rest args,minPrec),""] - -- 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 - ""base""formatMml(first args, minPrec)"" - else if #args = 2 then - -- it would be nice to substitue ′ for , in the case of - -- an ordinary derivative, it looks a lot better. - ""base""formatMml(first args,minPrec)""formatMml(first rest args, minPrec)"" - else if #args = 3 then - ""base""formatMml(first args,minPrec)""formatMml(first rest args,minPrec)""formatMml(first rest rest args,minPrec)"" - else if #args = 4 then - ""base""formatMml(first args,minPrec)""formatMml(first rest args,minPrec)""formatMml(first rest rest args,minPrec)""formatMml(first rest rest rest args,minPrec)"" - else - "Problem with multiscript object" - op = "SC" => - -- need to handle indentation someday - null args => "" - tmp := formatNaryNoGroup("", args, minPrec) - group concat ["",tmp,""] - 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 ["not done yet for: ",op,""] - - 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" => "Mistake in formatSub: no SUB" - stringify first rest rest atomE ^= "CONCAT" => "Mistake in formatSub: no CONCAT" - -- 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 := ""tmpS"" - else - s : S := ""string(ndiffs)""tmpS"" - -- 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""tmpS"" - else - s := s""tmpS""string(j)"" - i := i + 1 - s := s"(" - i := 1 - while i < #posLS+1 repeat - tmpS := stringify args.i - s := s""tmpS"" - if i < #posLS then s := s"," - i := i+1 - s := s")" - - 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" => "Mistake in formatSub: no SUB" - stringify first rest rest atomE ^= "CONCAT" => "Mistake in formatSub: no CONCAT" - -- 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 := ""funcS"" - i := 1 - while i < #numLS+1 repeat - s := s","numLS.i"" - i := i + 1 - s := s"(" - i := 1 - while i < #posLS+1 repeat --- tmpS := stringify args.i - tmpS := formatMml(first args,minPrec) - args := rest args - s := s""tmpS"" - if i < #posLS then s := s"," - i := i+1 - s := s")" - - 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 --- WriteLine$Lisp "SuperSub1 begin" - atomE : L E := atomize(expr) - op : S := stringify first atomE --- WriteLine$Lisp "op: "op - op ^= "SUPERSUB" => _ - "Mistake in formatSuperSub: no SUPERSUB1" - #args ^= 1 => "Mistake in SuperSub1: #args <> 1" - 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 --- WriteLine$Lisp "funcS: "funcS - bvarS : S := stringify first args --- WriteLine$Lisp "bvarS: "bvarS - -- 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 := ""funcS"" --- WriteLine$Lisp "s: "s - j : I := 0 - while j < i repeat - s := s"" - j := j + 1 - s := s"("formatMml(first args,minPrec)")" - - 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 --- WriteLine$Lisp "SuperSub begin" - atomE : L E := atomize(expr) - op : S := stringify first atomE - op ^= "SUPERSUB" => _ - "Mistake in formatSuperSub: no SUPERSUB" - #args ^= 1 => "Mistake in SuperSub: #args <> 1" - 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 := ""string(ndiffs)""funcS""formatMml(first args,minPrec)""string(ndiffs)"("formatMml(first args,minPrec)")" - - 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 - "" - -- Sum - op = "SIGMA2" => - checkarg := true - "" - -- Sum - op = "PI" => - checkarg := true - "" - -- Product - op = "PI2" => - checkarg := true - "" - -- Product --- op = "INTSIGN" => "" - -- Integral, int - op = "INDEFINTEGRAL" => "" - -- Integral, int - "????" - hold := formatMml(first args,minPrec) - args := rest args - if op ^= "INDEFINTEGRAL" then - if hold ^= "" then - s := concat ["",s,group hold] - else - s := concat ["",s,group " "] - if not null rest args then - hold := formatMml(first args,minPrec) - if hold ^= "" then - s := concat [s,group hold,""] - else - s := concat [s,group " ",""] - 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,"(",formatMml(first args,minPrec),")"] - 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 ["" integrand "" bvarS ""] - - 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 ["" lowlim "" highlim "" integrand "" bvarS ""] - - - formatMatrix(args : L E) : S == - -- format for args is [[ROW ...],[ROW ...],[ROW ...]] - -- generate string for formatting columns (centered) - group addBrackets concat - ["",formatNaryNoGroup("",args,minPrec), - ""] - - formatFunction(op : S, args : L E, prec : I) : S == - group concat ["",op,"",parenthesize formatNary(",",args,minPrec)] - - formatNullary(op : S) == - op = "NOTHING" => "" - group concat ["",op,"()"] - - formatUnary(op : S, arg : E, prec : I) == - p : I := position(op,unaryOps) - p < 1 => error "unknown unary op" - opPrec := unaryPrecs.p - s : S := concat ["",op,"",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 ["(",formatMml(first args, opPrec),")"] - else - s1 : S := formatMml(first args, opPrec) - s2 : S := formatMml(first rest args, opPrec) - op := - op = "|" => s := concat ["",s1,"",op,"",s2,""] - op = "**" => s := concat ["",s1,"",s2,""] - op = "/" => s := concat ["",s1,"",s2,""] - op = "OVER" => s := concat ["",s1,"",s2,""] - op = "+->" => s := concat ["",s1,"",op,"",s2,""] - s := concat ["",s1,"",op,"",s2,""] - 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 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) "+" 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-21-21 - op := - op = "," => "," --originally , \: - op = ";" => ";" --originally ; \: should figure these out - op = "*" => "" - -- InvisibleTimes - op = " " => "" - op = "ROW" => "" - op = "+" => - checkargs := true - "+" - op = "-" => - checkargs := true - "-" - 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 --- WriteLine$Lisp "checking args" - 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 ["(",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) - 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 => ""formatMml(first rest tmpZag,minPrec)""formatMml(first rest rest tmpZag,minPrec)"+"formatZag(rest args)"" - -- EQUAL(tmpZag, "...")$Lisp => "" - (first args = "..."::E)@Boolean => "" - position("ZAG",stringify first args,1) > 0 => - ""formatMml(first rest tmpZag,minPrec)formatMml(first rest rest tmpZag,minPrec)"" - "formatZag: Unexpected kind of ZAG" - - - 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 => ""formatMml(first rest tmpZag,minPrec)""formatMml(first rest rest tmpZag,minPrec)"+"formatZag(rest args)"" - (first args = "...":: E)@Boolean => "" - 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 ["",str,""] - nstr := - empty? str => nstr - concat [nstr," ",str] - concat ["",elt(nstr,segment(2)$US),""] - else str := concat ["",str,""] - str = "%pi" => "π" - -- pi - str = "%e" => "" - -- ExponentialE - str = "%i" => "" - -- ImaginaryI - len > 0 and str.1 = char "%" => concat(concat("",str),"") - len > 1 and digit? str.1 => concat ["",str,""] -- should handle floats - -- presumably this is a literal string - len > 0 and str.1 = char "_"" => - concat(concat("",str),"") - 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("",str),"") - -- if we get to here does that mean it's a variable? - concat ["",str,""] - 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) - -@ -\subsection{Mathematical Markup Language Form} -\pagehead{MathMLForm}{MMLFORM} -\pagepic{ps/v104mathmlform.ps}{MMLFORM}{1.00} - -{\bf Exports:}\\ -\begin{tabular}{lllll} -\cross{MMLFORM}{coerce} & -\cross{MMLFORM}{coerceL} & -\cross{MMLFORM}{coerceS} & -\cross{MMLFORM}{display} & -\cross{MMLFORM}{exprex} \\ -\cross{MMLFORM}{hash} & -\cross{MMLFORM}{latex} & -\cross{MMLFORM}{?=?} & -\cross{MMLFORM}{?\~{}=?} & -\end{tabular} - -<>= -<> -<> -<> -<> -<> -<> - -@ -<>= -"MMLFORM" [color="#FF4488",href="bookvol10.4.pdf#nameddest=MMLFORM"] -"FSAGG" [color="#4488FF",href="bookvol10.2.pdf#nameddest=FSAGG"] -"MMLFORM" -> "FSAGG" - -@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{package MATCAT2 MatrixCategoryFunctions2} \pagehead{MatrixCategoryFunctions2}{MATCAT2} \pagepic{ps/v104MatrixCategoryFunctions2.ps}{MATCAT2}{1.00} @@ -153350,7 +151918,6 @@ ZeroDimensionalSolvePackage(R,ls,ls2): Exports == Implementation where <> <> <> -<> <> <> <> diff --git a/changelog b/changelog index 2651edd..006b292 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,10 @@ +20090628 tpd src/axiom-website/patches.html 20090628.01.tpd.patch +20090628 tpd src/algebra/Makefile add MathML regress, help +20090628 tpd src/algebra/Makefile add TexFormat regress, help +20090628 tpd books/bookvol10.3 fix horizontal fractions +20090628 wxh src/interp/i-output.boot fix horizontal fractions +20090628 tpd books/bookvol10.3 move MathMLFormat domain +20090628 tpd books/bookvol10.4 move MathMLFormat domain 20090627 tpd src/axiom-website/patches.html 20090627.01.tpd.patch 20090627 tpd books/bookvol5 default set message autoload off 20090627 tpd src/Makefile fix typo diff --git a/src/algebra/Makefile.pamphlet b/src/algebra/Makefile.pamphlet index fc73ea2..dfe05db 100644 --- a/src/algebra/Makefile.pamphlet +++ b/src/algebra/Makefile.pamphlet @@ -16476,7 +16476,9 @@ SPADHELP=\ ${HELP}/LinearOrdinaryDifferentialOperator1.help \ ${HELP}/LinearOrdinaryDifferentialOperator2.help ${HELP}/List.help \ ${HELP}/LyndonWord.help ${HELP}/Magma.help \ - ${HELP}/MakeFunction.help ${HELP}/MappingPackage1.help \ + ${HELP}/MakeFunction.help \ + ${HELP}/MathMLFormat.help \ + ${HELP}/MappingPackage1.help \ ${HELP}/MappingPackage2.help ${HELP}/MappingPackage3.help \ ${HELP}/Matrix.help ${HELP}/MatrixCategory.help \ ${HELP}/Multiset.help \ @@ -16516,6 +16518,7 @@ SPADHELP=\ ${HELP}/SquareFreeRegularTriangularSet.help ${HELP}/Stack.help \ ${HELP}/Stream.help ${HELP}/String.help \ ${HELP}/StringTable.help ${HELP}/Symbol.help \ + ${HELP}/TexFormat.help \ ${HELP}/Table.help ${HELP}/TextFile.help \ ${HELP}/TwoDimensionalArray.help ${HELP}/TwoDimensionalViewport.help \ ${HELP}/UnivariateSkewPolynomial.help \ @@ -16571,6 +16574,7 @@ REGRESS=\ LinearOrdinaryDifferentialOperator1.regress \ LinearOrdinaryDifferentialOperator2.regress List.regress \ LyndonWord.regress Magma.regress \ + MathMLFormat.regress \ MakeFunction.regress MappingPackage1.regress \ MappingPackage2.regress MappingPackage3.regress \ Matrix.regress MatrixCategory.regress \ @@ -16594,7 +16598,8 @@ REGRESS=\ SquareFreeRegularTriangularSet.regress Stack.regress \ Stream.regress String.regress \ StringTable.regress Symbol.regress \ - Table.regress TextFile.regress \ + Table.regress TexFormat.regress \ + TextFile.regress \ TwoDimensionalArray.regress UnivariateSkewPolynomial.regress \ UnivariatePolynomial.regress UniversalSegment.regress \ Vector.regress Void.regress \ @@ -17253,6 +17258,15 @@ ${HELP}/MakeFunction.help: ${BOOKS}/bookvol10.4.pamphlet >${INPUT}/MakeFunction.input @echo "MakeFunction (MKFUNC)" >>${HELPFILE} +${HELP}/MathMLFormat.help: ${BOOKS}/bookvol10.3.pamphlet + @echo 7595 create MathMLFormat.help from ${BOOKS}/bookvol10.3.pamphlet + @${TANGLE} -R"MathMLFormat.help" ${BOOKS}/bookvol10.3.pamphlet \ + >${HELP}/MathMLFormat.help + @cp ${HELP}/MathMLFormat.help ${HELP}/MMLFORM.help + @${TANGLE} -R"MathMLFormat.input" ${BOOKS}/bookvol10.3.pamphlet \ + >${INPUT}/MathMLFormat.input + @echo "MathMLFormat (MMLFORM)" >>${HELPFILE} + ${HELP}/MappingPackage1.help: ${BOOKS}/bookvol10.4.pamphlet @echo 7600 create MappingPackage1.help from \ ${BOOKS}/bookvol10.4.pamphlet @@ -17781,6 +17795,15 @@ ${HELP}/Table.help: ${BOOKS}/bookvol10.3.pamphlet >${INPUT}/Table.input @echo "Table (TABLE)" >>${HELPFILE} +${HELP}/TexFormat.help: ${BOOKS}/bookvol10.3.pamphlet + @echo 8145 create TexFormat.help from ${BOOKS}/bookvol10.3.pamphlet + @${TANGLE} -R"TexFormat.help" ${BOOKS}/bookvol10.3.pamphlet \ + >${HELP}/TexFormat.help + @cp ${HELP}/TexFormat.help ${HELP}/TEX.help + @${TANGLE} -R"TexFormat.input" ${BOOKS}/bookvol10.3.pamphlet \ + >${INPUT}/TexFormat.input + @echo "TexFormat (TEX)" >>${HELPFILE} + ${HELP}/TextFile.help: ${BOOKS}/bookvol10.3.pamphlet @echo 8150 create TextFile.help from ${BOOKS}/bookvol10.3.pamphlet @${TANGLE} -R"TextFile.help" ${BOOKS}/bookvol10.3.pamphlet \ diff --git a/src/axiom-website/patches.html b/src/axiom-website/patches.html index 728f8de..dbc6dc8 100644 --- a/src/axiom-website/patches.html +++ b/src/axiom-website/patches.html @@ -1679,5 +1679,7 @@ bookvol10.4 UTSODETL +-> conversion
bookvol10.4 WEIER +-> conversion
20090627.01.tpd.patch bookvol5 default set message autoload off
+20090628.01.tpd.patch +bookvol10.3 TexFormat fix horizontal fractions
diff --git a/src/interp/i-output.boot.pamphlet b/src/interp/i-output.boot.pamphlet index 8a85823..3ca37ff 100644 --- a/src/interp/i-output.boot.pamphlet +++ b/src/interp/i-output.boot.pamphlet @@ -261,8 +261,18 @@ outputTran x == l is [a] => outputTran a [op,:"append"/[(ss is ["+",:ll] => ll; [ss]) for ss in l]] op = "/" => - if $fractionDisplayType = 'horizontal then op := 'SLASH - else op := 'OVER + $fractionDisplayType = 'horizontal => + op := 'SLASH + l is [a, b] => + a:= + ATOM(a) => a + ['PAREN, a] + b:= + ATOM(b) => b + ['PAREN, b] + [outputTran op, a, b] + BREAK() + op := 'OVER l is [["-",a],:b] => outputTran ["-",[op,a,:b]] [outputTran op,:l] op="|" and l is [["Tuple",:u],pred] =>