~ubuntu-branches/debian/squeeze/maxima/squeeze

« back to all changes in this revision

Viewing changes to share/contrib/lurkmathml/mathml.lisp

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2006-10-18 14:52:42 UTC
  • mto: (1.1.5 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20061018145242-vzyrm5hmxr8kiosf
ImportĀ upstreamĀ versionĀ 5.10.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(in-package :maxima)
 
2
;; MathML-printing
 
3
;; Created by David Drysdale (DMD), December 2002/January 2003
 
4
;;
 
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
 
11
 
 
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.
 
15
 
 
16
;; Method:
 
17
 
 
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.
 
24
 
 
25
;;  Instructions:
 
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.
 
31
 
 
32
(macsyma-module mathml)
 
33
 
 
34
(declare-top
 
35
         (special lop rop ccol $gcprint texport $labels $inchar
 
36
                  vaxima-main-dir
 
37
                  )
 
38
         (*expr mathml-lbp mathml-rbp))
 
39
 
 
40
;; top level command the result of converting the expression x.
 
41
 
 
42
(defmspec $mathml(l) ;; mexplabel, and optional filename
 
43
  ;;if filename supplied but 'nil' then return a string
 
44
  (let ((args (cdr l)))
 
45
    (cond ((and (cdr args) (null (cadr args)))
 
46
           (let ((*standard-output* (make-string-output-stream)))
 
47
             (apply 'mathml1  args)
 
48
             (get-output-stream-string *standard-output*)
 
49
             )
 
50
           )
 
51
          (t (apply 'mathml1  args)))))
 
52
 
 
53
(defun mathml1 (mexplabel &optional filename ) ;; mexplabel, and optional filename
 
54
  (prog (mexp  texport $gcprint ccol x y itsalabel tmpport)
 
55
        ;; $gcprint = nil turns gc messages off
 
56
        (setq ccol 1)
 
57
        (cond ((null mexplabel)
 
58
               (displa " No eqn given to MathML")
 
59
               (return nil)))
 
60
        ;; collect the file-name, if any, and open a port if needed
 
61
        (setq texport (cond((null filename) *standard-output* ); t= output to terminal
 
62
                           (t
 
63
                             (open (string (stripdollar filename))
 
64
                                   :direction :output
 
65
                                   :if-exists :append
 
66
                                   :if-does-not-exist :create))))
 
67
        ;; go back and analyze the first arg more thoroughly now.
 
68
        ;; do a normal evaluation of the expression in macsyma
 
69
        (setq mexp (meval mexplabel))
 
70
        (cond ((memq mexplabel $labels); leave it if it is a label
 
71
               (setq mexplabel (concat "(" (stripdollar mexplabel) ")"))
 
72
               (setq itsalabel t))
 
73
              (t (setq mexplabel nil)));flush it otherwise
 
74
 
 
75
        ;; maybe it is a function?
 
76
        (cond((symbolp (setq x mexp)) ;;exclude strings, numbers
 
77
              (setq x ($verbify x))
 
78
              (cond ((setq y (mget x 'mexpr))
 
79
                     (setq mexp (list '(mdefine) (cons (list x) (cdadr y)) (caddr y))))
 
80
                    ((setq y (mget x 'mmacro))
 
81
                     (setq mexp (list '(mdefmacro) (cons (list x) (cdadr y)) (caddr y))))
 
82
                    ((setq y (mget x 'aexpr))
 
83
                     (setq mexp (list '(mdefine) (cons (list x 'array) (cdadr y)) (caddr y)))))))
 
84
        (cond ((and (null (atom mexp))
 
85
                    (memq (caar mexp) '(mdefine mdefmacro)))
 
86
               (format texport "<pre>~%" ) 
 
87
               (cond (mexplabel (format texport "~a " mexplabel)))
 
88
               ;; need to get rid of "<" signs
 
89
               (setq tmpport (make-string-output-stream))
 
90
               (mgrind mexp tmpport)
 
91
               (close tmpport)
 
92
               (format texport "~a" 
 
93
                       (string-substitute "&lt;" #\< (get-output-stream-string tmpport)))
 
94
               (format texport ";~%</pre>"))
 
95
 
 
96
              ((and
 
97
                itsalabel ;; but is it a user-command-label?
 
98
                (eq (getchar $inchar 2) (getchar mexplabel 2)))
 
99
               ;; aha, this is a C-line: do the grinding:
 
100
               (format texport "<pre>~%~a " mexplabel) 
 
101
               ;; need to get rid of "<" signs
 
102
               (setq tmpport (make-string-output-stream))
 
103
               (mgrind mexp tmpport)
 
104
               (close tmpport)
 
105
               (format texport "~a" 
 
106
                       (string-substitute "&lt;" #\< (get-output-stream-string tmpport)))
 
107
               (format texport ";~%</pre>"))
 
108
 
 
109
              (t ; display the expression for MathML now:
 
110
                 (myprinc "<math xmlns=\"http://www.w3.org/1998/Math/MathML\"> ")
 
111
                 (mapc #'myprinc
 
112
                       ;;initially the left and right contexts are
 
113
                       ;; empty lists, and there are implicit parens
 
114
                       ;; around the whole expression
 
115
                       (mathml mexp nil nil 'mparen 'mparen))
 
116
                 (cond (mexplabel
 
117
                        (format texport "<mspace width=\"verythickmathspace\"/> <mtext>~a</mtext> " mexplabel)))
 
118
                 (format texport "</math>")))
 
119
        (cond(filename(terpri texport); and drain port if not terminal
 
120
                      (close texport)))
 
121
        (return mexplabel)))
 
122
 
 
123
(defun mathml (x l r lop rop)
 
124
        ;; x is the expression of interest; l is the list of strings to its
 
125
        ;; left, r to its right. lop and rop are the operators on the left
 
126
        ;; and right of x in the tree, and will determine if parens must
 
127
        ;; be inserted
 
128
        (setq x (nformat x))
 
129
        (cond ((atom x) (mathml-atom x l r))
 
130
              ((or (<= (mathml-lbp (caar x)) (mathml-rbp lop)) 
 
131
                   (> (mathml-lbp rop) (mathml-rbp (caar x))))
 
132
               (mathml-paren x l r))
 
133
              ;; special check needed because macsyma notates arrays peculiarly
 
134
              ((memq 'array (cdar x)) (mathml-array x l r))
 
135
              ;; dispatch for object-oriented mathml-ifiying
 
136
              ((get (caar x) 'mathml) (funcall (get (caar x) 'mathml) x l r))
 
137
              (t (mathml-function x l r nil))))
 
138
 
 
139
(defun string-substitute (newstring oldchar x &aux matchpos)
 
140
  (setq matchpos (position oldchar x))
 
141
  (if (null matchpos) x
 
142
    (concatenate 'string 
 
143
                 (subseq x 0 matchpos)
 
144
                 newstring
 
145
                 (string-substitute newstring oldchar (subseq x (1+ matchpos))))))
 
146
 
 
147
;;; NOTE that we try to include spaces after closing tags (e.g. "</mwhatever> ")
 
148
;;; so that the line breaking algorithm in myprinc has some spaces where it
 
149
;;; can choose to line break.
 
150
 
 
151
;;; First we have the functions which are called directly by mathml and its
 
152
;;; descendents
 
153
 
 
154
(defun mathml-atom (x l r) 
 
155
  (append l
 
156
          (list (cond ((numberp x) (mathmlnumformat x))
 
157
                      ((mstringp x) (string-left-trim '(#\&) x))
 
158
                      ((and (symbolp x) (get x 'mathmlword)))
 
159
                      (t (mathml-stripdollar x))))
 
160
          r))
 
161
 
 
162
(defun mathmlnumformat(atom)
 
163
  (let (r firstpart exponent)
 
164
    (cond ((integerp atom)
 
165
           (strcat "<mn>" (format nil "~d" atom) "</mn> "))
 
166
          (t
 
167
           (setq r (explode atom))
 
168
           (setq exponent (member 'e r :test #'string-equal));; is it ddd.ddde+EE
 
169
           (cond ((null exponent)
 
170
                   ;; it is not. go with it as given
 
171
                  (strcat "<mn>" (format nil "~s" atom) "</mn> "))
 
172
                 (t
 
173
                  (setq firstpart
 
174
                        (nreverse (cdr (member 'e (reverse r) :test #'string-equal))))
 
175
                  (strcat 
 
176
                   "<mrow><mn>"
 
177
                   (apply #'strcat firstpart)
 
178
                   "</mn><mo>&times;</mo> <msup><mn>10</mn><mn>"
 
179
                   (apply #'strcat (cdr exponent))
 
180
                   "</mn></msup> </mrow> ")
 
181
                  ))))))
 
182
 
 
183
(defun mathml-stripdollar(sym)
 
184
  (or (symbolp sym) 
 
185
      (return-from mathml-stripdollar sym))
 
186
  (let* ((pname (string-left-trim '(#\$) (symbol-name sym)))
 
187
         (l (length pname))
 
188
         (begin-sub
 
189
          (sloop for i downfrom (1- l)
 
190
                 when (not (digit-char-p (aref pname i)))
 
191
                 do (return (1+ i)))))
 
192
    (cond ((< begin-sub l) ;; need to do subscripting
 
193
           (strcat "<msub><mi>" 
 
194
                   (subseq pname 0 begin-sub)
 
195
                   "</mi> <mn>" 
 
196
                   (subseq pname begin-sub l)
 
197
                   "</mn></msub> "))
 
198
          (t ;; no subscripting needed
 
199
           (strcat "<mi>" pname "</mi> ")))))
 
200
 
 
201
(defun mathml-paren (x l r)
 
202
  (mathml x (append l '("<mfenced separators=\"\">")) (cons "</mfenced> " r) 'mparen 'mparen))
 
203
 
 
204
(defun mathml-array (x l r)
 
205
  (let ((f))
 
206
    (if (eq 'mqapply (caar x))
 
207
        (setq f (cadr x)
 
208
              x (cdr x)
 
209
              l (mathml f (append l (list "<mfenced separators=\",\">")) 
 
210
                        (list "</mfenced> ") 'mparen 'mparen))
 
211
      (setq f (caar x)
 
212
            l (mathml (mathmlword f) (append l '("<msub><mrow>")) nil lop 'mfunction)))
 
213
    (setq
 
214
     r (nconc (mathml-list (cdr x) nil (list "</mrow></msub> ") "<mo>,</mo>") r))
 
215
    (nconc l (list "</mrow><mrow>") r  )))
 
216
 
 
217
;; set up a list , separated by symbols (, * ...)  and then tack on the
 
218
;; ending item (e.g. "]" or perhaps ")"
 
219
(defun mathml-list (x l r sym)
 
220
  (if (null x) r
 
221
      (do ((nl))
 
222
          ((null (cdr x))
 
223
           (setq nl (nconc nl (mathml (car x)  l r 'mparen 'mparen)))
 
224
           nl)
 
225
          (setq nl (nconc nl (mathml (car x)  l (list sym) 'mparen 'mparen))
 
226
                  x (cdr x)
 
227
                  l nil))))
 
228
 
 
229
;; we could patch this so sin x rather than sin(x), but instead we made sin a prefix
 
230
;; operator
 
231
(defun mathml-function (x l r op) op
 
232
  (setq l (mathml (mathmlword (caar x)) l nil 'mparen 'mparen)
 
233
        r (mathml (cons '(mprogn) (cdr x)) nil r 'mparen 'mparen))
 
234
  (nconc l r))
 
235
 
 
236
;;; Now we have functions which are called via property lists
 
237
 
 
238
(defun mathml-prefix (x l r)
 
239
  (mathml (cadr x) (append l (mathmlsym (caar x))) r (caar x) rop))
 
240
 
 
241
(defun mathml-infix (x l r)
 
242
  ;; check for 2 args
 
243
  (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x)))
 
244
  (setq l (mathml (cadr x) l nil lop (caar x)))
 
245
  (mathml (caddr x) (append l (mathmlsym (caar x))) r (caar x) rop))
 
246
 
 
247
(defun mathml-postfix (x l r)
 
248
  (mathml (cadr x) l (append (mathmlsym (caar x)) r) lop (caar x)))
 
249
 
 
250
(defun mathml-nary (x l r)
 
251
  (let* ((op (caar x)) (sym (mathmlsym op)) (y (cdr x)) (ext-lop lop) (ext-rop rop))
 
252
    (cond ((null y)       (mathml-function x l r t)) ; this should not happen
 
253
          ((null (cdr y)) (mathml-function x l r t)) ; this should not happen, too
 
254
          (t (do ((nl) (lop ext-lop op) (rop op (if (null (cdr y)) ext-rop op)))
 
255
                 ((null (cdr y)) (setq nl (nconc nl (mathml (car y)  l r lop rop))) nl)
 
256
                 (setq nl (nconc nl (mathml (car y)  l (list sym)   lop rop))
 
257
                       y (cdr y)
 
258
                       l nil))))))
 
259
 
 
260
(defun mathml-nofix (x l r) (mathml (caar x) l r (caar x) rop))
 
261
 
 
262
(defun mathml-matchfix (x l r)
 
263
  (setq l (append l (car (mathmlsym (caar x))))
 
264
        ;; car of mathmlsym of a matchfix operator is the lead op
 
265
        r (append (cdr (mathmlsym (caar x))) r)
 
266
        ;; cdr is the trailing op
 
267
        x (mathml-list (cdr x) nil r "<mo>,</mo>")) 
 
268
  (append l x))
 
269
 
 
270
(defun mathmlsym (x) (or (get x 'mathmlsym) (get x 'strsym)(get x 'dissym)
 
271
                      (stripdollar x)))
 
272
 
 
273
(defun mathmlword (x)(or (get x 'mathmlword) (stripdollar x)))
 
274
 
 
275
(defprop bigfloat mathml-bigfloat mathml)
 
276
 
 
277
(defun mathml-bigfloat (x l r) (declare (ignore l r)) (fpformat x))
 
278
 
 
279
(defprop mprog "<mi>block</mi><mspace width=\"mediummathspace\"/> " mathmlword) 
 
280
(defprop %erf "<mi>erf</mi> " mathmlword)
 
281
(defprop $erf "<mi>erf</mi> " mathmlword) ;; etc for multicharacter names
 
282
(defprop $true  "<mi>true</mi> "  mathmlword)
 
283
(defprop $false "<mi>false</mi> " mathmlword)
 
284
 
 
285
(defprop mprogn mathml-matchfix mathml) ;; mprogn is (<progstmnt>, ...)
 
286
(defprop mprogn (("<mfenced separators=\"\">") "</mfenced> ") mathmlsym)
 
287
 
 
288
(defprop mlist mathml-matchfix mathml)
 
289
(defprop mlist (("<mfenced separators=\"\" open=\"[\" close=\"]\">")"</mfenced> ") mathmlsym)
 
290
 
 
291
;;absolute value
 
292
(defprop mabs mathml-matchfix mathml)
 
293
(defprop mabs (("<mfenced separators=\"\" open=\"|\" close=\"|\">")"</mfenced> ") mathmlsym) 
 
294
 
 
295
(defprop mqapply mathml-mqapply mathml)
 
296
 
 
297
(defun mathml-mqapply (x l r)
 
298
  (setq l (mathml (cadr x) l (list "(" ) lop 'mfunction)
 
299
        r (mathml-list (cddr x) nil (cons ")" r) "<mo>,</mo>"))
 
300
  (append l r));; fixed 9/24/87 RJF
 
301
 
 
302
(defprop $%i "<mi>&ImaginaryI;</mi> " mathmlword)
 
303
(defprop $%pi "<mi>&pi;</mi> " mathmlword)
 
304
(defprop $%e "<mi>&ExponentialE;</mi> " mathmlword)
 
305
(defprop $inf "<mi>&infin;</mi> " mathmlword)
 
306
(defprop $minf "<mi>-&infin;</mi> " mathmlword)
 
307
(defprop %laplace "<mo>&Laplacetrf;</mo>" mathmlword)
 
308
(defprop $alpha "<mi>&alpha;</mi> " mathmlword)
 
309
(defprop $beta "<mi>&beta;</mi> " mathmlword)
 
310
(defprop $gamma "<mi>&gamma;</mi> " mathmlword)
 
311
(defprop %gamma "<mi>&Gamma;</mi> " mathmlword)
 
312
(defprop $delta "<mi>&delta;</mi> " mathmlword)
 
313
(defprop $epsilon "<mi>&epsilon;</mi> " mathmlword)
 
314
(defprop $zeta "<mi>&zeta;</mi> " mathmlword)
 
315
(defprop $eta "<mi>&eta;</mi> " mathmlword)
 
316
(defprop $theta "<mi>&theta;</mi> " mathmlword)
 
317
(defprop $iota "<mi>&iota;</mi> " mathmlword)
 
318
(defprop $kappa "<mi>&kappa;</mi> " mathmlword)
 
319
;(defprop $lambda "<mi>&lambda;</mi> " mathmlword)
 
320
(defprop $mu "<mi>&mu;</mi> " mathmlword)
 
321
(defprop $nu "<mi>&nu;</mi> " mathmlword)
 
322
(defprop $xi "<mi>&xi;</mi> " mathmlword)
 
323
(defprop $pi "<mi>&pi;</mi> " mathmlword)
 
324
(defprop $rho "<mi>&rho;</mi> " mathmlword)
 
325
(defprop $sigma "<mi>&sigma;</mi> " mathmlword)
 
326
(defprop $tau "<mi>&tau;</mi> " mathmlword)
 
327
(defprop $upsilon "<mi>&upsilon;</mi> " mathmlword)
 
328
(defprop $phi "<mi>&phi;</mi> " mathmlword)
 
329
(defprop $chi "<mi>&chi;</mi> " mathmlword)
 
330
(defprop $psi "<mi>&psi;</mi> " mathmlword)
 
331
(defprop $omega "<mi>&omega;</mi> " mathmlword)
 
332
 
 
333
(defprop mquote mathml-prefix mathml)
 
334
(defprop mquote ("<mo>'</mo>") mathmlsym)
 
335
(defprop mquote 201. mathml-rbp)
 
336
 
 
337
(defprop msetq mathml-infix mathml)
 
338
(defprop msetq ("<mo>:</mo>") mathmlsym)
 
339
(defprop msetq 180. mathml-rbp)
 
340
(defprop msetq 20. mathml-rbp)
 
341
 
 
342
(defprop mset mathml-infix mathml)
 
343
(defprop mset ("<mo>::</mo>") mathmlsym)
 
344
(defprop mset 180. mathml-lbp)
 
345
(defprop mset 20. mathml-rbp)
 
346
 
 
347
(defprop mdefine mathml-infix mathml)
 
348
(defprop mdefine ("<mo>:=</mo>") mathmlsym)
 
349
(defprop mdefine 180. mathml-lbp)
 
350
(defprop mdefine 20. mathml-rbp)
 
351
 
 
352
(defprop mdefmacro mathml-infix mathml)
 
353
(defprop mdefmacro ("<mo>::=</mo>") mathmlsym)
 
354
(defprop mdefmacro 180. mathml-lbp)
 
355
(defprop mdefmacro 20. mathml-rbp)
 
356
 
 
357
(defprop marrow mathml-infix mathml)
 
358
(defprop marrow ("<mo>&rightarrow;</mo>") mathmlsym)
 
359
(defprop marrow 25 mathml-lbp)
 
360
(defprop marrow 25 mathml-rbp)
 
361
 
 
362
(defprop mfactorial mathml-postfix mathml)
 
363
(defprop mfactorial ("<mo>!</mo>") mathmlsym)
 
364
(defprop mfactorial 160. mathml-lbp)
 
365
 
 
366
(defprop mexpt mathml-mexpt mathml)
 
367
(defprop mexpt 140. mathml-lbp)
 
368
(defprop mexpt 139. mathml-rbp)
 
369
 
 
370
(defprop %sum 110. mathml-rbp)  ;; added by BLW, 1 Oct 2001
 
371
(defprop %product 115. mathml-rbp) ;; added by BLW, 1 Oct 2001
 
372
 
 
373
;; insert left-angle-brackets for mncexpt. a^<n> is how a^^n looks.
 
374
(defun mathml-mexpt (x l r)
 
375
  (let((nc (eq (caar x) 'mncexpt))); true if a^^b rather than a^b
 
376
     ;; here is where we have to check for f(x)^b to be displayed
 
377
     ;; as f^b(x), as is the case for sin(x)^2 .
 
378
     ;; which should be sin^2 x rather than (sin x)^2 or (sin(x))^2.
 
379
     ;; yet we must not display (a+b)^2 as +^2(a,b)...
 
380
     ;; or (sin(x))^(-1) as sin^(-1)x, which would be arcsine x
 
381
     (cond ;; this whole clause
 
382
           ;; should be deleted if this hack is unwanted and/or the
 
383
           ;; time it takes is of concern.
 
384
           ;; it shouldn't be too expensive.
 
385
           ((and (eq (caar x) 'mexpt) ; don't do this hack for mncexpt
 
386
                 (let*
 
387
                  ((fx (cadr x)); this is f(x)
 
388
                   (f (and (not (atom fx)) (atom (caar fx)) (caar fx))) ; this is f [or nil]
 
389
                   (bascdr (and f (cdr fx))) ; this is (x) [maybe (x,y..), or nil]
 
390
                   (expon (caddr x)) ;; this is the exponent
 
391
                   (doit (and
 
392
                          f ; there is such a function
 
393
                          (memq (getchar f 1) '(% $)) ;; insist it is a % or $ function
 
394
                          (not (memq f '(%sum %product %derivative %integrate %at
 
395
                                              %lsum %limit))) ;; what else? what a hack...
 
396
                          (or (and (atom expon) (not (numberp expon))) ; f(x)^y is ok
 
397
                              (and (atom expon) (numberp expon) (> expon 0))))))
 
398
                              ; f(x)^3 is ok, but not f(x)^-1, which could
 
399
                              ; inverse of f, if written f^-1 x
 
400
                              ; what else? f(x)^(1/2) is sqrt(f(x)), ??
 
401
                  (cond (doit
 
402
                        (setq l (mathml `((mexpt) ,f ,expon) l nil 'mparen 'mparen))
 
403
                        (if (and (null (cdr bascdr))
 
404
                                 (eq (get f 'mathml) 'mathml-prefix))
 
405
                            (setq r (mathml (car bascdr) nil r f 'mparen))
 
406
                          (setq r (mathml (cons '(mprogn) bascdr) nil r 'mparen 'mparen))))
 
407
                        (t nil))))) ; won't doit. fall through
 
408
      (t (setq l (mathml (cadr x) (append l '("<msup><mrow>")) nil lop (caar x))
 
409
               r (if (mmminusp (setq x (nformat (caddr x))))
 
410
                    ;; the change in base-line makes parens unnecessary
 
411
                    (if nc
 
412
                        (mathml (cadr x) '("</mrow> <mfenced separators=\"\" open=\"<\" close=\">\"> -")(cons "</mfenced></msup> " r) 'mparen 'mparen)
 
413
                        (mathml (cadr x) '("</mrow> <mfenced separators=\"\"> -")(cons "</mfenced></msup> " r) 'mparen 'mparen))
 
414
                    (if nc
 
415
                        (mathml x (list "</mrow> <mfenced separators=\"\" open=\"<\" close=\">\">")(cons "</mfenced></msup>" r) 'mparen 'mparen)
 
416
                        (if (and (numberp x) (< x 10))
 
417
                            (mathml x (list "</mrow> ")(cons "</msup> " r) 'mparen 'mparen)
 
418
                            (mathml x (list "</mrow> <mrow>")(cons "</mrow></msup> " r) 'mparen 'mparen))
 
419
                        )))))
 
420
      (append l r)))
 
421
 
 
422
(defprop mncexpt mathml-mexpt mathml)
 
423
 
 
424
(defprop mncexpt 135. mathml-lbp)
 
425
(defprop mncexpt 134. mathml-rbp)
 
426
 
 
427
(defprop mnctimes mathml-nary mathml)
 
428
(defprop mnctimes "<mi>&ctdot;</mi> " mathmlsym)
 
429
(defprop mnctimes 110. mathml-lbp)
 
430
(defprop mnctimes 109. mathml-rbp)
 
431
 
 
432
(defprop mtimes mathml-nary mathml)
 
433
(defprop mtimes "<mspace width=\"thinmathspace\"/>" mathmlsym)
 
434
(defprop mtimes 120. mathml-lbp)
 
435
(defprop mtimes 120. mathml-rbp)
 
436
 
 
437
(defprop %sqrt mathml-sqrt mathml)
 
438
 
 
439
(defun mathml-sqrt(x l r)
 
440
  ;; format as \\sqrt { } assuming implicit parens for sqr grouping
 
441
  (mathml (cadr x) (append l  '("<msqrt>")) (append '("</msqrt>") r) 'mparen 'mparen))
 
442
 
 
443
;; macsyma doesn't know about cube (or nth) roots,
 
444
;; but if it did, this is what it would look like.
 
445
(defprop $cubrt mathml-cubrt mathml)
 
446
 
 
447
(defun mathml-cubrt (x l r)
 
448
  (mathml (cadr x) (append l  '("<mroot><mrow>")) (append '("</mrow>3</mroot>") r) 'mparen 'mparen))
 
449
 
 
450
(defprop mquotient mathml-mquotient mathml)
 
451
(defprop mquotient ("<mo>/</mo>") mathmlsym)
 
452
(defprop mquotient 122. mathml-lbp) ;;dunno about this
 
453
(defprop mquotient 123. mathml-rbp)
 
454
 
 
455
(defun mathml-mquotient (x l r)
 
456
  (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x)))
 
457
  (setq l (mathml (cadr x) (append l '("<mfrac><mrow>")) nil 'mparen 'mparen)
 
458
        r (mathml (caddr x) (list "</mrow> <mrow>") (append '("</mrow></mfrac> ")r) 'mparen 'mparen))
 
459
  (append l r))
 
460
 
 
461
(defprop $matrix mathml-matrix mathml)
 
462
 
 
463
(defun mathml-matrix(x l r) ;;matrix looks like ((mmatrix)((mlist) a b) ...)
 
464
  (append l `("<mfenced separators=\"\" open=\"(\" close=\")\"><mtable>")
 
465
         (mapcan #'(lambda(y)
 
466
                          (mathml-list (cdr y) (list "<mtr><mtd>") (list "</mtd></mtr> ") "</mtd><mtd>"))
 
467
                 (cdr x))
 
468
         '("</mtable></mfenced> ") r))
 
469
 
 
470
;; macsyma sum or prod is over integer range, not  low <= index <= high
 
471
;; Mathml is lots more flexible .. but
 
472
 
 
473
(defprop %sum mathml-sum mathml)
 
474
(defprop %lsum mathml-lsum mathml)
 
475
(defprop %product mathml-sum mathml)
 
476
 
 
477
;; easily extended to union, intersect, otherops
 
478
 
 
479
(defun mathml-lsum(x l r)
 
480
  (let ((op (cond ((eq (caar x) '%lsum) "<mrow><munder><mo>&sum;</mo> <mrow>")
 
481
                  ;; extend here
 
482
                  ))
 
483
        ;; gotta be one of those above 
 
484
        (s1 (mathml (cadr x) nil nil 'mparen rop));; summand
 
485
        (index ;; "index = lowerlimit"
 
486
               (mathml `((min simp) , (caddr x), (cadddr x))  nil nil 'mparen 'mparen)))
 
487
       (append l `( ,op ,@index "</mrow></munder> <mrow>" ,@s1 "</mrow></mrow> ") r)))
 
488
 
 
489
(defun mathml-sum(x l r)
 
490
  (let ((op (cond ((eq (caar x) '%sum) "<mrow><munderover><mo>&sum;</mo><mrow>")
 
491
                  ((eq (caar x) '%product) "<mrow><munderover><mo>&prod;</mo><mrow>")
 
492
                  ;; extend here
 
493
                  ))
 
494
        ;; gotta be one of those above
 
495
        (s1 (mathml (cadr x) nil nil 'mparen rop));; summand
 
496
        (index ;; "index = lowerlimit"
 
497
               (mathml `((mequal simp) ,(caddr x),(cadddr x)) nil nil 'mparen 'mparen))
 
498
        (toplim (mathml (car(cddddr x)) nil nil 'mparen 'mparen)))
 
499
       (append l `( ,op ,@index "</mrow> <mrow>" ,@toplim "</mrow></munderover> <mrow>" ,@s1 "</mrow></mrow> ") r)))
 
500
 
 
501
(defprop %integrate mathml-int mathml)
 
502
 
 
503
(defun mathml-int (x l r)
 
504
  (let ((s1 (mathml (cadr x) nil nil 'mparen 'mparen));;integrand delims / & d
 
505
        (var (mathml (caddr x) nil nil 'mparen rop))) ;; variable
 
506
       (cond((= (length x) 3)
 
507
             (append l `("<mrow><mo>&int;</mo><mrow>" ,@s1 "</mrow> <mspace width=\"mediummathspace\"/> <mrow><mo>&DifferentialD;</mo><mi>" ,@var "</mi></mrow></mrow> ") r))
 
508
            (t ;; presumably length 5
 
509
               (let ((low (mathml (nth 3 x) nil nil 'mparen 'mparen))
 
510
                     ;; 1st item is 0
 
511
                     (hi (mathml (nth 4 x) nil nil 'mparen 'mparen)))
 
512
                    (append l `("<mrow><munderover><mo>&int;</mo> <mrow>" ,@low "</mrow> <mrow>" ,@hi "</mrow> </munderover> <mrow>" ,@s1 "</mrow> <mspace width=\"mediummathspace\"/> <mrow><mo>&DifferentialD;</mo><mi>" ,@var "</mi> </mrow></mrow> ") r))))))
 
513
 
 
514
(defprop %limit mathml-limit mathml)
 
515
 
 
516
(defprop mrarr mathml-infix mathml)
 
517
(defprop mrarr ("<mo>&rarr;</mo> ") mathmlsym)
 
518
(defprop mrarr 80. mathml-lbp)
 
519
(defprop mrarr 80. mathml-rbp)
 
520
 
 
521
(defun mathml-limit(x l r) ;; ignoring direction, last optional arg to limit
 
522
  (let ((s1 (mathml (second x) nil nil 'mparen rop));; limitfunction
 
523
        (subfun ;; the thing underneath "limit"
 
524
         (mathml `((mrarr simp) ,(third x) ,(fourth x)) nil nil 'mparen 'mparen)))
 
525
       (append l `("<munder><mo>lim</mo><mrow>" ,@subfun "</mrow> </munder> <mrow>" ,@s1 "</mrow>") r)))
 
526
 
 
527
(defprop %at mathml-at mathml)
 
528
 
 
529
;; e.g.  at(diff(f(x)),x=a)
 
530
(defun mathml-at (x l r)
 
531
  (let ((s1 (mathml (cadr x) nil nil lop rop))
 
532
        (sub (mathml (caddr x) nil nil 'mparen 'mparen)))
 
533
       (append l '("<msub><mfenced separators=\"\" open=\"\" close=\"|\">") s1  '("</mfenced> <mrow>") sub '("</mrow> </msub> ") r)))
 
534
 
 
535
;;binomial coefficients
 
536
 
 
537
(defprop %binomial mathml-choose mathml)
 
538
 
 
539
(defun mathml-choose (x l r)
 
540
  `(,@l
 
541
    "<mfenced separators=\"\" open=\"(\" close=\")\"><mtable><mtr><mtd>"
 
542
    ,@(mathml (cadr x) nil nil 'mparen 'mparen)
 
543
    "</mtd></mtr> <mtr><mtd>"
 
544
    ,@(mathml (caddr x) nil nil 'mparen 'mparen)
 
545
    "</mtd></mtr> </mtable></mfenced> "
 
546
    ,@r))
 
547
 
 
548
 
 
549
(defprop rat mathml-rat mathml)
 
550
(defprop rat 120. mathml-lbp)
 
551
(defprop rat 121. mathml-rbp)
 
552
(defun mathml-rat(x l r) (mathml-mquotient x l r))
 
553
 
 
554
(defprop mplus mathml-mplus mathml)
 
555
(defprop mplus 100. mathml-lbp)
 
556
(defprop mplus 100. mathml-rbp)
 
557
 
 
558
(defun mathml-mplus (x l r)
 
559
 ;(declare (fixnum w))
 
560
 (cond ((memq 'trunc (car x))(setq r (cons "<mo>+</mo><mtext>&ctdot;</mtext> " r))))
 
561
 (cond ((null (cddr x))
 
562
        (if (null (cdr x))
 
563
            (mathml-function x l r t)
 
564
            (mathml (cadr x) (cons "<mo>+</mo>" l) r 'mplus rop)))
 
565
       (t (setq l (mathml (cadr x) l nil lop 'mplus)
 
566
                x (cddr x))
 
567
          (do ((nl l)  (dissym))
 
568
              ((null (cdr x))
 
569
               (if (mmminusp (car x)) (setq l (cadar x) dissym (list "<mo>-</mo> "))
 
570
                   (setq l (car x) dissym (list "<mo>+</mo> ")))
 
571
               (setq r (mathml l dissym r 'mplus rop))
 
572
               (append nl r))
 
573
              (if (mmminusp (car x)) (setq l (cadar x) dissym (list "<mo>-</mo> "))
 
574
                  (setq l (car x) dissym (list "<mo>+</mo> ")))
 
575
              (setq nl (append nl (mathml l dissym nil 'mplus 'mplus))
 
576
                    x (cdr x))))))
 
577
 
 
578
(defprop mminus mathml-prefix mathml)
 
579
(defprop mminus ("-") mathmlsym)
 
580
(defprop mminus 100. mathml-rbp)
 
581
(defprop mminus 100. mathml-lbp)
 
582
 
 
583
(defprop min mathml-infix mathml)
 
584
(defprop min ("<mo>&isin;</mo> ") mathmlsym)
 
585
(defprop min 80. mathml-lbp)
 
586
(defprop min 80. mathml-rbp)
 
587
 
 
588
(defprop mequal mathml-infix mathml)
 
589
(defprop mequal ("<mo>=</mo> ") mathmlsym)
 
590
(defprop mequal 80. mathml-lbp)
 
591
(defprop mequal 80. mathml-rbp)
 
592
 
 
593
(defprop mnotequal mathml-infix mathml)
 
594
(defprop mnotequal 80. mathml-lbp)
 
595
(defprop mnotequal 80. mathml-rbp)
 
596
 
 
597
(defprop mgreaterp mathml-infix mathml)
 
598
(defprop mgreaterp ("<mo>&gt;</mo> ") mathmlsym)
 
599
(defprop mgreaterp 80. mathml-lbp)
 
600
(defprop mgreaterp 80. mathml-rbp)
 
601
 
 
602
(defprop mgeqp mathml-infix mathml)
 
603
(defprop mgeqp ("<mo>&ge;</mo> ") mathmlsym)
 
604
(defprop mgeqp 80. mathml-lbp)
 
605
(defprop mgeqp 80. mathml-rbp)
 
606
 
 
607
(defprop mlessp mathml-infix mathml)
 
608
(defprop mlessp ("<mo>&lt;</mo> ") mathmlsym)
 
609
(defprop mlessp 80. mathml-lbp)
 
610
(defprop mlessp 80. mathml-rbp)
 
611
 
 
612
(defprop mleqp mathml-infix mathml)
 
613
(defprop mleqp ("<mo>&le;</mo> ") mathmlsym)
 
614
(defprop mleqp 80. mathml-lbp)
 
615
(defprop mleqp 80. mathml-rbp)
 
616
 
 
617
(defprop mnot mathml-prefix mathml)
 
618
(defprop mnot ("<mo>&not;</mo> ") mathmlsym)
 
619
(defprop mnot 70. mathml-rbp)
 
620
 
 
621
(defprop mand mathml-nary mathml)
 
622
(defprop mand ("<mo>&and;</mo> ") mathmlsym)
 
623
(defprop mand 60. mathml-lbp)
 
624
(defprop mand 60. mathml-rbp)
 
625
 
 
626
(defprop mor mathml-nary mathml)
 
627
(defprop mor ("<mo>&or;</mo> ") mathmlsym)
 
628
 
 
629
;; make sin(x) display as sin x , but sin(x+y) as sin(x+y)
 
630
;; etc
 
631
 
 
632
(defun mathml-setup (x)
 
633
  (let((a (car x))
 
634
       (b (cadr x)))
 
635
      (setf (get a 'mathml) 'mathml-prefix)
 
636
      (setf (get a 'mathmlword) b)  ;This means "sin" will always be roman
 
637
      (setf (get a 'mathmlsym) (list b))
 
638
      (setf (get a 'mathml-rbp) 130)))
 
639
 
 
640
(mapc #'mathml-setup
 
641
  '(
 
642
     (%acos "<mi>arccos</mi> ")
 
643
     (%asin "<mi>arcsin</mi> ")
 
644
     (%atan "<mi>arctan</mi> ")
 
645
     (%arg "<mi>arg</mi> ")
 
646
     (%cos "<mi>cos</mi> ")
 
647
     (%cosh "<mi>cosh</mi> ")
 
648
     (%cot "<mi>cot</mi> ")
 
649
     (%coth "<mi>coth</mi> ")
 
650
     (%csc "<mi>cosec</mi> ")
 
651
     (%deg "<mi>deg</mi> ")
 
652
     (%determinant "<mi>det</mi> ")
 
653
     (%dim "<mi>dim</mi> ")
 
654
     (%exp "<mi>exp</mi> ")
 
655
     (%gcd "<mi>gcd</mi> ")
 
656
     (%hom "<mi>hom</mi> ")
 
657
     (%inf "<mi>&infin;</mi> ") 
 
658
     (%ker "<mi>ker</mi> ")
 
659
     (%lg "<mi>lg</mi> ")
 
660
     ;;(%limit "<mi>lim</mi> ")
 
661
     (%liminf "<mi>lim inf</mi> ")
 
662
     (%limsup "<mi>lim sup</mi> ")
 
663
     (%ln "<mi>ln</mi> ")
 
664
     (%log "<mi>log</mi> ")
 
665
     (%max "<mi>max</mi> ")
 
666
     (%min "<mi>min</mi> ")
 
667
     ; Latex's "Pr" ... ?
 
668
     (%sec "<mi>sec</mi> ")
 
669
     (%sech "<mi>sech</mi> ")
 
670
     (%sin "<mi>sin</mi> ")
 
671
     (%sinh "<mi>sinh</mi> ")
 
672
     (%sup "<mi>sup</mi> ")
 
673
     (%tan "<mi>tan</mi> ")
 
674
     (%tanh "<mi>tanh</mi> ")
 
675
    ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual
 
676
     ;(%laplace "{\\cal L}")
 
677
     )) ;; etc
 
678
 
 
679
(defprop mor mathml-nary mathml)
 
680
(defprop mor 50. mathml-lbp)
 
681
(defprop mor 50. mathml-rbp)
 
682
 
 
683
(defprop mcond mathml-mcond mathml)
 
684
(defprop mcond 25. mathml-lbp)
 
685
(defprop mcond 25. mathml-rbp)
 
686
 
 
687
(defprop %derivative mathml-derivative mathml)
 
688
 
 
689
(defun mathml-derivative (x l r)
 
690
  (mathml (mathml-d x "&DifferentialD;") l r lop rop ))
 
691
 
 
692
(defun mathml-d(x dsym) ;dsym should be "&DifferentialD;" or "&PartialD;"
 
693
  ;; format the macsyma derivative form so it looks
 
694
  ;; sort of like a quotient times the deriva-dand.
 
695
  (let*
 
696
   ((arg (cadr x)) ;; the function being differentiated
 
697
    (difflist (cddr x)) ;; list of derivs e.g. (x 1 y 2)
 
698
    (ords (odds difflist 0)) ;; e.g. (1 2)
 
699
    (vars (odds difflist 1)) ;; e.g. (x y)
 
700
    (numer `((mexpt) ,dsym ((mplus) ,@ords))) ; d^n numerator
 
701
    (denom (cons '(mtimes)
 
702
                 (mapcan #'(lambda(b e)
 
703
                                  `(,dsym ,(simplifya `((mexpt) ,b ,e) nil)))
 
704
                         vars ords))))
 
705
   `((mtimes)
 
706
     ((mquotient) ,(simplifya numer nil) ,denom)
 
707
     ,arg)))
 
708
 
 
709
(defun mathml-mcond (x l r)
 
710
  (append l
 
711
    (mathml (cadr x) '("<mi>if</mi> <mspace width=\"mediummathspace\"/>")
 
712
      '("<mspace width=\"mediummathspace\"/> <mi>then</mi><mspace width=\"mediummathspace\"/> ") 'mparen 'mparen)
 
713
    (if (eql (fifth x) '$false)
 
714
      (mathml (caddr x) nil r 'mcond rop)
 
715
      (append (mathml (caddr x) nil nil 'mparen 'mparen)
 
716
        (mathml (fifth x) '("<mspace width=\"mediummathspace\"/> <mi>else</mi><mspace width=\"mediummathspace\"/> ") r 'mcond rop)))))
 
717
 
 
718
(defprop mdo mathml-mdo mathml)
 
719
(defprop mdo 30. mathml-lbp)
 
720
(defprop mdo 30. mathml-rbp)
 
721
(defprop mdoin mathml-mdoin mathml)
 
722
(defprop mdoin 30. mathml-rbp)
 
723
 
 
724
(defun mathml-lbp(x)(cond((get x 'mathml-lbp))(t(lbp x))))
 
725
(defun mathml-rbp(x)(cond((get x 'mathml-rbp))(t(lbp x))))
 
726
 
 
727
;; these aren't quite right
 
728
 
 
729
(defun mathml-mdo (x l r)
 
730
  (mathml-list (mathmlmdo x) l r "<mspace width=\"mediummathspace\"/> "))
 
731
 
 
732
(defun mathml-mdoin (x l r)
 
733
  (mathml-list (mathmlmdoin x) l r "<mspace width=\"mediummathspace\"/> "))
 
734
 
 
735
(defun mathmlmdo (x)
 
736
   (nconc (cond ((second x) `("<mi>for</mi> " ,(second x))))
 
737
         (cond ((equal 1 (third x)) nil)
 
738
               ((third x)  `("<mi>from</mi> " ,(third x))))
 
739
         (cond ((equal 1 (fourth x)) nil)
 
740
               ((fourth x) `("<mi>step</mi> " ,(fourth x)))
 
741
               ((fifth x)  `("<mi>next</mi> " ,(fifth x))))
 
742
         (cond ((sixth x)  `("<mi>thru</mi> " ,(sixth x))))
 
743
         (cond ((null (seventh x)) nil)
 
744
               ((eq 'mnot (caar (seventh x)))
 
745
                `("<mi>while</mi> " ,(cadr (seventh x))))
 
746
               (t `("<mi>unless</mi> " ,(seventh x))))
 
747
         `("<mi>do</mi> " ,(eighth x))))
 
748
 
 
749
(defun mathmlmdoin (x)
 
750
  (nconc `("<mi>for</mi>" ,(second x) "<mi>in</mi> " ,(third x))
 
751
         (cond ((sixth x) `("<mi>thru</mi> " ,(sixth x))))
 
752
         (cond ((null (seventh x)) nil)
 
753
               ((eq 'mnot (caar (seventh x)))
 
754
                `("<mi>while</mi> " ,(cadr (seventh x))))
 
755
               (t `("<mi>unless</mi> " ,(seventh x))))
 
756
         `("<mi>do</mi> " ,(eighth x))))
 
757
 
 
758
;; Undone and trickier:
 
759
;; Maybe do some special hacking for standard notations for
 
760
;; hypergeometric fns, alternative summation notations  0<=n<=inf, etc.