home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 January / enter-2004-01.iso / files / maxima-5.9.0.exe / {app} / share / maxima / 5.9.0 / src / mactex.lisp < prev    next >
Encoding:
Text File  |  2003-02-09  |  29.8 KB  |  925 lines

  1. (in-package "MAXIMA")
  2. ;; TeX-printing
  3. ;; (c) copyright 1987, Richard J. Fateman
  4. ;; small corrections and additions: Andrey Grozin, 2001
  5. ;; additional additions: Judah Milgram (JM), September 2001
  6. ;; additional corrections: Barton Willis (BLW), October 2001
  7.  
  8. ;; Usage: tex(d8,"/tmp/foo.tex"); tex(d10,"/tmp/foo.tex"); ..
  9. ;; to append lines d8 and d10 to the tex file.  If given only
  10. ;; one argument the result goes to standard output.
  11.  
  12. ;; Extract from permission letter to wfs:
  13. ;; Date: Sat, 2 Apr 88 18:06:16 PST
  14. ;; From: fateman%vangogh.Berkeley.EDU@ucbvax.Berkeley.EDU (Richard Fateman)
  15. ;; To: wfs@rascal.ics.UTEXAS.EDU
  16. ;; Subject: about tex...
  17. ;; You have my permission to put it in NESC or give it to anyone
  18. ;; else who might be interested in it....
  19.  
  20. ;; source language:
  21. ;; There are changes by wfs to allow use inside MAXIMA which runs
  22. ;; in COMMON LISP.  For original FRANZ LISP version contact rfw.
  23.  
  24. ;; intended environment: vaxima (Vax or Sun). Parser should be
  25. ;; equivalent (in lbp/rbp data) to 1986 NESC Vaxima.
  26. ;;;(provide 'tex)
  27. ;;;(in-package 'tex)
  28. ;;;(export '($tex $texinit))
  29. ;;;;; we'd like to just
  30. ;;;(import '(user::$bothcases user::lbp user::rbp user::nformat))
  31. ;;;(use-package 'user)
  32.  
  33. ;; March, 1987
  34.  
  35. ;; Method:
  36.  
  37. ;; Producing TeX from a macsyma internal expression is done by
  38. ;; a reversal of the parsing process.  Fundamentally, a
  39. ;; traversal of the expression tree is produced by the tex programs,
  40. ;; with appropriate substitutions and recognition of the
  41. ;; infix / prefix / postfix / matchfix relations on symbols. Various
  42. ;; changes are made to this so that TeX will like the results.
  43. ;; It is important to understand the binding powers of the operators
  44. ;; in Macsyma, in mathematics, and in TeX so that parentheses will
  45. ;; be inserted when necessary. Because TeX has different kinds of
  46. ;; groupings (e.g. in superscripts, within sqrts), not all
  47. ;; parentheses are explicitly need.
  48.  
  49. ;;  Instructions:
  50. ;; in macsyma, type tex(<expression>);  or tex(<label>); or
  51. ;; tex(<expr-or-label>, <file-name>);  In the case of a label,
  52. ;; a left-equation-number will be produced.
  53. ;; in case a file-name is supplied, the output will be sent
  54. ;; (perhaps appended) to that file.
  55.  
  56. ;(macsyma-module tex ); based on "mrg/grind"
  57.  
  58. #+franz
  59. ($bothcases t) ;; allow alpha and Alpha to be different
  60. (declare-top
  61.      (special lop rop ccol $gcprint texport $labels $inchar
  62.           vaxima-main-dir
  63.           )
  64.      (*expr tex-lbp tex-rbp))
  65.  
  66. ;; top level command the result of tex'ing the expression x.
  67. ;; Lots of messing around here to get C-labels verbatim printed
  68. ;; and function definitions verbatim "ground"
  69.  
  70. ;(defmspec $tex(l) ;; mexplabel, and optional filename
  71. ;  (let ((args (cdr l)))
  72. ;  (apply 'tex1  args)))
  73.  
  74. (defmspec $tex(l) ;; mexplabel, and optional filename
  75.   ;;if filename supplied but 'nil' then return a string
  76.   (let ((args (cdr l)))
  77.     (cond ((and (cdr args) (null (cadr args)))
  78.        (let ((*standard-output* (make-string-output-stream)))
  79.          (apply 'tex1  args)
  80.          (get-output-stream-string *standard-output*)
  81.          )
  82.        )
  83.       (t (apply 'tex1  args)))))
  84.  
  85.  
  86.  
  87. (defun tex1 (mexplabel &optional filename ) ;; mexplabel, and optional filename
  88.   (prog (mexp  texport $gcprint ccol x y itsalabel)
  89.     ;; $gcprint = nil turns gc messages off
  90.     (setq ccol 1)
  91.     (cond ((null mexplabel)
  92.            (displa " No eqn given to TeX")
  93.            (return nil)))
  94.     ;; collect the file-name, if any, and open a port if needed
  95.     (setq texport (cond((null filename) *standard-output* ); t= output to terminal
  96.                (t
  97.                  (open (string (stripdollar filename))
  98.                    :direction :output
  99.                    :if-exists :append
  100.                    :if-does-not-exist :create))))
  101.     ;; go back and analyze the first arg more thoroughly now.
  102.     ;; do a normal evaluation of the expression in macsyma
  103.     (setq mexp (meval mexplabel))
  104.     (cond ((memq mexplabel $labels); leave it if it is a label
  105.            (setq mexplabel (concat "(" (stripdollar mexplabel) ")"))
  106.            (setq itsalabel t))
  107.           (t (setq mexplabel nil)));flush it otherwise
  108.  
  109.     ;; maybe it is a function?
  110.     (cond((symbolp (setq x mexp)) ;;exclude strings, numbers
  111.           (setq x ($verbify x))
  112.           (cond ((setq y (mget x 'mexpr))
  113.              (setq mexp (list '(mdefine) (cons (list x) (cdadr y)) (caddr y))))
  114.             ((setq y (mget x 'mmacro))
  115.              (setq mexp (list '(mdefmacro) (cons (list x) (cdadr y)) (caddr y))))
  116.             ((setq y (mget x 'aexpr))
  117.              (setq mexp (list '(mdefine) (cons (list x 'array) (cdadr y)) (caddr y)))))))
  118.     (cond ((and (null(atom mexp))
  119.             (memq (caar mexp) '(mdefine mdefmacro)))
  120.            (format texport "|~%" ) ;delimit with |marks
  121.            (cond (mexplabel (format texport "~a " mexplabel)))
  122.            (mgrind mexp texport) ;write expression as string
  123.            (format texport ";|~%"))
  124.  
  125.           ((and
  126.         itsalabel ;; but is it a user-command-label?
  127.         (eq (getchar $inchar 2) (getchar mexplabel 2)))
  128.            ;; aha, this is a C-line: do the grinding:
  129.            (format texport "~%|~a " mexplabel) ;delimit with |marks
  130.            (mgrind mexp texport) ;write expression as string
  131.            (format texport ";|~%"))
  132.  
  133.           (t ; display the expression for TeX now:
  134.          (myprinc "$$")
  135.          (mapc #'myprinc
  136.                ;;initially the left and right contexts are
  137.                ;; empty lists, and there are implicit parens
  138.                ;; around the whole expression
  139.                (tex mexp nil nil 'mparen 'mparen))
  140.          (cond (mexplabel
  141.             (format texport "\\leqno{\\tt ~a}" mexplabel)))
  142.          (format texport "$$")))
  143.     (cond(filename(terpri texport); and drain port if not terminal
  144.               (close texport)))
  145.     (return mexplabel)))
  146.  
  147. ;;; myprinc is an intelligent low level printing routine.  it keeps track of
  148. ;;; the size of the output for purposes of allowing the TeX file to
  149. ;;; have a reasonable line-line. myprinc will break it at a space
  150. ;;; once it crosses a threshold.
  151. ;;; this has nothign to do with breaking the resulting equations.
  152.  
  153. ;-      arg:    chstr -  string or number to princ
  154. ;-      scheme: This function keeps track of the current location
  155. ;-              on the line of the cursor and makes sure
  156. ;-              that a value is all printed on one line (and not divided
  157. ;-              by the crazy top level os routines)
  158.  
  159. (defun myprinc (chstr)
  160.        (prog (chlst)
  161.               (cond ((greaterp (plus (length (setq chlst (exploden chstr)))
  162.                                  ccol)
  163.                            70.)
  164.                   (terpri texport)      ;would have exceeded the line length
  165.                       (setq ccol 1.)
  166.               (myprinc " ")   ; lead off with a space for safety
  167.                       )) ;so we split it up.
  168.              (do ((ch chlst (cdr ch))
  169.                   (colc ccol (add1 colc)))
  170.                  ((null ch) (setq ccol colc))
  171.                  (tyo (car ch) texport))))
  172.  
  173. (defun myterpri nil
  174.   (cond (texport (terpri texport))
  175.     (t (mterpri)))
  176.     (setq ccol 1))
  177.  
  178. (defun tex (x l r lop rop)
  179.     ;; x is the expression of interest; l is the list of strings to its
  180.     ;; left, r to its right. lop and rop are the operators on the left
  181.     ;; and right of x in the tree, and will determine if parens must
  182.     ;; be inserted
  183.     (setq x (nformat x))
  184.     (cond ((atom x) (tex-atom x l r))
  185.           ((or (<= (tex-lbp (caar x)) (tex-rbp lop)) (> (tex-lbp rop) (tex-rbp (caar x))))
  186.            (tex-paren x l r))
  187.           ;; special check needed because macsyma notates arrays peculiarly
  188.           ((memq 'array (cdar x)) (tex-array x l r))
  189.           ;; dispatch for object-oriented tex-ifiying
  190.           ((get (caar x) 'tex) (funcall (get (caar x) 'tex) x l r))
  191.           (t (tex-function x l r nil))))
  192.  
  193. (defun tex-atom (x l r) ;; atoms: note: can we lose by leaving out {}s ?
  194.   (append l
  195.       (list (cond ((numberp x) (texnumformat x))
  196.               ((and (symbolp x) (get x 'texword)))
  197.               (t (tex-stripdollar x))))
  198.  
  199.       r))
  200.  
  201.  
  202.  
  203. (defvar *tex-translations* nil)
  204. ;; '(("AB" . "a")("X" . "x")) would cause  AB12 and X3 C4 to print a_{12} and x_3 C_4
  205.  
  206. ;; Read forms from file F1 and output them to F2
  207. (defun tex-forms (f1 f2 &aux tem (eof *mread-eof-obj*))
  208.   (with-open-file (st f1)
  209.     (sloop while (not (eq (setq tem (mread-raw st eof)) eof))
  210.        do (tex1 (third tem) f2))))
  211.  
  212. (defun tex-stripdollar(sym &aux )
  213.   (or (symbolp sym) (return-from tex-stripdollar sym))
  214.   (let* ((pname (symbol-name sym))
  215.      (l (length pname))
  216.      (begin-sub
  217.       (sloop for i downfrom (1- l)
  218.          when (not (digit-char-p (aref pname i)))
  219.          do (return (1+ i))))
  220.      (tem  (make-array (+ l 4) :element-type ' #.(array-element-type "abc") :fill-pointer 0)))
  221.     (sloop for i below l
  222.        do
  223.        (cond ((eql i begin-sub)
  224.           (let ((a (assoc tem  *tex-translations* :test 'equal)))
  225.             (cond (a
  226.                (setq a (cdr a))
  227.                (setf (fill-pointer tem) 0)
  228.                (sloop for i below (length a)
  229.                   do
  230.                   (vector-push (aref a i) tem)))))
  231.           (vector-push #\_ tem)
  232.           (unless (eql i (- l 1))
  233.              (vector-push #\{ tem)
  234.              (setq begin-sub t))))
  235.        (cond ((not (and (eql i 0) (eql (aref pname i) #\$)))
  236.           (vector-push (aref pname i) tem)))
  237.        finally
  238.        (cond ((eql begin-sub t)
  239.           (vector-push #\} tem))))
  240.     (intern tem)))
  241.  
  242. ;; A.G. 2001: I prefer the following version:
  243. ;(defun tex-stripdollar (sym)
  244. ;  (or (symbolp sym) (return-from tex-stripdollar sym))
  245. ;  (let* ((name (symbol-name sym))
  246. ;      (pname (if (eql (elt name 0) #\$) (subseq name 1) name))
  247. ;      (l (length pname)))
  248. ;    (cond
  249. ;      ((eql l 1) pname)
  250. ;      (t (concatenate 'string "\\mathrm{" pname "}")))))
  251.  
  252. (defun strcat (&rest args)
  253.   (apply #'concatenate 'string (mapcar #'string args)))
  254.  
  255. ;; 10/14/87 RJF  convert 1.2e20 to 1.2 \cdot 10^{20}
  256. ;; 03/30/01 RLT  make that 1.2 \times 10^{20}
  257. (defun texnumformat(atom)
  258.   (let (r firstpart exponent)
  259.     (cond ((integerp atom)
  260.        atom)
  261.       (t
  262.        (setq r (explode atom))
  263.        (setq exponent (member 'e r :test #'string-equal));; is it ddd.ddde+EE
  264.        (cond ((null exponent)
  265.            ;; it is not. go with it as given
  266.           atom)
  267.          (t
  268.           (setq firstpart
  269.             (nreverse (cdr (member 'e (reverse r) :test #'string-equal))))
  270.           (strcat (apply #'strcat firstpart )
  271.               " \\times 10^{"
  272.               (apply #'strcat (cdr exponent))
  273.               "}")))))))
  274.  
  275. (defun tex-paren (x l r)
  276.   (tex x (append l '("\\left(")) (cons "\\right)" r) 'mparen 'mparen))
  277.  
  278. (defun tex-array (x l r)
  279.   (let ((f))
  280.     (if (eq 'mqapply (caar x))
  281.     (setq f (cadr x)
  282.           x (cdr x)
  283.           l (tex f (append l (list "\\left(")) (list "\\right)") 'mparen 'mparen))
  284.       (setq f (caar x)
  285.         l (tex (texword f) l nil lop 'mfunction)))
  286.     (setq
  287.      r (nconc (tex-list (cdr x) nil (list "}") ",") r))
  288.     (nconc l (list "_{") r  )))
  289.  
  290. ;; we could patch this so sin x rather than sin(x), but instead we made sin a prefix
  291. ;; operator
  292.  
  293. (defun tex-function (x l r op) op
  294.     (setq l (tex (texword (caar x)) l nil 'mparen 'mparen)
  295.           r (tex (cons '(mprogn) (cdr x)) nil r 'mparen 'mparen))
  296.     (nconc l r))
  297.  
  298. ;; set up a list , separated by symbols (, * ...)  and then tack on the
  299. ;; ending item (e.g. "]" or perhaps ")"
  300.  
  301. (defun tex-list (x l r sym)
  302.   (if (null x) r
  303.       (do ((nl))
  304.       ((null (cdr x))
  305.        (setq nl (nconc nl (tex (car x)  l r 'mparen 'mparen)))
  306.        nl)
  307.       (setq nl (nconc nl (tex (car x)  l (list sym) 'mparen 'mparen))
  308.           x (cdr x)
  309.           l nil))))
  310.  
  311. (defun tex-prefix (x l r)
  312.   (tex (cadr x) (append l (texsym (caar x))) r (caar x) rop))
  313.  
  314. (defun tex-infix (x l r)
  315.   ;; check for 2 args
  316.   (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x)))
  317.   (setq l (tex (cadr x) l nil lop (caar x)))
  318.   (tex (caddr x) (append l (texsym (caar x))) r (caar x) rop))
  319.  
  320. (defun tex-postfix (x l r)
  321.   (tex (cadr x) l (append (texsym (caar x)) r) lop (caar x)))
  322.  
  323. (defun tex-nary (x l r)
  324.   (let* ((op (caar x)) (sym (texsym op)) (y (cdr x)) (ext-lop lop) (ext-rop rop))
  325.     (cond ((null y)       (tex-function x l r t)) ; this should not happen
  326.           ((null (cdr y)) (tex-function x l r t)) ; this should not happen, too
  327.           (t (do ((nl) (lop ext-lop op) (rop op (if (null (cdr y)) ext-rop op)))
  328.                  ((null (cdr y)) (setq nl (nconc nl (tex (car y)  l r lop rop))) nl)
  329.              (setq nl (nconc nl (tex (car y)  l (list sym)   lop rop))
  330.                y (cdr y)
  331.                l nil))))))
  332.  
  333. (defun tex-nofix (x l r) (tex (caar x) l r (caar x) rop))
  334.  
  335. (defun tex-matchfix (x l r)
  336.   (setq l (append l (car (texsym (caar x))))
  337.     ;; car of texsym of a matchfix operator is the lead op
  338.     r (append (cdr (texsym (caar x))) r)
  339.     ;; cdr is the trailing op
  340.     x (tex-list (cdr x) nil r ","))
  341.   (append l x))
  342.  
  343. (defun texsym (x) (or (get x 'texsym) (get x 'strsym)(get x 'dissym)
  344.               (stripdollar x)))
  345.  
  346. (defun texword (x)(or (get x 'texword) (stripdollar x)))
  347.  
  348. (defprop bigfloat tex-bigfloat tex)
  349.  
  350. (defun tex-bigfloat (x l r) (fpformat x))
  351.  
  352. (defprop mprog "\\mathbf{block}\\>" texword)
  353. (defprop %erf "\\mathrm{erf}" texword)
  354. (defprop $erf "\\mathrm{erf}" texword) ;; etc for multicharacter names
  355. (defprop $true  "\\mathbf{true}"  texword)
  356. (defprop $false "\\mathbf{false}" texword)
  357.  
  358. (defprop mprogn tex-matchfix tex) ;; mprogn is (<progstmnt>, ...)
  359. (defprop mprogn (("\\left(") "\\right)") texsym)
  360.  
  361. (defprop mlist tex-matchfix tex)
  362. (defprop mlist (("\\left[ ")" \\right] ") texsym)
  363.  
  364. ;;absolute value
  365. (defprop mabs tex-matchfix tex)
  366. (defprop mabs (("\\left| ")"\\right| ") texsym)
  367.  
  368. (defprop mqapply tex-mqapply tex)
  369.  
  370. (defun tex-mqapply (x l r)
  371.   (setq l (tex (cadr x) l (list "(" ) lop 'mfunction)
  372.     r (tex-list (cddr x) nil (cons ")" r) ","))
  373.   (append l r));; fixed 9/24/87 RJF
  374.  
  375. (defprop $%i "i" texword)
  376. (defprop $%pi "\\pi" texword)
  377. (defprop $%e "e" texword)
  378. (defprop $inf "\\infty " texword)
  379. (defprop $minf " -\\infty " texword)
  380. (defprop %laplace "{\\cal L}" texword)
  381. (defprop $alpha "\\alpha" texword)
  382. (defprop $beta "\\beta" texword)
  383. (defprop $gamma "\\gamma" texword)
  384. (defprop %gamma "\\Gamma" texword)
  385. (defprop $delta "\\delta" texword)
  386. (defprop $epsilon "\\varepsilon" texword)
  387. (defprop $zeta "\\zeta" texword)
  388. (defprop $eta "\\eta" texword)
  389. (defprop $theta "\\vartheta" texword)
  390. (defprop $iota "\\iota" texword)
  391. (defprop $kappa "\\varkappa" texword)
  392. ;(defprop $lambda "\\lambda" texword)
  393. (defprop $mu "\\mu" texword)
  394. (defprop $nu "\\nu" texword)
  395. (defprop $xi "\\xi" texword)
  396. (defprop $pi "\\pi" texword)
  397. (defprop $rho "\\rho" texword)
  398. (defprop $sigma "\\sigma" texword)
  399. (defprop $tau "\\tau" texword)
  400. (defprop $upsilon "\\upsilon" texword)
  401. (defprop $phi "\\varphi" texword)
  402. (defprop $chi "\\chi" texword)
  403. (defprop $psi "\\psi" texword)
  404. (defprop $omega "\\omega" texword)
  405.  
  406. (defprop mquote tex-prefix tex)
  407. (defprop mquote ("'") texsym)
  408. (defprop mquote 201. tex-rbp)
  409.  
  410. (defprop msetq tex-infix tex)
  411. (defprop msetq (":") texsym)
  412. (defprop msetq 180. tex-rbp)
  413. (defprop msetq 20. tex-rbp)
  414.  
  415. (defprop mset tex-infix tex)
  416. (defprop mset ("::") texsym)
  417. (defprop mset 180. tex-lbp)
  418. (defprop mset 20. tex-rbp)
  419.  
  420. (defprop mdefine tex-infix tex)
  421. (defprop mdefine (":=") texsym)
  422. (defprop mdefine 180. tex-lbp)
  423. (defprop mdefine 20. tex-rbp)
  424.  
  425. (defprop mdefmacro tex-infix tex)
  426. (defprop mdefmacro ("::=") texsym)
  427. (defprop mdefmacro 180. tex-lbp)
  428. (defprop mdefmacro 20. tex-rbp)
  429.  
  430. (defprop marrow tex-infix tex)
  431. (defprop marrow ("\\rightarrow ") texsym)
  432. (defprop marrow 25 tex-lbp)
  433. (defprop marrow 25 tex-rbp)
  434.  
  435. (defprop mfactorial tex-postfix tex)
  436. (defprop mfactorial ("!") texsym)
  437. (defprop mfactorial 160. tex-lbp)
  438.  
  439. (defprop mexpt tex-mexpt tex)
  440. (defprop mexpt 140. tex-lbp)
  441. (defprop mexpt 139. tex-rbp)
  442.  
  443. (defprop %sum 110. tex-rbp)  ;; added by BLW, 1 Oct 2001
  444. (defprop %product 115. tex-rbp) ;; added by BLW, 1 Oct 2001
  445.  
  446. ;; insert left-angle-brackets for mncexpt. a^<n> is how a^^n looks.
  447. (defun tex-mexpt (x l r)
  448.   (let((nc (eq (caar x) 'mncexpt))); true if a^^b rather than a^b
  449.      ;; here is where we have to check for f(x)^b to be displayed
  450.      ;; as f^b(x), as is the case for sin(x)^2 .
  451.      ;; which should be sin^2 x rather than (sin x)^2 or (sin(x))^2.
  452.      ;; yet we must not display (a+b)^2 as +^2(a,b)...
  453.      ;; or (sin(x))^(-1) as sin^(-1)x, which would be arcsine x
  454.      (cond ;; this whole clause
  455.        ;; should be deleted if this hack is unwanted and/or the
  456.        ;; time it takes is of concern.
  457.        ;; it shouldn't be too expensive.
  458.        ((and (eq (caar x) 'mexpt) ; don't do this hack for mncexpt
  459.          (let*
  460.           ((fx (cadr x)); this is f(x)
  461.            (f (and (not (atom fx)) (atom (caar fx)) (caar fx))) ; this is f [or nil]
  462.            (bascdr (and f (cdr fx))) ; this is (x) [maybe (x,y..), or nil]
  463.            (expon (caddr x)) ;; this is the exponent
  464.            (doit (and
  465.               f ; there is such a function
  466.               (memq (getchar f 1) '(% $)) ;; insist it is a % or $ function
  467.                           (not (memq f '(%sum %product %derivative %integrate %at
  468.                           %lsum %limit))) ;; what else? what a hack...
  469.               (or (and (atom expon) (not (numberp expon))) ; f(x)^y is ok
  470.                   (and (atom expon) (numberp expon) (> expon 0))))))
  471.                   ; f(x)^3 is ok, but not f(x)^-1, which could
  472.                   ; inverse of f, if written f^-1 x
  473.                   ; what else? f(x)^(1/2) is sqrt(f(x)), ??
  474.           (cond (doit
  475.             (setq l (tex `((mexpt) ,f ,expon) l nil 'mparen 'mparen))
  476.             (if (and (null (cdr bascdr))
  477.                  (eq (get f 'tex) 'tex-prefix))
  478.                 (setq r (tex (car bascdr) nil r f 'mparen))
  479.               (setq r (tex (cons '(mprogn) bascdr) nil r 'mparen 'mparen))))
  480.                 (t nil))))) ; won't doit. fall through
  481.       (t (setq l (tex (cadr x) l nil lop (caar x))
  482.            r (if (mmminusp (setq x (nformat (caddr x))))
  483.             ;; the change in base-line makes parens unnecessary
  484.             (if nc
  485.             (tex (cadr x) '("^ {-\\langle ")(cons "\\rangle }" r) 'mparen 'mparen)
  486.             (tex (cadr x) '("^ {- ")(cons " }" r) 'mparen 'mparen))
  487.             (if nc
  488.             (tex x (list "^{\\langle ")(cons "\\rangle}" r) 'mparen 'mparen)
  489.             (if (and (numberp x) (< x 10))
  490.                 (tex x (list "^")(cons "" r) 'mparen 'mparen)
  491.                 (tex x (list "^{")(cons "}" r) 'mparen 'mparen))
  492.             )))))
  493.       (append l r)))
  494.  
  495. (defprop mncexpt tex-mexpt tex)
  496.  
  497. (defprop mncexpt 135. tex-lbp)
  498. (defprop mncexpt 134. tex-rbp)
  499.  
  500. (defprop mnctimes tex-nary tex)
  501. (defprop mnctimes "\\cdot " texsym)
  502. (defprop mnctimes 110. tex-lbp)
  503. (defprop mnctimes 109. tex-rbp)
  504.  
  505. (defprop mtimes tex-nary tex)
  506. (defprop mtimes "\\," texsym)
  507. (defprop mtimes 120. tex-lbp)
  508. (defprop mtimes 120. tex-rbp)
  509.  
  510. (defprop %sqrt tex-sqrt tex)
  511.  
  512. (defun tex-sqrt(x l r)
  513.   ;; format as \\sqrt { } assuming implicit parens for sqr grouping
  514.   (tex (cadr x) (append l  '("\\sqrt{")) (append '("}") r) 'mparen 'mparen))
  515.  
  516. ;; macsyma doesn't know about cube (or nth) roots,
  517. ;; but if it did, this is what it would look like.
  518. (defprop $cubrt tex-cubrt tex)
  519.  
  520. (defun tex-cubrt (x l r)
  521.   (tex (cadr x) (append l  '("\\root 3 \\of{")) (append '("}") r) 'mparen 'mparen))
  522.  
  523. (defprop mquotient tex-mquotient tex)
  524. (defprop mquotient ("\\over") texsym)
  525. (defprop mquotient 122. tex-lbp) ;;dunno about this
  526. (defprop mquotient 123. tex-rbp)
  527.  
  528. (defun tex-mquotient (x l r)
  529.   (if (or (null (cddr x)) (cdddr x)) (wna-err (caar x)))
  530.   (setq l (tex (cadr x) (append l '("{{")) nil 'mparen 'mparen)
  531.     ;the divide bar groups things
  532.     r (tex (caddr x) (list "}\\over{") (append '("}}")r) 'mparen 'mparen))
  533.   (append l r))
  534.  
  535. (defprop $matrix tex-matrix tex)
  536.  
  537. (defun tex-matrix(x l r) ;;matrix looks like ((mmatrix)((mlist) a b) ...)
  538.   (append l `("\\pmatrix{")
  539.      (mapcan #'(lambda(y)
  540.               (tex-list (cdr y) nil (list "\\cr ") "&"))
  541.          (cdr x))
  542.      '("}") r))
  543.  
  544. ;; macsyma sum or prod is over integer range, not  low <= index <= high
  545. ;; TeX is lots more flexible .. but
  546.  
  547. (defprop %sum tex-sum tex)
  548. (defprop %lsum tex-lsum tex)
  549. (defprop %product tex-sum tex)
  550.  
  551. ;; easily extended to union, intersect, otherops
  552.  
  553. (defun tex-lsum(x l r)
  554.   (let ((op (cond ((eq (caar x) '%lsum) "\\sum_{")
  555.           ;; extend here
  556.           ))
  557.     ;; gotta be one of those above 
  558.     (s1 (tex (cadr x) nil nil 'mparen rop));; summand
  559.     (index ;; "index = lowerlimit"
  560.            (tex `((min simp) , (caddr x), (cadddr x))  nil nil 'mparen 'mparen)))
  561.        (append l `( ,op ,@index "}}{" ,@s1 "}") r)))
  562.  
  563. (defun tex-sum(x l r)
  564.   (let ((op (cond ((eq (caar x) '%sum) "\\sum_{")
  565.           ((eq (caar x) '%product) "\\prod_{")
  566.           ;; extend here
  567.           ))
  568.     ;; gotta be one of those above
  569.     (s1 (tex (cadr x) nil nil 'mparen rop));; summand
  570.     (index ;; "index = lowerlimit"
  571.            (tex `((mequal simp) ,(caddr x),(cadddr x)) nil nil 'mparen 'mparen))
  572.     (toplim (tex (car(cddddr x)) nil nil 'mparen 'mparen)))
  573.        (append l `( ,op ,@index "}^{" ,@toplim "}{" ,@s1 "}") r)))
  574.  
  575. (defprop %integrate tex-int tex)
  576. (defun tex-int (x l r)
  577.   (let ((s1 (tex (cadr x) nil nil 'mparen 'mparen));;integrand delims / & d
  578.     (var (tex (caddr x) nil nil 'mparen rop))) ;; variable
  579.        (cond((= (length x) 3)
  580.          (append l `("\\int {" ,@s1 "}{\\>d" ,@var "}") r))
  581.         (t ;; presumably length 5
  582.            (let ((low (tex (nth 3 x) nil nil 'mparen 'mparen))
  583.              ;; 1st item is 0
  584.              (hi (tex (nth 4 x) nil nil 'mparen 'mparen)))
  585.             (append l `("\\int_{" ,@low "}^{" ,@hi "}{" ,@s1 "\\>d" ,@var "}") r))))))
  586.  
  587. (defprop %limit tex-limit tex)
  588.  
  589. (defun tex-limit(x l r) ;; ignoring direction, last optional arg to limit
  590.   (let ((s1 (tex (cadr x) nil nil 'mparen rop));; limitfunction
  591.     (subfun ;; the thing underneath "limit"
  592.      (subst "\\rightarrow " '=
  593.         (tex `((mequal simp) ,(caddr x),(cadddr x))
  594.              nil nil 'mparen 'mparen))))
  595.        (append l `("\\lim_{" ,@subfun "}{" ,@s1 "}") r)))
  596.  
  597. (defprop %at tex-at tex)
  598.  
  599. ;; e.g.  at(diff(f(x)),x=a)
  600. (defun tex-at (x l r)
  601.   (let ((s1 (tex (cadr x) nil nil lop rop))
  602.     (sub (tex (caddr x) nil nil 'mparen 'mparen)))
  603.        (append l '("\\left.") s1  '("\\right|_{") sub '("}") r)))
  604.  
  605. (defprop mbox tex-mbox tex)
  606.  
  607. ;; \boxed is defined in amsmath.sty,
  608. ;; \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
  609.  
  610. (defun tex-mbox (x l r)
  611.   (append l '("\\boxed{") (tex (cadr x) nil nil 'mparen 'mparen) '("}") r))
  612.  
  613. (defprop mlabox tex-mlabox tex)
  614.  
  615. (defun tex-mlabox (x l r)
  616.    (append l '("\\stackrel{") (tex (caddr x) nil nil 'mparen 'mparen)
  617.        '("}{\\boxed{") (tex (cadr x) nil nil 'mparen 'mparen) '("}}") r))
  618.  
  619. ;;binomial coefficients
  620.  
  621. (defprop %binomial tex-choose tex)
  622.  
  623. (defun tex-choose (x l r)
  624.   `(,@l
  625.     "{"
  626.     ,@(tex (cadr x) nil nil 'mparen 'mparen)
  627.     "\\choose "
  628.     ,@(tex (caddr x) nil nil 'mparen 'mparen)
  629.     "}"
  630.     ,@r))
  631.  
  632.  
  633. (defprop rat tex-rat tex)
  634. (defprop rat 120. tex-lbp)
  635. (defprop rat 121. tex-rbp)
  636. (defun tex-rat(x l r) (tex-mquotient x l r))
  637.  
  638. (defprop mplus tex-mplus tex)
  639. (defprop mplus 100. tex-lbp)
  640. (defprop mplus 100. tex-rbp)
  641.  
  642. (defun tex-mplus (x l r)
  643.  ;(declare (fixnum w))
  644.  (cond ((memq 'trunc (car x))(setq r (cons "+\\cdots " r))))
  645.  (cond ((null (cddr x))
  646.     (if (null (cdr x))
  647.         (tex-function x l r t)
  648.         (tex (cadr x) (cons "+" l) r 'mplus rop)))
  649.        (t (setq l (tex (cadr x) l nil lop 'mplus)
  650.         x (cddr x))
  651.       (do ((nl l)  (dissym))
  652.           ((null (cdr x))
  653.            (if (mmminusp (car x)) (setq l (cadar x) dissym (list "-"))
  654.            (setq l (car x) dissym (list "+")))
  655.            (setq r (tex l dissym r 'mplus rop))
  656.            (append nl r))
  657.           (if (mmminusp (car x)) (setq l (cadar x) dissym (list "-"))
  658.           (setq l (car x) dissym (list "+")))
  659.           (setq nl (append nl (tex l dissym nil 'mplus 'mplus))
  660.             x (cdr x))))))
  661.  
  662. (defprop mminus tex-prefix tex)
  663. (defprop mminus ("-") texsym)
  664. (defprop mminus 100. tex-rbp)
  665. (defprop mminus 100. tex-lbp)
  666.  
  667. (defprop min tex-infix tex)
  668. (defprop min ("\\in{") texsym)
  669. (defprop min 80. tex-lbp)
  670. (defprop min 80. tex-rbp)
  671.  
  672. (defprop mequal tex-infix tex)
  673. (defprop mequal (=) texsym)
  674. (defprop mequal 80. tex-lbp)
  675. (defprop mequal 80. tex-rbp)
  676.  
  677. (defprop mnotequal tex-infix tex)
  678. (defprop mnotequal 80. tex-lbp)
  679. (defprop mnotequal 80. tex-rbp)
  680.  
  681. (defprop mgreaterp tex-infix tex)
  682. (defprop mgreaterp (>) texsym)
  683. (defprop mgreaterp 80. tex-lbp)
  684. (defprop mgreaterp 80. tex-rbp)
  685.  
  686. (defprop mgeqp tex-infix tex)
  687. (defprop mgeqp ("\\geq ") texsym)
  688. (defprop mgeqp 80. tex-lbp)
  689. (defprop mgeqp 80. tex-rbp)
  690.  
  691. (defprop mlessp tex-infix tex)
  692. (defprop mlessp (<) texsym)
  693. (defprop mlessp 80. tex-lbp)
  694. (defprop mlessp 80. tex-rbp)
  695.  
  696. (defprop mleqp tex-infix tex)
  697. (defprop mleqp ("\\leq ") texsym)
  698. (defprop mleqp 80. tex-lbp)
  699. (defprop mleqp 80. tex-rbp)
  700.  
  701. (defprop mnot tex-prefix tex)
  702. (defprop mnot ("\\not ") texsym)
  703. (defprop mnot 70. tex-rbp)
  704.  
  705. (defprop mand tex-nary tex)
  706. (defprop mand ("\\and") texsym)
  707. (defprop mand 60. tex-lbp)
  708. (defprop mand 60. tex-rbp)
  709.  
  710. (defprop mor tex-nary tex)
  711. (defprop mor ("\\or") texsym)
  712.  
  713. ;; make sin(x) display as sin x , but sin(x+y) as sin(x+y)
  714. ;; etc
  715.  
  716. (defun tex-setup (x)
  717.   (let((a (car x))
  718.        (b (cadr x)))
  719.       (setf (get a 'tex) 'tex-prefix)
  720.       (setf (get a 'texword) b)  ;This means "sin" will always be roman
  721.       (setf (get a 'texsym) (list b))
  722.       (setf (get a 'tex-rbp) 130)))
  723.  
  724. ;; JM 09/01 expand and re-order to follow table of "log-like" functions,
  725. ;; see table in Lamport, 2nd edition, 1994, p. 44, table 3.9.
  726. ;; I don't know if these are Latex-specific so you may have to define
  727. ;; them if you use plain Tex.
  728.  
  729. (mapc #'tex-setup
  730.   '(
  731.      (%acos "\\arccos ")
  732.      (%asin "\\arcsin ")
  733.      (%atan "\\arctan ")
  734.      ; Latex's arg(x) is ... ?
  735.      (%cos "\\cos ")
  736.      (%cosh "\\cosh ")
  737.      (%cot "\\cot ")
  738.      (%coth "\\coth ")
  739.      (%csc "\\csc ")
  740.      ; Latex's "deg" is ... ?
  741.      (%determinant "\\det ")
  742.      (%dim "\\dim ")
  743.      (%exp "\\exp ")
  744.      (%gcd "\\gcd ")
  745.      ; Latex's "hom" is ... ?
  746.      (%inf "\\inf ") ; many will prefer "\\infty". Hmmm.
  747.      ; Latex's "ker" is ... ?
  748.      ; Latex's "lg" is ... ?
  749.      (%limit "\\lim ")
  750.      ; Latex's "liminf" ... ?
  751.      ; Latex's "limsup" ... ?
  752.      (%ln "\\ln ")
  753.      (%log "\\log ")
  754.      (%max "\\max ")
  755.      (%min "\\min ")
  756.      ; Latex's "Pr" ... ?
  757.      (%sec "\\sec ")
  758.      (%sin "\\sin ")
  759.      (%sinh "\\sinh ")
  760.      ; Latex's "sup" ... ?
  761.      (%tan "\\tan ")
  762.      (%tanh "\\tanh ")
  763.     ;; (%erf "{\\rm erf}") this would tend to set erf(x) as erf x. Unusual
  764.      ;(%laplace "{\\cal L}")
  765.      )) ;; etc
  766.  
  767. (defprop mor tex-nary tex)
  768. (defprop mor 50. tex-lbp)
  769. (defprop mor 50. tex-rbp)
  770.  
  771. (defprop mcond tex-mcond tex)
  772. (defprop mcond 25. tex-lbp)
  773. (defprop mcond 25. tex-rbp)
  774. (defprop %derivative tex-derivative tex)
  775. (defun tex-derivative (x l r)
  776.   (tex (tex-d x '$|d|) l r lop rop ))
  777.  
  778. (defun tex-d(x dsym) ;dsym should be $d or "$\\partial"
  779.   ;; format the macsyma derivative form so it looks
  780.   ;; sort of like a quotient times the deriva-dand.
  781.   (let*
  782.    ((arg (cadr x)) ;; the function being differentiated
  783.     (difflist (cddr x)) ;; list of derivs e.g. (x 1 y 2)
  784.     (ords (odds difflist 0)) ;; e.g. (1 2)
  785.     (vars (odds difflist 1)) ;; e.g. (x y)
  786.     (numer `((mexpt) ,dsym ((mplus) ,@ords))) ; d^n numerator
  787.     (denom (cons '(mtimes)
  788.          (mapcan #'(lambda(b e)
  789.                   `(,dsym ,(simplifya `((mexpt) ,b ,e) nil)))
  790.              vars ords))))
  791.    `((mtimes)
  792.      ((mquotient) ,(simplifya numer nil) ,denom)
  793.      ,arg)))
  794.  
  795. (defun odds(n c)
  796.   ;; if c=1, get the odd terms  (first, third...)
  797.   (cond ((null n) nil)
  798.     ((= c 1)(cons (car n)(odds (cdr n) 0)))
  799.     ((= c 0)(odds (cdr n) 1))))
  800.  
  801. (defun tex-mcond (x l r)
  802.   (append l
  803.     (tex (cadr x) '("\\mathbf{if}\\>")
  804.       '("\\>\\mathbf{then}\\>") 'mparen 'mparen)
  805.     (if (eql (fifth x) '$false)
  806.       (tex (caddr x) nil r 'mcond rop)
  807.       (append (tex (caddr x) nil nil 'mparen 'mparen)
  808.         (tex (fifth x) '("\\>\\mathbf{else}\\>") r 'mcond rop)))))
  809.  
  810. (defprop mdo tex-mdo tex)
  811. (defprop mdo 30. tex-lbp)
  812. (defprop mdo 30. tex-rbp)
  813. (defprop mdoin tex-mdoin tex)
  814. (defprop mdoin 30. tex-rbp)
  815.  
  816. (defun tex-lbp(x)(cond((get x 'tex-lbp))(t(lbp x))))
  817. (defun tex-rbp(x)(cond((get x 'tex-rbp))(t(lbp x))))
  818.  
  819. ;; these aren't quite right
  820.  
  821. (defun tex-mdo (x l r)
  822.   (tex-list (texmdo x) l r "\\>"))
  823.  
  824. (defun tex-mdoin (x l r)
  825.   (tex-list (texmdoin x) l r "\\>"))
  826.  
  827. (defun texmdo (x)
  828.    (nconc (cond ((second x) `("\\mathbf{for}" ,(second x))))
  829.      (cond ((equal 1 (third x)) nil)
  830.            ((third x)  `("\\mathbf{from}" ,(third x))))
  831.      (cond ((equal 1 (fourth x)) nil)
  832.            ((fourth x) `("\\mathbf{step}" ,(fourth x)))
  833.            ((fifth x)  `("\\mathbf{next}" ,(fifth x))))
  834.      (cond ((sixth x)  `("\\mathbf{thru}" ,(sixth x))))
  835.      (cond ((null (seventh x)) nil)
  836.            ((eq 'mnot (caar (seventh x)))
  837.         `("\\mathbf{while}" ,(cadr (seventh x))))
  838.            (t `("\\mathbf{unless}" ,(seventh x))))
  839.      `("\\mathbf{do}" ,(eighth x))))
  840.  
  841. (defun texmdoin (x)
  842.   (nconc `("\\mathbf{for}" ,(second x) "\\mathbf{in}" ,(third x))
  843.      (cond ((sixth x) `("\\mathbf{thru}" ,(sixth x))))
  844.      (cond ((null (seventh x)) nil)
  845.            ((eq 'mnot (caar (seventh x)))
  846.         `("\\mathbf{while}" ,(cadr (seventh x))))
  847.            (t `("\\mathbf{unless}" ,(seventh x))))
  848.      `("\\mathbf{do}" ,(eighth x))))
  849.  
  850. ;; initialize a file so that c-lines will look ok in verbatim mode
  851. ;; run this first before tex(<whatever>, file);
  852. (defun $texinit(file)
  853.   ;; copy header from some generic place
  854.   (funcall 'exec (list
  855.           (concat "cp "
  856.               vaxima-main-dir
  857.               "//ucb//verbwin "  ;extra slashes for maclisp // = /
  858.               (stripdollar file))))
  859.   '$done )
  860. ;; this just prints a \\end on the file;  this is something a TeXnician would
  861. ;; probably have no trouble spotting, and will generally be unnecessary, since
  862. ;; we anticipate almost all use of tex would be involved in inserting this
  863. ;; stuff into larger files that would have their own \\end or equivalent.
  864. (defun $texend(filename)
  865.   (with-open-file (st      (stripdollar filename)
  866.                    :direction :output
  867.                    :if-exists :append
  868.                    :if-does-not-exist :create)
  869.   (format st "\\end~%")
  870.   '$done))
  871.  
  872. ;; Undone and trickier:
  873. ;; handle reserved symbols stuff, just in case someone
  874. ;; has a macsyma variable named (yuck!!) \over  or has a name with
  875. ;; {} in it.
  876. ;; Maybe do some special hacking for standard notations for
  877. ;; hypergeometric fns, alternative summation notations  0<=n<=inf, etc.
  878.  
  879. ;;Undone and really pretty hard: line breaking
  880.  
  881. ;;  The texput function was written by Barton Willis.
  882.  
  883. (defun $texput (e s &optional tx)
  884.  
  885.   (cond ((mstringp e)
  886.      (setq e (define-symbol (string-left-trim '(#\&) e)))))
  887.  
  888.   (cond (($listp s)
  889.      (setq s (margs s)))
  890.     (t
  891.      (setq s (list s))))
  892.   
  893.   (setq s (mapcar #'stripdollar s))
  894.  
  895.   (cond ((null tx)
  896.      (putprop e (nth 0 s) 'texword))
  897.     
  898.     ((eq tx '$matchfix)
  899.      (putprop e 'tex-matchfix 'tex)
  900.      (cond ((< (length s) 2)
  901.         (merror "Improper 2nd argument to TEXPUT for matchfix operator."))
  902.            ((eq (length s) 2)
  903.         (putprop e (list (list (nth 0 s)) (nth 1 s)) 'texsym))
  904.            (t
  905.         (putprop e (list (list (nth 0 s)) (nth 1 s) (nth 2 s)) 'texsym))))
  906.  
  907.           ; The left and right binding powers may be wrong.
  908.  
  909.     ((eq tx '$prefix)
  910.      (putprop e 'tex-prefix 'tex)
  911.      (putprop e s 'texsym)
  912.      (putprop e 200 'tex-lbp)
  913.      (putprop e 180 'tex-rbp))
  914.         
  915.     ((eq tx '$infix)
  916.      (putprop e 'tex-infix 'tex)
  917.      (putprop e  s 'texsym)
  918.      (putprop e 200 'tex-lbp)
  919.      (putprop e 180 'tex-rbp))
  920.  
  921.     ((eq tx '$postfix)
  922.      (putprop e 'tex-postfix 'tex)
  923.      (putprop e  s 'texsym)
  924.      (putprop e 160 'tex-lbp))))
  925.