3 ;; Created by David Drysdale (DMD), December 2002/January 2003
5 ;; closely based on the original TeX conversion code in mactex.lisp,
6 ;; for which the following credits apply:
7 ;; (c) copyright 1987, Richard J. Fateman
8 ;; small corrections and additions: Andrey Grozin, 2001
9 ;; additional additions: Judah Milgram (JM), September 2001
10 ;; additional corrections: Barton Willis (BLW), October 2001
12 ;; Usage: mathml(d8,"/tmp/foo.xml"); mathml(d10,"/tmp/foo.xml"); ..
13 ;; to append lines d8 and d10 to the mathml file. If given only
14 ;; one argument the result goes to standard output.
18 ;; Producing MathML from a macsyma internal expression is done by
19 ;; a reversal of the parsing process. Fundamentally, a
20 ;; traversal of the expression tree is produced by the program,
21 ;; with appropriate substitutions and recognition of the
22 ;; infix / prefix / postfix / matchfix relations on symbols. Various
23 ;; changes are made to this so that MathML will like the results.
26 ;; in macsyma, type mathml(<expression>); or mathml(<label>); or
27 ;; mathml(<expr-or-label>, <file-name>); In the case of a label,
28 ;; an equation-number will also be produced.
29 ;; in case a file-name is supplied, the output will be sent
30 ;; (perhaps appended) to that file.
32 (macsyma-module mathml
)
34 (declare-top (special lop rop ccol $gcprint texport $labels $inchar vaxima-main-dir
))
36 ;; top level command the result of converting the expression x.
38 (defmspec $mathml
(l) ;; mexplabel, and optional filename
39 ;;if filename supplied but 'nil' then return a string
41 (cond ((and (cdr args
) (null (cadr args
)))
42 (let ((*standard-output
* (make-string-output-stream)))
44 (get-output-stream-string *standard-output
*)
47 (t (apply 'mathml1 args
)))))
49 (defun mathml1 (mexplabel &optional filename
) ;; mexplabel, and optional filename
50 (prog (mexp texport $gcprint ccol x y itsalabel tmpport
)
51 ;; $gcprint = nil turns gc messages off
53 (cond ((null mexplabel
)
54 (displa " No eqn given to MathML")
56 ;; collect the file-name, if any, and open a port if needed
57 (setq texport
(cond((null filename
) *standard-output
* ); t= output to terminal
59 (open (string (stripdollar filename
))
62 :if-does-not-exist
:create
))))
63 ;; go back and analyze the first arg more thoroughly now.
64 ;; do a normal evaluation of the expression in macsyma
65 (setq mexp
(meval mexplabel
))
66 (cond ((member mexplabel $labels
:test
#'eq
); leave it if it is a label
67 (setq mexplabel
(intern (format nil
"(~a)" (stripdollar mexplabel
))))
69 (t (setq mexplabel nil
)));flush it otherwise
71 ;; maybe it is a function?
72 (cond((symbolp (setq x mexp
)) ;;exclude strings, numbers
74 (cond ((setq y
(mget x
'mexpr
))
75 (setq mexp
(list '(mdefine) (cons (list x
) (cdadr y
)) (caddr y
))))
76 ((setq y
(mget x
'mmacro
))
77 (setq mexp
(list '(mdefmacro) (cons (list x
) (cdadr y
)) (caddr y
))))
78 ((setq y
(mget x
'aexpr
))
79 (setq mexp
(list '(mdefine) (cons (list x
'array
) (cdadr y
)) (caddr y
)))))))
80 (cond ((and (null (atom mexp
))
81 (member (caar mexp
) '(mdefine mdefmacro
) :test
#'eq
))
82 (format texport
"<pre>~%" )
83 (cond (mexplabel (format texport
"~a " mexplabel
)))
84 ;; need to get rid of "<" signs
85 (setq tmpport
(make-string-output-stream))
89 (string-substitute "<" #\
< (get-output-stream-string tmpport
)))
90 (format texport
";~%</pre>"))
92 ((and itsalabel
;; but is it a user-command-label?
93 (char= (char (string $inchar
) 1) (char (string mexplabel
) 1)))
94 ;; aha, this is a C-line: do the grinding:
95 (format texport
"<pre>~%~a " mexplabel
)
96 ;; need to get rid of "<" signs
97 (setq tmpport
(make-string-output-stream))
101 (string-substitute "<" #\
< (get-output-stream-string tmpport
)))
102 (format texport
";~%</pre>"))
104 (t ; display the expression for MathML now:
105 (myprinc "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"> " texport
)
106 (mapc #'(lambda (x) (myprinc x texport
))
107 ;;initially the left and right contexts are
108 ;; empty lists, and there are implicit parens
109 ;; around the whole expression
110 (mathml mexp nil nil
'mparen
'mparen
))
112 (format texport
"<mspace width=\"verythickmathspace\"/> <mtext>~a</mtext> " mexplabel
)))
113 (format texport
"</math>")))
114 (cond(filename(terpri texport
); and drain port if not terminal
118 (defun mathml (x l r lop rop
)
119 ;; x is the expression of interest; l is the list of strings to its
120 ;; left, r to its right. lop and rop are the operators on the left
121 ;; and right of x in the tree, and will determine if parens must
124 (cond ((atom x
) (mathml-atom x l r
))
125 ((or (<= (mathml-lbp (caar x
)) (mathml-rbp lop
))
126 (> (mathml-lbp rop
) (mathml-rbp (caar x
))))
127 (mathml-paren x l r
))
128 ;; special check needed because macsyma notates arrays peculiarly
129 ((member 'array
(cdar x
) :test
#'eq
) (mathml-array x l r
))
130 ;; dispatch for object-oriented mathml-ifiying
131 ((get (caar x
) 'mathml
) (funcall (get (caar x
) 'mathml
) x l r
))
132 (t (mathml-function x l r nil
))))
134 (defun string-substitute (newstring oldchar x
&aux matchpos
)
135 (setq matchpos
(position oldchar x
))
136 (if (null matchpos
) x
138 (subseq x
0 matchpos
)
140 (string-substitute newstring oldchar
(subseq x
(1+ matchpos
))))))
142 ;;; NOTE that we try to include spaces after closing tags (e.g. "</mwhatever> ")
143 ;;; so that the line breaking algorithm in myprinc has some spaces where it
144 ;;; can choose to line break.
146 ;;; First we have the functions which are called directly by mathml and its
149 (defun mathml-atom (x l r
)
151 (list (cond ((numberp x
) (mathmlnumformat x
))
152 ((stringp x
) (format nil
"<mtext>~a</mtext>" x
))
153 ((and (symbolp x
) (get x
'mathmlword
)))
154 (t (mathml-stripdollar x
))))
157 (defun mathmlnumformat(atom)
158 (let (r firstpart exponent
)
159 (cond ((integerp atom
)
160 (strcat "<mn>" (format nil
"~d" atom
) "</mn> "))
162 (setq r
(explode atom
))
163 (setq exponent
(member 'e r
:test
#'string-equal
));; is it ddd.ddde+EE
164 (cond ((null exponent
)
165 (strcat "<mn>" (format nil
"~a" (implode (exploden atom
))) "</mn> "))
168 (nreverse (cdr (member 'e
(reverse r
) :test
#'string-equal
))))
171 (apply #'strcat firstpart
)
172 "</mn><mo>×</mo> <msup><mn>10</mn><mn>"
173 (apply #'strcat
(cdr exponent
))
174 "</mn></msup> </mrow> ")
177 (defun mathml-stripdollar(sym)
179 (return-from mathml-stripdollar sym
))
180 (let* ((pname (maybe-invert-string-case (string-left-trim '(#\$
) (symbol-name sym
))))
183 (loop for i downfrom
(1- l
)
184 when
(not (digit-char-p (aref pname i
)))
185 do
(return (1+ i
)))))
186 (cond ((< begin-sub l
) ;; need to do subscripting
188 (subseq pname
0 begin-sub
)
190 (subseq pname begin-sub l
)
192 (t ;; no subscripting needed
193 (strcat "<mi>" pname
"</mi> ")))))
195 (defun mathml-paren (x l r
)
196 (mathml x
(append l
'("<mfenced separators=\"\">")) (cons "</mfenced> " r
) 'mparen
'mparen
))
198 (defun mathml-array (x l r
)
200 (if (eq 'mqapply
(caar x
))
203 l
(mathml f
(append l
(list "<mfenced separators=\",\">"))
204 (list "</mfenced> ") 'mparen
'mparen
))
206 l
(mathml (mathmlword f
) (append l
'("<msub><mrow>")) nil lop
'mfunction
)))
208 r
(nconc (mathml-list (cdr x
) nil
(list "</mrow></msub> ") "<mo>,</mo>") r
))
209 (nconc l
(list "</mrow><mrow>") r
)))
211 ;; set up a list , separated by symbols (, * ...) and then tack on the
212 ;; ending item (e.g. "]" or perhaps ")"
213 (defun mathml-list (x l r sym
)
217 (setq nl
(nconc nl
(mathml (car x
) l r
'mparen
'mparen
)))
219 (setq nl
(nconc nl
(mathml (car x
) l
(list sym
) 'mparen
'mparen
))
223 ;; we could patch this so sin x rather than sin(x), but instead we made sin a prefix
225 (defun mathml-function (x l r op
) op
226 (setq l
(mathml (mathmlword (caar x
)) l nil
'mparen
'mparen
)
227 r
(mathml (cons '(mprogn) (cdr x
)) nil r
'mparen
'mparen
))
230 ;;; Now we have functions which are called via property lists
232 (defun mathml-prefix (x l r
)
233 (mathml (cadr x
) (append l
(mathmlsym (caar x
))) r
(caar x
) rop
))
235 (defun mathml-infix (x l r
)
237 (if (or (null (cddr x
)) (cdddr x
)) (wna-err (caar x
)))
238 (setq l
(mathml (cadr x
) l nil lop
(caar x
)))
239 (mathml (caddr x
) (append l
(mathmlsym (caar x
))) r
(caar x
) rop
))
241 (defun mathml-postfix (x l r
)
242 (mathml (cadr x
) l
(append (mathmlsym (caar x
)) r
) lop
(caar x
)))
244 (defun mathml-nary (x l r
)
245 (let* ((op (caar x
)) (sym (mathmlsym op
)) (y (cdr x
)) (ext-lop lop
) (ext-rop rop
))
246 (cond ((null y
) (mathml-function x l r t
)) ; this should not happen
247 ((null (cdr y
)) (mathml-function x l r t
)) ; this should not happen, too
248 (t (do ((nl) (lop ext-lop op
) (rop op
(if (null (cdr y
)) ext-rop op
)))
249 ((null (cdr y
)) (setq nl
(nconc nl
(mathml (car y
) l r lop rop
))) nl
)
250 (setq nl
(nconc nl
(mathml (car y
) l
(list sym
) lop rop
))
254 (defun mathml-nofix (x l r
) (mathml (caar x
) l r
(caar x
) rop
))
256 (defun mathml-matchfix (x l r
)
257 (setq l
(append l
(car (mathmlsym (caar x
))))
258 ;; car of mathmlsym of a matchfix operator is the lead op
259 r
(append (cdr (mathmlsym (caar x
))) r
)
260 ;; cdr is the trailing op
261 x
(mathml-list (cdr x
) nil r
"<mo>,</mo>"))
264 (defun mathmlsym (x) (or (get x
'mathmlsym
) (get x
'strsym
)(get x
'dissym
)
267 (defun mathmlword (x)(or (get x
'mathmlword
) (stripdollar x
)))
269 (defprop bigfloat mathml-bigfloat mathml
)
271 (defun mathml-bigfloat (x l r
)
272 (let ((formatted (fpformat x
)))
273 (if (or (find '|b| formatted
) (find '|B| formatted
))
277 '("<mrow><msub><mn>")
280 #'(lambda (e) (if (or (eq e
'|b|
) (eq e
'|B|
))
281 '("</mn><mi>B</mi></msub>"
283 "<msup><mn>10</mn><mn>")
286 '("</mn></msup></mrow>"))))
287 (append l spell-out-expt r
))
288 (append l formatted r
))))
290 (defprop mprog
"<mi>block</mi><mspace width=\"mediummathspace\"/> " mathmlword
)
291 (defprop %erf
"<mi>erf</mi> " mathmlword
)
292 (defprop $erf
"<mi>erf</mi> " mathmlword
) ;; etc for multicharacter names
293 (defprop $true
"<mi>true</mi> " mathmlword
)
294 (defprop $false
"<mi>false</mi> " mathmlword
)
296 (defprop mprogn mathml-matchfix mathml
) ;; mprogn is (<progstmnt>, ...)
297 (defprop mprogn
(("<mfenced separators=\"\">") "</mfenced> ") mathmlsym
)
299 (defprop mlist mathml-matchfix mathml
)
300 (defprop mlist
(("<mfenced separators=\"\" open=\"[\" close=\"]\">")"</mfenced> ") mathmlsym
)
303 (defprop mabs mathml-matchfix mathml
)
304 (defprop mabs
(("<mfenced separators=\"\" open=\"|\" close=\"|\">")"</mfenced> ") mathmlsym
)
306 (defprop mqapply mathml-mqapply mathml
)
308 (defun mathml-mqapply (x l r
)
309 (setq l
(mathml (cadr x
) l
(list "(" ) lop
'mfunction
)
310 r
(mathml-list (cddr x
) nil
(cons ")" r
) "<mo>,</mo>"))
311 (append l r
));; fixed 9/24/87 RJF
313 (defprop $%i
"<mi>ⅈ</mi> " mathmlword
)
314 (defprop $%pi
"<mi>π</mi> " mathmlword
)
315 (defprop $%e
"<mi>ⅇ</mi> " mathmlword
)
316 (defprop $inf
"<mi>∞</mi> " mathmlword
)
317 (defprop $minf
"<mi>-∞</mi> " mathmlword
)
318 (defprop %laplace
"<mo>ℒ</mo>" mathmlword
)
319 (defprop $alpha
"<mi>α</mi> " mathmlword
)
320 (defprop $beta
"<mi>β</mi> " mathmlword
)
321 (defprop $gamma
"<mi>γ</mi> " mathmlword
)
322 (defprop %gamma
"<mi>Γ</mi> " mathmlword
)
323 (defprop $delta
"<mi>δ</mi> " mathmlword
)
324 (defprop $epsilon
"<mi>ε</mi> " mathmlword
)
325 (defprop $zeta
"<mi>ζ</mi> " mathmlword
)
326 (defprop $eta
"<mi>η</mi> " mathmlword
)
327 (defprop $theta
"<mi>θ</mi> " mathmlword
)
328 (defprop $iota
"<mi>ι</mi> " mathmlword
)
329 (defprop $kappa
"<mi>κ</mi> " mathmlword
)
330 (defprop lambda
"<mi>λ</mi> " mathmlword
)
331 (defprop $mu
"<mi>μ</mi> " mathmlword
)
332 (defprop $nu
"<mi>ν</mi> " mathmlword
)
333 (defprop $xi
"<mi>ξ</mi> " mathmlword
)
334 (defprop $pi
"<mi>π</mi> " mathmlword
)
335 (defprop $rho
"<mi>ρ</mi> " mathmlword
)
336 (defprop $sigma
"<mi>σ</mi> " mathmlword
)
337 (defprop $tau
"<mi>τ</mi> " mathmlword
)
338 (defprop $upsilon
"<mi>υ</mi> " mathmlword
)
339 (defprop $phi
"<mi>φ</mi> " mathmlword
)
340 (defprop $chi
"<mi>χ</mi> " mathmlword
)
341 (defprop $psi
"<mi>ψ</mi> " mathmlword
)
342 (defprop $omega
"<mi>ω</mi> " mathmlword
)
344 (defprop mquote mathml-prefix mathml
)
345 (defprop mquote
("<mo>'</mo>") mathmlsym
)
346 (defprop mquote
201. mathml-rbp
)
348 (defprop msetq mathml-infix mathml
)
349 (defprop msetq
("<mo>:</mo>") mathmlsym
)
350 (defprop msetq
180. mathml-rbp
)
351 (defprop msetq
20. mathml-rbp
)
353 (defprop mset mathml-infix mathml
)
354 (defprop mset
("<mo>::</mo>") mathmlsym
)
355 (defprop mset
180. mathml-lbp
)
356 (defprop mset
20. mathml-rbp
)
358 (defprop mdefine mathml-infix mathml
)
359 (defprop mdefine
("<mo>:=</mo>") mathmlsym
)
360 (defprop mdefine
180. mathml-lbp
)
361 (defprop mdefine
20. mathml-rbp
)
363 (defprop mdefmacro mathml-infix mathml
)
364 (defprop mdefmacro
("<mo>::=</mo>") mathmlsym
)
365 (defprop mdefmacro
180. mathml-lbp
)
366 (defprop mdefmacro
20. mathml-rbp
)
368 (defprop marrow mathml-infix mathml
)
369 (defprop marrow
("<mo>→</mo>") mathmlsym
)
370 (defprop marrow
25 mathml-lbp
)
371 (defprop marrow
25 mathml-rbp
)
373 (defprop mfactorial mathml-postfix mathml
)
374 (defprop mfactorial
("<mo>!</mo>") mathmlsym
)
375 (defprop mfactorial
160. mathml-lbp
)
377 (defprop mexpt mathml-mexpt mathml
)
378 (defprop mexpt
140. mathml-lbp
)
379 (defprop mexpt
139. mathml-rbp
)
381 (defprop %sum
110. mathml-rbp
) ;; added by BLW, 1 Oct 2001
382 (defprop %product
115. mathml-rbp
) ;; added by BLW, 1 Oct 2001
384 ;; insert left-angle-brackets for mncexpt. a^<n> is how a^^n looks.
385 (defun mathml-mexpt (x l r
)
386 (let((nc (eq (caar x
) 'mncexpt
))); true if a^^b rather than a^b
387 ;; here is where we have to check for f(x)^b to be displayed
388 ;; as f^b(x), as is the case for sin(x)^2 .
389 ;; which should be sin^2 x rather than (sin x)^2 or (sin(x))^2.
390 ;; yet we must not display (a+b)^2 as +^2(a,b)...
391 ;; or (sin(x))^(-1) as sin^(-1)x, which would be arcsine x
392 (cond ;; this whole clause
393 ;; should be deleted if this hack is unwanted and/or the
394 ;; time it takes is of concern.
395 ;; it shouldn't be too expensive.
396 ((and (eq (caar x
) 'mexpt
) ; don't do this hack for mncexpt
398 ((fx (cadr x
)); this is f(x)
399 (f (and (not (atom fx
)) (atom (caar fx
)) (caar fx
))) ; this is f [or nil]
400 (bascdr (and f
(cdr fx
))) ; this is (x) [maybe (x,y..), or nil]
401 (expon (caddr x
)) ;; this is the exponent
403 f
; there is such a function
404 (member (get-first-char f
) '(#\%
#\$
) :test
#'char
=) ;; insist it is a % or $ function
405 (not (member f
'(%sum %product %derivative %integrate %at
406 %lsum %limit
) :test
#'eq
)) ;; what else? what a hack...
407 (or (and (atom expon
) (not (numberp expon
))) ; f(x)^y is ok
408 (and (atom expon
) (numberp expon
) (> expon
0))))))
409 ; f(x)^3 is ok, but not f(x)^-1, which could
410 ; inverse of f, if written f^-1 x
411 ; what else? f(x)^(1/2) is sqrt(f(x)), ??
413 (setq l
(mathml `((mexpt) ,f
,expon
) l nil
'mparen
'mparen
))
414 (if (and (null (cdr bascdr
))
415 (eq (get f
'mathml
) 'mathml-prefix
))
416 (setq r
(mathml (car bascdr
) nil r f
'mparen
))
417 (setq r
(mathml (cons '(mprogn) bascdr
) nil r
'mparen
'mparen
))))
418 (t nil
))))) ; won't doit. fall through
419 (t (setq l
(mathml (cadr x
) (append l
'("<msup><mrow>")) nil lop
(caar x
))
420 r
(if (mmminusp (setq x
(nformat (caddr x
))))
421 ;; the change in base-line makes parens unnecessary
423 (mathml (cadr x
) '("</mrow> <mfenced separators=\"\" open=\"<\" close=\">\"> -")(cons "</mfenced></msup> " r
) 'mparen
'mparen
)
424 (mathml (cadr x
) '("</mrow> <mfenced separators=\"\"> -")(cons "</mfenced></msup> " r
) 'mparen
'mparen
))
426 (mathml x
(list "</mrow> <mfenced separators=\"\" open=\"<\" close=\">\">")(cons "</mfenced></msup>" r
) 'mparen
'mparen
)
427 (if (and (numberp x
) (< x
10))
428 (mathml x
(list "</mrow> ")(cons "</msup> " r
) 'mparen
'mparen
)
429 (mathml x
(list "</mrow> <mrow>")(cons "</mrow></msup> " r
) 'mparen
'mparen
))
433 (defprop mncexpt mathml-mexpt mathml
)
435 (defprop mncexpt
135. mathml-lbp
)
436 (defprop mncexpt
134. mathml-rbp
)
438 (defprop mnctimes mathml-nary mathml
)
439 (defprop mnctimes
"<mi>⋯</mi> " mathmlsym
)
440 (defprop mnctimes
110. mathml-lbp
)
441 (defprop mnctimes
109. mathml-rbp
)
443 (defprop mtimes mathml-nary mathml
)
444 (defprop mtimes
"<mspace width=\"thinmathspace\"/>" mathmlsym
)
445 (defprop mtimes
120. mathml-lbp
)
446 (defprop mtimes
120. mathml-rbp
)
448 (defprop %sqrt mathml-sqrt mathml
)
450 (defun mathml-sqrt(x l r
)
451 ;; format as \\sqrt { } assuming implicit parens for sqr grouping
452 (mathml (cadr x
) (append l
'("<msqrt>")) (append '("</msqrt>") r
) 'mparen
'mparen
))
454 ;; macsyma doesn't know about cube (or nth) roots,
455 ;; but if it did, this is what it would look like.
456 (defprop $cubrt mathml-cubrt mathml
)
458 (defun mathml-cubrt (x l r
)
459 (mathml (cadr x
) (append l
'("<mroot><mrow>")) (append '("</mrow>3</mroot>") r
) 'mparen
'mparen
))
461 (defprop mquotient mathml-mquotient mathml
)
462 (defprop mquotient
("<mo>/</mo>") mathmlsym
)
463 (defprop mquotient
122. mathml-lbp
) ;;dunno about this
464 (defprop mquotient
123. mathml-rbp
)
466 (defun mathml-mquotient (x l r
)
467 (if (or (null (cddr x
)) (cdddr x
)) (wna-err (caar x
)))
468 (setq l
(mathml (cadr x
) (append l
'("<mfrac><mrow>")) nil
'mparen
'mparen
)
469 r
(mathml (caddr x
) (list "</mrow> <mrow>") (append '("</mrow></mfrac> ")r
) 'mparen
'mparen
))
472 (defprop $matrix mathml-matrix mathml
)
474 (defun mathml-matrix(x l r
) ;;matrix looks like ((mmatrix)((mlist) a b) ...)
475 (append l
`("<mfenced separators=\"\" open=\"(\" close=\")\"><mtable>")
477 (mathml-list (cdr y
) (list "<mtr><mtd>") (list "</mtd></mtr> ") "</mtd><mtd>"))
479 '("</mtable></mfenced> ") r
))
481 ;; macsyma sum or prod is over integer range, not low <= index <= high
482 ;; Mathml is lots more flexible .. but
484 (defprop %sum mathml-sum mathml
)
485 (defprop %lsum mathml-lsum mathml
)
486 (defprop %product mathml-sum mathml
)
488 ;; easily extended to union, intersect, otherops
490 (defun mathml-lsum(x l r
)
491 (let ((op (cond ((eq (caar x
) '%lsum
) "<mrow><munder><mo>∑</mo> <mrow>")
494 ;; gotta be one of those above
495 (s1 (mathml (cadr x
) nil nil
'mparen rop
));; summand
496 (index ;; "index = lowerlimit"
497 (mathml `((min simp
) , (caddr x
), (cadddr x
)) nil nil
'mparen
'mparen
)))
498 (append l
`( ,op
,@index
"</mrow></munder> <mrow>" ,@s1
"</mrow></mrow> ") r
)))
500 (defun mathml-sum(x l r
)
501 (let ((op (cond ((eq (caar x
) '%sum
) "<mrow><munderover><mo>∑</mo><mrow>")
502 ((eq (caar x
) '%product
) "<mrow><munderover><mo>∏</mo><mrow>")
505 ;; gotta be one of those above
506 (s1 (mathml (cadr x
) nil nil
'mparen rop
));; summand
507 (index ;; "index = lowerlimit"
508 (mathml `((mequal simp
) ,(caddr x
),(cadddr x
)) nil nil
'mparen
'mparen
))
509 (toplim (mathml (car(cddddr x
)) nil nil
'mparen
'mparen
)))
510 (append l
`( ,op
,@index
"</mrow> <mrow>" ,@toplim
"</mrow></munderover> <mrow>" ,@s1
"</mrow></mrow> ") r
)))
512 (defprop %integrate mathml-int mathml
)
514 (defun mathml-int (x l r
)
515 (let ((s1 (mathml (cadr x
) nil nil
'mparen
'mparen
));;integrand delims / & d
516 (var (mathml (caddr x
) nil nil
'mparen rop
))) ;; variable
517 (cond((= (length x
) 3)
518 (append l
`("<mrow><mo>∫</mo><mrow>" ,@s1
"</mrow> <mspace width=\"mediummathspace\"/> <mrow><mo>ⅆ</mo><mi>" ,@var
"</mi></mrow></mrow> ") r
))
519 (t ;; presumably length 5
520 (let ((low (mathml (nth 3 x
) nil nil
'mparen
'mparen
))
522 (hi (mathml (nth 4 x
) nil nil
'mparen
'mparen
)))
523 (append l
`("<mrow><munderover><mo>∫</mo> <mrow>" ,@low
"</mrow> <mrow>" ,@hi
"</mrow> </munderover> <mrow>" ,@s1
"</mrow> <mspace width=\"mediummathspace\"/> <mrow><mo>ⅆ</mo><mi>" ,@var
"</mi> </mrow></mrow> ") r
))))))
525 (defprop %limit mathml-limit mathml
)
527 (defprop mrarr mathml-infix mathml
)
528 (defprop mrarr
("<mo>→</mo> ") mathmlsym
)
529 (defprop mrarr
80. mathml-lbp
)
530 (defprop mrarr
80. mathml-rbp
)
532 (defun mathml-limit(x l r
) ;; ignoring direction, last optional arg to limit
533 (let ((s1 (mathml (second x
) nil nil
'mparen rop
));; limitfunction
534 (subfun ;; the thing underneath "limit"
535 (mathml `((mrarr simp
) ,(third x
) ,(fourth x
)) nil nil
'mparen
'mparen
)))
536 (append l
`("<munder><mo>lim</mo><mrow>" ,@subfun
"</mrow> </munder> <mrow>" ,@s1
"</mrow>") r
)))
538 (defprop %at mathml-at mathml
)
540 ;; e.g. at(diff(f(x)),x=a)
541 (defun mathml-at (x l r
)
542 (let ((s1 (mathml (cadr x
) nil nil lop rop
))
543 (sub (mathml (caddr x
) nil nil
'mparen
'mparen
)))
544 (append l
'("<msub><mfenced separators=\"\" open=\"\" close=\"|\">") s1
'("</mfenced> <mrow>") sub
'("</mrow> </msub> ") r
)))
546 ;;binomial coefficients
548 (defprop %binomial mathml-choose mathml
)
550 (defun mathml-choose (x l r
)
552 "<mfenced separators=\"\" open=\"(\" close=\")\"><mtable><mtr><mtd>"
553 ,@(mathml (cadr x
) nil nil
'mparen
'mparen
)
554 "</mtd></mtr> <mtr><mtd>"
555 ,@(mathml (caddr x
) nil nil
'mparen
'mparen
)
556 "</mtd></mtr> </mtable></mfenced> "
560 (defprop rat mathml-rat mathml
)
561 (defprop rat
120. mathml-lbp
)
562 (defprop rat
121. mathml-rbp
)
563 (defun mathml-rat(x l r
) (mathml-mquotient x l r
))
565 (defprop mplus mathml-mplus mathml
)
566 (defprop mplus
100. mathml-lbp
)
567 (defprop mplus
100. mathml-rbp
)
569 (defun mathml-mplus (x l r
)
570 ;(declare (fixnum w))
571 (cond ((member 'trunc
(car x
) :test
#'eq
)
572 (setq r
(cons "<mo>+</mo><mtext>⋯</mtext> " r
))))
573 (cond ((null (cddr x
))
575 (mathml-function x l r t
)
576 (mathml (cadr x
) (cons "<mo>+</mo>" l
) r
'mplus rop
)))
577 (t (setq l
(mathml (cadr x
) l nil lop
'mplus
)
579 (do ((nl l
) (dissym))
581 (if (mmminusp (car x
)) (setq l
(cadar x
) dissym
(list "<mo>-</mo> "))
582 (setq l
(car x
) dissym
(list "<mo>+</mo> ")))
583 (setq r
(mathml l dissym r
'mplus rop
))
585 (if (mmminusp (car x
)) (setq l
(cadar x
) dissym
(list "<mo>-</mo> "))
586 (setq l
(car x
) dissym
(list "<mo>+</mo> ")))
587 (setq nl
(append nl
(mathml l dissym nil
'mplus
'mplus
))
590 (defprop mminus mathml-prefix mathml
)
591 (defprop mminus
("<mo>-</mo>") mathmlsym
)
592 (defprop mminus
100. mathml-rbp
)
593 (defprop mminus
100. mathml-lbp
)
595 (defprop min mathml-infix mathml
)
596 (defprop min
("<mo>∈</mo> ") mathmlsym
)
597 (defprop min
80. mathml-lbp
)
598 (defprop min
80. mathml-rbp
)
600 (defprop mequal mathml-infix mathml
)
601 (defprop mequal
("<mo>=</mo> ") mathmlsym
)
602 (defprop mequal
80. mathml-lbp
)
603 (defprop mequal
80. mathml-rbp
)
605 (defprop mnotequal mathml-infix mathml
)
606 (defprop mnotequal
80. mathml-lbp
)
607 (defprop mnotequal
80. mathml-rbp
)
609 (defprop mgreaterp mathml-infix mathml
)
610 (defprop mgreaterp
("<mo>></mo> ") mathmlsym
)
611 (defprop mgreaterp
80. mathml-lbp
)
612 (defprop mgreaterp
80. mathml-rbp
)
614 (defprop mgeqp mathml-infix mathml
)
615 (defprop mgeqp
("<mo>≥</mo> ") mathmlsym
)
616 (defprop mgeqp
80. mathml-lbp
)
617 (defprop mgeqp
80. mathml-rbp
)
619 (defprop mlessp mathml-infix mathml
)
620 (defprop mlessp
("<mo><</mo> ") mathmlsym
)
621 (defprop mlessp
80. mathml-lbp
)
622 (defprop mlessp
80. mathml-rbp
)
624 (defprop mleqp mathml-infix mathml
)
625 (defprop mleqp
("<mo>≤</mo> ") mathmlsym
)
626 (defprop mleqp
80. mathml-lbp
)
627 (defprop mleqp
80. mathml-rbp
)
629 (defprop mnot mathml-prefix mathml
)
630 (defprop mnot
("<mo>¬</mo> ") mathmlsym
)
631 (defprop mnot
70. mathml-rbp
)
633 (defprop mand mathml-nary mathml
)
634 (defprop mand
("<mo>∧</mo> ") mathmlsym
)
635 (defprop mand
60. mathml-lbp
)
636 (defprop mand
60. mathml-rbp
)
638 (defprop mor mathml-nary mathml
)
639 (defprop mor
("<mo>∨</mo> ") mathmlsym
)
641 ;; make sin(x) display as sin x , but sin(x+y) as sin(x+y)
644 (defun mathml-setup (x)
647 (setf (get a
'mathml
) 'mathml-prefix
)
648 (setf (get a
'mathmlword
) b
) ;This means "sin" will always be roman
649 (setf (get a
'mathmlsym
) (list b
))
650 (setf (get a
'mathml-rbp
) 130)))
654 (%acos
"<mi>arccos</mi> ")
655 (%asin
"<mi>arcsin</mi> ")
656 (%atan
"<mi>arctan</mi> ")
657 (%arg
"<mi>arg</mi> ")
658 (%cos
"<mi>cos</mi> ")
659 (%cosh
"<mi>cosh</mi> ")
660 (%cot
"<mi>cot</mi> ")
661 (%coth
"<mi>coth</mi> ")
662 (%csc
"<mi>cosec</mi> ")
663 (%deg
"<mi>deg</mi> ")
664 (%determinant
"<mi>det</mi> ")
665 (%dim
"<mi>dim</mi> ")
666 (%exp
"<mi>exp</mi> ")
667 (%gcd
"<mi>gcd</mi> ")
668 (%hom
"<mi>hom</mi> ")
669 (%inf
"<mi>∞</mi> ")
670 (%ker
"<mi>ker</mi> ")
672 ;;(%limit "<mi>lim</mi> ")
673 (%liminf
"<mi>lim inf</mi> ")
674 (%limsup
"<mi>lim sup</mi> ")
676 (%log
"<mi>log</mi> ")
677 (%max
"<mi>max</mi> ")
678 (%min
"<mi>min</mi> ")
680 (%sec
"<mi>sec</mi> ")
681 (%sech
"<mi>sech</mi> ")
682 (%sin
"<mi>sin</mi> ")
683 (%sinh
"<mi>sinh</mi> ")
684 (%sup
"<mi>sup</mi> ")
685 (%tan
"<mi>tan</mi> ")
686 (%tanh
"<mi>tanh</mi> ")
687 ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual
688 ;(%laplace "{\\cal L}")
691 (defprop mor mathml-nary mathml
)
692 (defprop mor
50. mathml-lbp
)
693 (defprop mor
50. mathml-rbp
)
695 (defprop mcond mathml-mcond mathml
)
696 (defprop mcond
25. mathml-lbp
)
697 (defprop mcond
25. mathml-rbp
)
699 (defprop %derivative mathml-derivative mathml
)
701 (defun mathml-derivative (x l r
)
702 (mathml (mathml-d x
"ⅆ") l r lop rop
))
704 (defun mathml-d(x dsym
) ;dsym should be "ⅆ" or "∂"
705 ;; format the macsyma derivative form so it looks
706 ;; sort of like a quotient times the deriva-dand.
708 ((arg (cadr x
)) ;; the function being differentiated
709 (difflist (cddr x
)) ;; list of derivs e.g. (x 1 y 2)
710 (ords (odds difflist
0)) ;; e.g. (1 2)
711 (vars (odds difflist
1)) ;; e.g. (x y)
712 (numer `((mexpt) ,dsym
((mplus) ,@ords
))) ; d^n numerator
713 (denom (cons '(mtimes)
714 (mapcan #'(lambda(b e
)
715 `(,dsym
,(simplifya `((mexpt) ,b
,e
) nil
)))
718 ((mquotient) ,(simplifya numer nil
) ,denom
)
721 (defun mathml-mcond (x l r
)
723 (mathml (cadr x
) '("<mi>if</mi> <mspace width=\"mediummathspace\"/>")
724 '("<mspace width=\"mediummathspace\"/> <mi>then</mi><mspace width=\"mediummathspace\"/> ") 'mparen
'mparen
)
725 (if (eql (fifth x
) '$false
)
726 (mathml (caddr x
) nil r
'mcond rop
)
727 (append (mathml (caddr x
) nil nil
'mparen
'mparen
)
728 (mathml (fifth x
) '("<mspace width=\"mediummathspace\"/> <mi>else</mi><mspace width=\"mediummathspace\"/> ") r
'mcond rop
)))))
730 (defprop mdo mathml-mdo mathml
)
731 (defprop mdo
30. mathml-lbp
)
732 (defprop mdo
30. mathml-rbp
)
733 (defprop mdoin mathml-mdoin mathml
)
734 (defprop mdoin
30. mathml-rbp
)
736 (defun mathml-lbp(x)(cond((get x
'mathml-lbp
))(t(lbp x
))))
737 (defun mathml-rbp(x)(cond((get x
'mathml-rbp
))(t(lbp x
))))
739 ;; these aren't quite right
741 (defun mathml-mdo (x l r
)
742 (mathml-list (mathmlmdo x
) l r
"<mspace width=\"mediummathspace\"/> "))
744 (defun mathml-mdoin (x l r
)
745 (mathml-list (mathmlmdoin x
) l r
"<mspace width=\"mediummathspace\"/> "))
748 (nconc (cond ((second x
) `("<mi>for</mi> " ,(second x
))))
749 (cond ((equal 1 (third x
)) nil
)
750 ((third x
) `("<mi>from</mi> " ,(third x
))))
751 (cond ((equal 1 (fourth x
)) nil
)
752 ((fourth x
) `("<mi>step</mi> " ,(fourth x
)))
753 ((fifth x
) `("<mi>next</mi> " ,(fifth x
))))
754 (cond ((sixth x
) `("<mi>thru</mi> " ,(sixth x
))))
755 (cond ((null (seventh x
)) nil
)
756 ((eq 'mnot
(caar (seventh x
)))
757 `("<mi>while</mi> " ,(cadr (seventh x
))))
758 (t `("<mi>unless</mi> " ,(seventh x
))))
759 `("<mi>do</mi> " ,(eighth x
))))
761 (defun mathmlmdoin (x)
762 (nconc `("<mi>for</mi>" ,(second x
) "<mi>in</mi> " ,(third x
))
763 (cond ((sixth x
) `("<mi>thru</mi> " ,(sixth x
))))
764 (cond ((null (seventh x
)) nil
)
765 ((eq 'mnot
(caar (seventh x
)))
766 `("<mi>while</mi> " ,(cadr (seventh x
))))
767 (t `("<mi>unless</mi> " ,(seventh x
))))
768 `("<mi>do</mi> " ,(eighth x
))))
770 ;; Undone and trickier:
771 ;; Maybe do some special hacking for standard notations for
772 ;; hypergeometric fns, alternative summation notations 0<=n<=inf, etc.