12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385 |
- #| -*-Scheme-*-
- Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
- Institute of Technology
- This file is part of MIT/GNU Scheme.
- MIT/GNU Scheme is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at
- your option) any later version.
- MIT/GNU Scheme is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with MIT/GNU Scheme; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
- USA.
- |#
- #!fold-case
- ;;;; DISPLAY-EXPRESSION
- ;;; This is a package of expression display programs for Scmutils.
- ;;; This printer is a modified version of code developed by Aubrey
- ;;; Jaffer for the JACAL symbolic mathematics system. It also uses
- ;;; ideas from a printer developed by Kleanthes Koniaris.
- ;;; SHOW-EXPRESSION uses Tex to put up a window with the displayed
- ;;; expression. It also pretty-prints the expression in the Scheme
- ;;; buffer. It also prints the tex string used togenerate the tex output.
- ;;; The window is displayed using xdvi. Type Q in the window to get rid
- ;;; of it. If you quit in other ways (e.g., quitting from Scheme) this
- ;;; may leave garbage temp files in your directory. The garbage files are
- ;;; named temp-display<n>.
- ;;; EXPRESSION->TEX-STRING returns the string that is input to tex
- ;;; 2D-SHOW-EXPRESSION is a simple 2D ASCII character printer for
- ;;; mathematical expressions.
- ;;; Example:
- ;;; (define test
- ;;; '(/
- ;;; (+ alpha (/ ((derivative f) b) (+ alpha beta)))
- ;;; (+ (/ (+ x y) 2) (expt (/ (+ a c (/ 2 x)) (* d e)) (+ f (/ g h))))))
- ;;; (display (expression->tex-string test))
- ;;; $${{\alpha + {{Df\left( b \right)}\over {\alpha + \beta}}}
- ;;; \over {{{x + y}\over {2}} + \left( {{a + c + {{2}\over {x}}}\over {d e}} \right)
- ;;; ^{f + {{g}\over {h}}}}}$$
- ;;; (2d-show-expression test)
- ;;; Df(b)
- ;;; alpha + ------------
- ;;; alpha + beta
- ;;; ----------------------------
- ;;; g
- ;;; f + -
- ;;; / 2 \ h
- ;;; | a + c + - |
- ;;; x + y | x |
- ;;; ----- + | --------- |
- ;;; 2 \ d e /
- ;;; Unlike Jaffer's code, this version does not handle line breaks. We
- ;;; can extend it some day.
- #|
- ;;; To make this stand-alone must add:
- (define derivative-symbol 'D)
- (define (up-maker? expr) (and (pair? expr) (eq? (car expr) 'up)))
- (define (vector-maker? expr) (and (pair? expr) (eq? (car expr) 'vector)))
- (define (down-maker? expr) (and (pair? expr) (eq? (car expr) 'down)))
- (define (matrix-by-rows-maker? expr)
- (and (pair? expr) (eq? (car expr) 'matrix-by-rows)))
- |#
- (declare (usual-integrations))
- ;;; exported functions
- (define enable-tex-display #t)
- ;;; FBE: we may have to move this to the end of the file.
- ;; (module exdisplay-module (internal-show-expression
- ;; 2d-show-expression
- ;; expression->tex-string
- ;; display-tex-string
- ;;
- ;; last-tex-string-generated)
- ;;(define internal-show-expression)
- ;;(define 2d-show-expression)
- ;;(define expression->tex-string)
- ;;(define display-tex-string)
- ;;; FBE: make a parameter
- (define last-tex-string-generated (make-parameter (void)))
- (define display-in-screen-window
- (let ((count 0))
- (lambda (tex-string)
- (let* ((dirname (->namestring (user-homedir-pathname)))
- (file-name (string-append dirname
- "temp-display"
- (number->string count)))
- (complete-tex-input (string-append
- ;;" \\magnification=\\magstep2\n"
- ;;"\\hsize=48pc \\hoffset=-4pc "
- "\\voffset=-6pc "
- "\\hsize=48pc " " \\hoffset=-6pc "
- boxit-string "\n"
- tex-string
- "\\vfil\\bye")))
- (with-output-to-file
- (string-append file-name ".tex")
- (lambda () (display complete-tex-input)))
- #|
- (working-unix/system (string-append "cd " dirname ";"
- " tex " file-name
- " > //dev//null 2>&1 "))
- (working-unix/system
- (string-append "xdvi " file-name ".dvi "
- "-s 4 "
- "-yoffset 3.5 "
- "-geometry 900x400+1+1; "
- "//bin//rm " file-name ".*"
- ))
- |#
- (run-shell-command
- (string-append "cd " dirname ";"
- " tex " file-name
- " > /dev/null 2>&1 ")
- 'output #f
- 'shell-file-name "/bin/sh")
- (run-shell-command
- (string-append "xdvi " file-name ".dvi "
- "-s 4 "
- "-yoffset 3.5 "
- "-geometry 900x400+1+1"
- " > /dev/null 2>&1; "
- "/bin/rm " file-name ".*"
- )
- 'output #f
- 'shell-file-name "/bin/sh")
- (set! count (+ count 1))
- ))))
- (define boxit-string
- "\\def\\boxit#1{\\vbox{\\hrule\\hbox{\\vrule\\kern5pt
- \\vbox{\\kern5pt#1\\kern5pt}\\kern3pt\\vrule}\\hrule}}\n")
- ;;; A couple of utility procedures:
- #|
- ;;some magic from Jinx
- (define (working-unix/system string)
- (let ((old #f))
- (dynamic-wind
- (lambda ()
- (set! old (thread-timer-interval))
- (set-thread-timer-interval! #f))
- (lambda ()
- (unix/system string))
- (lambda ()
- (set-thread-timer-interval! old)))))
- |#
- (define (2d-display-box box)
- (newline)
- (newline)
- (for-each (lambda (line)
- (for-each display (line-elements line))
- (newline))
- (box-lines box))
- (newline))
- ;;; The program works by gluing together boxes, which are lists of
- ;;; lines, all of the same width (the box-width). A box also has a
- ;;; vertical offset (box-voffset), which is used to align boxes when
- ;;; gluing them together horizontally--the vertical offset represents
- ;;; the height of the top line of the box with respect to a designated
- ;;; "zero" line. There is also a binding power (box-binding-power)
- ;;; that is used in unparsing expressions from infix to prefix. The
- ;;; binding power represents how how tightly the box is "held together". If
- ;;; the binding power is less than the required binding power, the box
- ;;; will be enclosed in parentheses.
- ;;; A character string is considered to be a special kind of box with
- ;;; voffset 0 and binding power the maximum binding power.
- ;;; Data structure definitions for boxes
- (define (make-box voffset width binding-power lines)
- (append (list 'box voffset width binding-power)
- lines))
- (define (explicit-box? elt)
- (and (pair? elt)
- (eq? (car elt) 'BOX)))
- (define (box-voffset box)
- (if (explicit-box? box)
- (list-ref box 1)
- 0))
- (define (box-width box)
- (if (explicit-box? box)
- (list-ref box 2)
- (string-length box)))
- (define (box-binding-power box)
- (if (explicit-box? box)
- (list-ref box 3)
- max-bp))
- (define (box-lines box)
- (if (explicit-box? box)
- (list-tail box 4)
- (list (make-line (list box)))))
- (define (box-nlines box)
- (length (box-lines box)))
- ;;;make a box just like the given one, but with the designated binding
- ;;;power
- (define (make-box-with-bp bp box)
- (make-box (box-voffset box)
- (box-width box)
- bp
- (box-lines box)))
- (define (make-empty-box width height)
- (let ((lines (make-list height (make-blank-line width))))
- (make-box 0 ;v-offset arbitrary
- width
- max-bp ;binding power arbitrary
- lines)))
- ;;; A LINE is a list of strings (the line-elements of the line)
- (define (make-line elements)
- (cons 'line elements))
- (define (line-elements line)
- (cdr line))
- (define (make-blank-line width)
- (make-line (make-blank-line-elts width)))
- (define (make-blank-line-elts width)
- (if (= width 0)
- '()
- (list (make-string width #\SPACE))))
- ;;;; Operations for combining boxes
- ;;;Join boxes horizontally, aligned according to the vertical offsets.
- ;;;Resulting box will have the binding power of the first box and a
- ;;;v-offset equal to the max of the v-offsets
- (define (glue-horiz boxes)
- (if (null? (cdr boxes))
- (car boxes)
- (join2-right (car boxes) (glue-horiz (cdr boxes)))))
- (define (join2-right box1 box2)
- (let ((v1 (box-voffset box1))
- (v2 (box-voffset box2))
- (blank1 (make-blank-line (box-width box1)))
- (blank2 (make-blank-line (box-width box2))))
- (make-box (max v1 v2)
- (+ (box-width box1) (box-width box2))
- (box-binding-power box1)
- (cond ((> v1 v2)
- ;;must pad box2 on top to start
- (join-lines-horiz
- (box-lines box1)
- (append (make-list (- v1 v2) blank2)
- (box-lines box2))
- blank1
- blank2))
- ((> v2 v1)
- ;;must pad box1 on top
- (join-lines-horiz
- (append (make-list (- v2 v1) blank1)
- (box-lines box1))
- (box-lines box2)
- blank1
- blank2))
- (else (join-lines-horiz (box-lines box1)
- (box-lines box2)
- blank1
- blank2))))))
- (define (join-lines-horiz lines1 lines2 blank1 blank2)
- (cond ((null? lines1)
- (map (lambda (line2) (make-line (append (line-elements blank1)
- (line-elements line2))))
- lines2))
- ((null? lines2)
- (map (lambda (line1) (make-line (append (line-elements line1)
- (line-elements blank2))))
- lines1))
- (else (cons (make-line (append (line-elements (car lines1))
- (line-elements (car lines2))))
- (join-lines-horiz (cdr lines1) (cdr lines2) blank1 blank2)))))
- ;;; Glue boxes vertically. The boxes will all be extended to the
- ;;; width of the maximum width box, and centered within that width.
- ;;; The voffset will be the voffset of the first box. (I.e., the
- ;;; first box will stay at the same level, and the other boxes will be
- ;;; appended below it.) The binding power will be the binding power
- ;;; of the first box.
- (define (glue-vert boxes)
- (if (null? (cdr boxes))
- (car boxes)
- (glue-below (car boxes) (glue-vert (cdr boxes)))))
- (define (glue-below box1 box2)
- (let* ((new-width (max (box-width box1) (box-width box2)))
- (nbox1 (pad-box-centered-to-width new-width box1))
- (nbox2 (pad-box-centered-to-width new-width box2)))
- (make-box
- (box-voffset box1)
- new-width
- (box-binding-power box1)
- (append (box-lines nbox1) (box-lines nbox2)))))
-
- ;;; Glue-above is similar to glue-below below, except that the
- ;;; v-offset of the top line in box2 remains
- ;;; what it was, and box1 is glued in above it.
- (define (glue-above box1 box2)
- (let* ((new-width (max (box-width box1) (box-width box2)))
- (nbox1 (pad-box-centered-to-width new-width box1))
- (nbox2 (pad-box-centered-to-width new-width box2)))
- (make-box
- (+ (box-voffset box2) (length (box-lines box1)))
- new-width
- (box-binding-power box1)
- (append (box-lines nbox1) (box-lines nbox2)))))
- ;;;pad the box on both the left and the right so it is centered in a
- ;;;box of the given width
- (define (pad-box-centered-to-width width box)
- (let* ((extra (- width (box-width box)))
- (extra-left (floor->exact (/ extra 2)))
- (extra-right (- extra extra-left))
- (pad-left (make-blank-line-elts extra-left))
- (pad-right (make-blank-line-elts extra-right)))
- (make-box (box-voffset box)
- width
- (box-binding-power box)
- (map (lambda (line)
- (make-line
- (append pad-left
- (line-elements line)
- pad-right)))
- (box-lines box)))))
- ;;; pad the box on both the top and the bottom so it will be centeted
- ;;; in a box of the given height. "Centered" here means that the box
- ;;; will appear in the center of the expanded box, regardles of where
- ;;; the zero line was.
- (define (pad-box-centered-to-height height box)
- (let* ((extra (- height (box-nlines box)))
- (extra-top (floor->exact (/ extra 2)))
- (extra-bottom (- extra extra-top))
- (width (box-width box)))
- (let ((padded-box
- (glue-below (glue-above (make-empty-box width extra-top)
- box)
- (make-empty-box width extra-bottom))))
- (shift-top-to (- (box-nlines padded-box) 1)
- padded-box))))
- ;;; Offsetting boxes vertically
- ;;; Make the voffset of the bottom of the box be at n
- (define (shift-bottom-to n box)
- (shift-top-to (+ n -1 (box-nlines box)) box))
- ;;; Shift the box so that its zero line is now at n
- (define (shift-zero-to n box)
- (shift-top-to (+ n (box-voffset box)) box))
- ;;; Shift the box so that the top of the box is now at n
- (define (shift-top-to n box)
- (make-box n
- (box-width box)
- (box-binding-power box)
- (box-lines box)))
- ;;;Create a box from a list of strings, on string per line. The
- ;;;strings are padded on the right to be all the same width.
- (define (strings->vbox voffset strings)
- (let* ((width (apply max (map string-length strings)))
- (padded-strings
- (map (lambda (string)
- (string-append (make-string
- (- width (string-length string))
- #\SPACE)
- string))
- strings))
- (lines (map (lambda (string)
- (make-line (list string)))
- padded-strings)))
- (make-box voffset
- width
- max-bp
- lines)))
- ;;; List utility:
- ;;;Interpolate element between all items in the list
- (define (interpolate element list)
- (cond ((null? list) '())
- ((null? (cdr list)) list)
- (else (cons (car list)
- (cons element
- (interpolate element (cdr list)))))))
- ;;; Binding powers of elements, and required binding powers. An element
- ;;; on the left will be parenthesized if it is used in a context on the
- ;;; right that appears above it in the table.
- ;;;
- ;;; max-bp 200
- ;;; one-char symbol 200
- ;;; parenthesized thing 200
- ;;;
- ;;; n-char symbol 190 product set off with dots in Tex
- ;;;
- ;;; subscripted 140
- ;;; superscripted 140
- ;;; derivative 140
- ;;; 2nd derviv 140
- ;;; partial deriv 140
- ;;; nth deriv 140
- ;;; base of exponentiation 140
- ;;; item to be subscripted 140
- ;;; subscript 140
- ;;; item to be differentiated 140
- ;;; expt 130
- ;;; application 130
- ;;; operator of application 130
- ;;; product 120
- ;;; quotient 120
- ;;; term in product 120
- ;;; sum/diff 100
- ;;; exponent of exponentiation 100
- ;;; term in sum 100
- ;;; negation 99
- (define max-bp 200)
- ;;; Enclose the box in parentheses if its binding power is less than
- ;;; the required bp. Uptable is the unparsing table (needed in order
- ;;; to know how to parenthesize).
- (define (insure-bp uptable required box)
- (if (< (box-binding-power box) required)
- ((cadr (assq 'parenthesize uptable)) uptable box)
- box))
- ;;; Create a new box by enclosing the given box in vertically
- ;;; expanding parentheses. The binding power of the new box is the
- ;;; maximum binding power. The voffset will be the voffset of the
- ;;; original box.
- (define (2d:parenthesize uptable box)
- (let ((n (box-nlines box)))
- (cond ((= n 0) "()")
- ((<= n 2)
- (make-box-with-bp max-bp
- (glue-horiz (list "(" box ")"))))
- (else
- (let ((left-paren
- (strings->vbox
- (box-voffset box)
- (append '(" / ")
- (make-list (- n 2) "| ")
- '(" \\ "))))
- (right-paren
- (strings->vbox
- (box-voffset box)
- (append '(" \\ ")
- (make-list (- n 2) " |")
- '(" / ")))))
- (make-box-with-bp max-bp (glue-horiz (list left-paren box right-paren))))))))
- (define (tex:parenthesize uptable box)
- (make-box-with-bp max-bp (glue-horiz (list "\\left( " box " \\right)"))))
- ;;;; Unparsing handlers. Each handler takes the expression and the
- ;;;; unparsing table.
- ;;; Some of the handlers here work both for tex-display and for
- ;;; 2d-display, others are specific to one or the other.
- (define (unparse-default uptable args)
- (make-box-with-bp 130
- (glue-horiz
- (list (insure-bp uptable 130 (car args))
- ((cadr (assq 'parenthesize uptable))
- uptable
- (if (null? (cdr args))
- ""
- (glue-horiz (interpolate ", " (cdr args)))))))))
- (define (unparse-sum uptable args)
- (let ((args (map (lambda (a) (insure-bp uptable 100 a)) args)))
- (make-box-with-bp 100 (glue-horiz (interpolate " + " args)))))
- (define (unparse-difference uptable args)
- (let ((args (map (lambda (a) (insure-bp uptable 100 a)) args)))
- (make-box-with-bp 100 (glue-horiz (interpolate " - " args)))))
- (define (unparse-negation uptable args)
- (make-box-with-bp 99
- (glue-horiz
- (list "- " (insure-bp uptable 101 (car args))))))
- (define (unparse-signed-sum uptable signs terms)
- (let ((args (map (lambda (a) (insure-bp uptable 100 a)) terms)))
- (make-box-with-bp 100 (glue-horiz (interpolate-signs signs args)))))
- ;;number of signs should equal number of args
- (define (interpolate-signs signs args)
- (define (interp signs args)
- (cond ((null? args) '())
- ((null? (cdr args)) args)
- (else (cons (car args)
- (cons (if (eq? (car signs) '-) " - " " + ")
- (interp (cdr signs) (cdr args)))))))
- (let ((after-first-sign (interp (cdr signs) args)))
- (if (eq? (car signs) '-)
- (cons " - " after-first-sign)
- after-first-sign)))
- (define (2d:unparse-product uptable args)
- (let ((args (map (lambda (a) (insure-bp uptable 120 a)) args)))
- (make-box-with-bp 120 (glue-horiz (interpolate " " args)))))
- ;;; For a product, if an element is a >1-char symbol (binding power
- ;;; 190), we set it off from the other factors by dots
- (define (tex:unparse-product uptable args)
- (let ((args (map (lambda (a) (insure-bp uptable 120 a)) args)))
- (make-box-with-bp 120 (glue-horiz (interpolate-for-tex-product args)))))
- (define (interpolate-for-tex-product list)
- (define (separator a1 a2)
- (if (or (= (box-binding-power a1) 190)
- (= (box-binding-power a2) 190))
- " \\cdot "
- " "))
- (cond ((null? list) '())
- ((null? (cdr list)) list)
- (else (cons (car list)
- (cons (separator (car list) (cadr list))
- (interpolate-for-tex-product (cdr list)))))))
- (define (2d:unparse-quotient uptable args)
- (let* ((box1 (car args))
- (box2 (cadr args))
- (width (max (box-width box1) (box-width box2)))
- (rule-box (make-string width #\-)))
- (make-box-with-bp 120
- (glue-below
- (glue-above box1 rule-box)
- box2))))
- (define (tex:unparse-quotient uptable args)
- (let ((box1 (car args))
- (box2 (cadr args)))
- (make-box-with-bp 120
- (glue-horiz
- (list "{" "{" box1 "}"
- "\\over "
- "{" box2 "}" "}")))))
- (define (2d:unparse-expt uptable args)
- ;;if base is not shorter than expt, raise expt
- ;;so that its zero is one above the top of the base.
- ;;otherwise raise so that bottom of expt is one above the top of the
- ;;base
- (let* ((base (insure-bp uptable 140 (car args)))
- (expt (insure-bp uptable 100 (cadr args)))
- (shift-expt
- (if (>= (box-nlines base) (box-nlines expt))
- (shift-zero-to (+ (box-voffset base) 1)
- expt)
- (shift-bottom-to (+ (box-voffset base) 1)
- expt))))
- (make-box-with-bp
- 130
- (glue-horiz (list base shift-expt)))))
- (define (tex:unparse-expt uptable args)
- (let ((base (insure-bp uptable 140 (car args)))
- (expt (insure-bp uptable 100 (cadr args))))
- (make-box-with-bp
- 130
- (glue-horiz (list "{" base "}^{" expt "}")))))
- (define (2d:unparse-superscript uptable args)
- (let ((top (insure-bp uptable 140 (car args)))
- (script (insure-bp uptable 140 (cadr args))))
- (make-box-with-bp
- 140
- (glue-horiz
- (list top
- (shift-top-to (+ (box-voffset top) (box-nlines top))
- script))))))
- (define (tex:unparse-superscript uptable args)
- (let ((top (insure-bp uptable 140 (car args)))
- (scripts
- (map (lambda (ss)
- (insure-bp uptable 140 ss))
- (cdr args))))
- (make-box-with-bp
- 140
- (glue-horiz
- (append (list "{")
- (list top)
- (list "}^{")
- (let lp ((scripts scripts))
- (if (null? (cdr scripts))
- (list (car scripts))
- (append (list (car scripts))
- (list ", ")
- (lp (cdr scripts)))))
- (list "}"))))))
- (define (2d:unparse-subscript uptable args)
- (let ((top (insure-bp uptable 140 (car args)))
- (script (insure-bp uptable 140 (cadr args))))
- (make-box-with-bp
- 140
- (glue-horiz
- (list top
- (shift-top-to (- (box-voffset top) (box-nlines top))
- script))))))
- (define (tex:unparse-subscript uptable args)
- (let ((top (insure-bp uptable 140 (car args)))
- (scripts
- (map (lambda (ss)
- (insure-bp uptable 140 ss))
- (cdr args))))
- (make-box-with-bp
- 140
- (glue-horiz
- (append (list "{")
- (list top)
- (list "}_{")
- (let lp ((scripts scripts))
- (if (null? (cdr scripts))
- (list (car scripts))
- (append (list (car scripts))
- (list ", ")
- (lp (cdr scripts)))))
- (list "}"))))))
- #|
- (define (tex:unparse-subscript uptable args)
- (let ((top (insure-bp uptable 140 (car args)))
- (script (insure-bp uptable 140 (cadr args))))
- (make-box-with-bp
- 140
- (glue-horiz (list top "_{" script "}")))))
- |#
- (define (unparse-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "D" (insure-bp uptable 140 (car args))))))
- #|
- (define (unparse-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list (insure-bp uptable 140 (car args)) "'"))))
- |#
- (define (tex:unparse-sqrt uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "\\sqrt{" (insure-bp uptable 90 (car args)) "}"))))
- (define (tex:unparse-dotted uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "\\dot{" (insure-bp uptable 140 (car args)) "}"))))
- (define (2d:unparse-dotted uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "(dot " (insure-bp uptable 140 (car args)) ")"))))
- (define (tex:unparse-dotdotted uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "\\ddot{" (insure-bp uptable 140 (car args)) "}"))))
- (define (2d:unparse-dotdotted uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "(ddot " (insure-bp uptable 140 (car args)) ")"))))
- (define (tex:unparse-primed uptable args)
- (let ((top (insure-bp uptable 140 (car args))))
- (make-box-with-bp 140
- (glue-horiz (list "{" top "}^\\prime")))))
- (define (2d:unparse-primed uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "(prime " (insure-bp uptable 140 (car args)) ")"))))
- (define (tex:unparse-primeprimed uptable args)
- (let ((top (insure-bp uptable 140 (car args))))
- (make-box-with-bp 140
- (glue-horiz (list "{" top "}^{\\prime\\prime}")))))
- (define (2d:unparse-primeprimed uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list "(primeprime " (insure-bp uptable 140 (car args)) ")"))))
- #|
- (define (unparse-second-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list (insure-bp uptable 140 (car args)) "''"))))
- |#
- (define (2d:unparse-second-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list (2d:unparse-expt uptable (list "D" "2"))
- (insure-bp uptable 140 (car args))))))
- (define (tex:unparse-second-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list (tex:unparse-expt uptable (list "D" "2"))
- (insure-bp uptable 140 (car args))))))
- ;;; This does not work with multiple subscripts
- (define (2d:unparse-partial-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz (list (2d:unparse-subscript uptable (list "D" (cadr args)))
- (insure-bp uptable 140 (car args))))))
- (define (tex:unparse-partial-derivative uptable args)
- (make-box-with-bp
- 140
- (glue-horiz
- (list (tex:unparse-subscript uptable (cons "\\partial" (cdr args)))
- (insure-bp uptable 140 (car args))))))
- (define (2d:unparse-nth-derivative uptable args)
- (let ((op (2d:unparse-expt uptable (list "D" (cadr args)))))
- (make-box-with-bp
- 140
- (glue-horiz (list op (insure-bp uptable 140 (car args)))))))
- (define (tex:unparse-nth-derivative uptable args)
- (let ((op (tex:unparse-expt uptable (list "D" (cadr args)))))
- (make-box-with-bp
- 140
- (glue-horiz (list op (insure-bp uptable 140 (car args)))))))
- ;;; vector is printed as column matrix
- (define (2d:unparse-vector uptable args)
- (2d:unparse-matrix uptable
- (map list args)))
- ;;; a vector will be displayed as a 1-column matrix
- (define (tex:unparse-vector uptable args)
- ;;args here is the list of vector elements
- (tex:unparse-matrix uptable
- (map list args)))
- ;;; matrix list is a list of rows where each row is a list
- (define (2d:unparse-matrix uptable matrix-list)
- ;;first pad all elements in each column to the max width in the
- ;;column
- (define (transpose matrix-lists)
- (apply map (cons list matrix-lists)))
- (let* ((matrix-with-widended-columns
- (transpose
- (map (lambda (column)
- (let ((width (apply max (map box-width column))))
- (map (lambda (element)
- (pad-box-centered-to-width width element))
- column)))
- (transpose matrix-list))))
- ;;pad all elts in each row to the max height
- (matrix-with-lengthened-rows
- (map (lambda (row)
- (let ((height (apply max (map box-nlines row))))
- (map (lambda (element)
- (pad-box-centered-to-height height element))
- row)))
- matrix-with-widended-columns))
- ;;glue elts in each row together, separated by two spaces
- (row-boxes
- (map (lambda (row) (glue-horiz (interpolate " " row)))
- matrix-with-lengthened-rows))
- ;;glue the rows together, with separated by blank lines
- (separated-row-boxes
- (interpolate (make-empty-box (box-width (car row-boxes)) 1)
- row-boxes))
- (all-elts
- (glue-vert separated-row-boxes))
- ;;surround matrix by brackets
- (with-brackets
- (glue-horiz
- (list (strings->vbox (box-voffset all-elts)
- (make-list (box-nlines all-elts) "["))
- all-elts
- (strings->vbox (box-voffset all-elts)
- (make-list (box-nlines all-elts) "]"))))))
- ;;center matrix vertically
- (shift-top-to
- (floor->exact (/ (box-nlines with-brackets) 2))
- with-brackets)))
-
- (define (tex:unparse-matrix uptable matrix-list)
- (let* ((displaystyle-rows
- (map (lambda (row)
- (map (lambda (elt)
- (glue-horiz (list "\\displaystyle{ "
- elt
- "}")))
- row))
- matrix-list))
- (separated-rows
- (map (lambda (row) (glue-horiz (interpolate " & " row)))
- displaystyle-rows))
- (separated-columns
- (glue-horiz (interpolate " \\cr \\cr " separated-rows))))
- #;
- (glue-horiz
- (list "\\left\\{ \\matrix{ "
- separated-columns
- "} \\right\\}"))
- (glue-horiz
- (list "\\left\\lgroup \\matrix{ "
- separated-columns
- "} \\right\\rgroup"))))
-
- (define (tex:unparse-up uptable matrix-list)
- (let* ((displaystyle-rows
- (map (lambda (row)
- (map (lambda (elt)
- (glue-horiz (list "\\displaystyle{ "
- elt
- "}")))
- row))
- matrix-list))
- (separated-rows
- (map (lambda (row) (glue-horiz (interpolate " & " row)))
- displaystyle-rows))
- (separated-columns
- (glue-horiz (interpolate " \\cr \\cr " separated-rows))))
- (glue-horiz
- (list left-up-delimiter separated-columns right-up-delimiter))))
- (define (tex:unparse-down uptable matrix-list)
- (let* ((displaystyle-rows
- (map (lambda (row)
- (map (lambda (elt)
- (glue-horiz (list "\\displaystyle{ "
- elt
- "}")))
- row))
- matrix-list))
- (separated-rows
- (map (lambda (row) (glue-horiz (interpolate " & " row)))
- displaystyle-rows))
- (separated-columns
- (glue-horiz (interpolate " \\cr \\cr " separated-rows))))
- (glue-horiz
- (list left-down-delimiter separated-columns right-down-delimiter))))
- ;;; Unparsing table for 2D displays
- (define 2d:unparse-table
- `((parenthesize ,2d:parenthesize)
- (default ,unparse-default)
- (+ ,unparse-sum)
- ;;need sum (in addition to +) as an internal hook for
- ;;process-sum
- (sum ,unparse-sum)
- (- ,unparse-difference)
- (* ,2d:unparse-product)
- (negation ,unparse-negation)
- (/ ,2d:unparse-quotient)
- (signed-sum ,unparse-signed-sum)
- (expt ,2d:unparse-expt)
- (,derivative-symbol ,unparse-derivative)
- (derivative ,unparse-derivative)
- (second-derivative ,2d:unparse-second-derivative)
- (nth-derivative ,2d:unparse-nth-derivative)
- (partial-derivative ,2d:unparse-partial-derivative)
- (subscript ,2d:unparse-subscript)
- (superscript ,2d:unparse-superscript)
- (vector ,2d:unparse-vector)
- (row ,2d:unparse-matrix)
- (column ,2d:unparse-matrix)
- (down ,2d:unparse-matrix)
- (up ,2d:unparse-matrix)
- (matrix ,2d:unparse-matrix)
- (dotted ,2d:unparse-dotted)
- (dotdotted ,2d:unparse-dotdotted)
- (primed ,2d:unparse-primed)
- (primeprimed ,2d:unparse-primeprimed)
- ))
- (define 2d:symbol-substs
- `((derivative "D")
- ))
- (define tex:unparse-table
- `((parenthesize ,tex:parenthesize)
- (default ,unparse-default)
- (+ ,unparse-sum)
- ;;need sum (in addition to +) as an internal hook for
- ;;process-sum
- (sum ,unparse-sum)
- (- ,unparse-difference)
- (* ,tex:unparse-product)
- (& ,tex:unparse-product)
- (negation ,unparse-negation)
- (/ ,tex:unparse-quotient)
- (signed-sum ,unparse-signed-sum)
- (expt ,tex:unparse-expt)
- (,derivative-symbol ,unparse-derivative)
- (derivative ,unparse-derivative)
- (second-derivative ,tex:unparse-second-derivative)
- (nth-derivative ,tex:unparse-nth-derivative)
- (partial-derivative ,tex:unparse-partial-derivative)
- (subscript ,tex:unparse-subscript)
- (superscript ,tex:unparse-superscript)
- (vector ,tex:unparse-vector)
- (column ,tex:unparse-up)
- (row ,tex:unparse-down)
- (up ,tex:unparse-up)
- (down ,tex:unparse-down)
- (matrix ,tex:unparse-matrix)
- (sqrt ,tex:unparse-sqrt)
- (dotted ,tex:unparse-dotted)
- (dotdotted ,tex:unparse-dotdotted)
- (primed ,tex:unparse-primed)
- (primeprimed ,tex:unparse-primeprimed)
- ))
- (define tex:symbol-substs
- (append `((derivative "D")
- (acos "\\arccos")
- (asin "\\arcsin")
- (atan "\\arctan")
- )
- (map (lambda (string)
- (list (string->symbol string)
- (string-append "\\" string)))
- '(
- "alpha" "beta" "gamma" "delta" "epsilon" "zeta" "eta" "theta"
- "iota" "kappa" "lambda" "mu" "nu" "xi"
- ;; "omicron" does not appear in tex
- "pi" "rho" "tau" "upsilon" "phi" "chi" "psi" "omega"
- "varepsilon" "vartheta" "varpi" "varrho" "varsigma" "varphi"
- ;;"Alpha" "Beta"
- "Gamma" "Delta"
- ;;"Epsilon" "Zeta" "Eta"
- "Theta"
- ;;"Iota" "Kappa"
- "Lambda"
- ;;"Mu" "Nu"
- "Xi"
- ;;"Omicron"
- "Pi"
- ;;"Rho" "Tau"
- "Upsilon" "Phi"
- ;;"Chi"
- "Psi" "Omega"
- "aleph" "hbar" "nabla" "top" "bot" "mho" "Re" "Im"
- "infty" "Box" "diamond" "Diamond" "triangle"
- "sin" "cos" "tan" "cot" "sec" "csc" "log" "exp"
- ))
- (map (lambda (string)
- (list (string->symbol string)
- (string-append "{\\rm\\ " string " }")))
- '("&meter" "&kilogram" "&second"
- "&ere" "&kelvin" "&mole"
- "&candela" "&radian"
- "&newton" "&joule" "&coulomb"
- "&watt" "&volt" "&ohm"
- "&siemens" "&farad" "&weber"
- "&henry" "&hertz" "&tesla"
- "&pascal" "&katal" "&becquerel"
- "&gray" "&sievert" "&inch"
- "£" "&slug" "&foot"
- "&mile" "&dyne" "&calorie"
- "&day" "&year" "&sidereal-year"
- "&AU" "&arcsec" "&pc"
- "&ly" "&esu" "&ev"))))
- ;;; Actual unparsing procedure. Symbol-substs is a table of special symbols
- ;;; to be substituted for. UPtable is an unparsing table.
- (define (unparse exp symbol-substs uptable)
- (let ((exp (unparse-special-convert exp))
- (up (lambda (exp) (unparse exp symbol-substs uptable))))
- (cond ((null? exp) "")
- ((number? exp) (unparse-number exp symbol-substs uptable))
- ((symbol? exp) (unparse-symbol exp symbol-substs uptable))
- ((up-maker? exp)
- ((cadr (assq 'column uptable))
- uptable
- (map list (map up (cdr exp)))))
- ((down-maker? exp)
- ((cadr (assq 'row uptable))
- uptable
- ;; For horizontal format
- ;;(list (map up (cdr exp)))
- ;; For vertical format
- (map list (map up (cdr exp)))))
- ((vector-maker? exp)
- ((cadr (assq 'vector uptable))
- uptable
- (map up (cdr exp))))
- ((matrix-by-rows-maker? exp)
- ((cadr (assq 'matrix uptable))
- uptable
- (map (lambda (row) (cdr (map up row)))
- (cdr exp))))
- ((eq? (car exp) '+)
- (process-sum exp symbol-substs uptable))
- ((symbol? (car exp))
- (let ((proc (assq (car exp) uptable)))
- (if proc
- ((cadr proc) uptable (map up (cdr exp)))
- ((cadr (assq 'default uptable)) uptable (map up exp)))))
- (else
- (let ((proc (assq 'default uptable)))
- ((cadr proc) uptable (map up exp)))))))
-
- (define (unparse-number n symbol-substs uptable)
- (cond ((and (real? n) (< n 0))
- (unparse `(- ,(- n)) symbol-substs uptable))
- ((and (rational? n) (exact? n) (not (= (denominator n) 1)))
- (unparse `(/ ,(numerator n) ,(denominator n))
- symbol-substs
- uptable))
- (else (number->string n))))
- ;;; symbols are treated as follows: some symbols are looked for and
- ;;; substituted specially (e.g., alpha turns into \alpha for tex).
- ;;; Other symbols have implied subscripts, e.g., m_1. Symbols that
- ;;; are more than one character long have a lower binding power than
- ;;; symbols that are one character long, so that the product of foo
- ;;; and x, for example, will be written as foo <dot> x in Tex, or the
- ;;; square of dt will be (dt)^2.
- (define (unparse-symbol symbol symbol-substs uptable)
- (let ((s (assq symbol symbol-substs)))
- (if s
- (cadr s)
- (let ((string (symbol->string symbol)))
- (split-at-underscore-or-caret
- string
- (lambda (before at after)
- (if (not before) ;no underscore or caret in symbol
- (unparse-string string symbol-substs uptable)
- (unparse `(,at ,(string->symbol before) ,(string->symbol after))
- symbol-substs
- uptable))))))))
- (define dotdot-string "dotdot")
- (define dotdot-string-length (string-length dotdot-string))
- (define dot-string "dot")
- (define dot-string-length (string-length dot-string))
- (define primeprime-string "primeprime")
- (define primeprime-string-length (string-length primeprime-string))
- (define prime-string "prime")
- (define prime-string-length (string-length prime-string))
- #|
- (define (unparse-string string symbol-substs uptable)
- (if (= (string-length string) 1)
- string
- (cond ((string-search-forward dotdot-string string)
- => (lambda (n)
- (if (= (+ n dotdot-string-length) ;terminal dotdot
- (string-length string))
- (unparse `(dotdotted
- ,(string->symbol (string-head string n)))
- symbol-substs uptable)
- (make-box-with-bp 190 string))))
- ((string-search-forward dot-string string)
- => (lambda (n)
- (if (= (+ n dot-string-length) ;terminal dot
- (string-length string))
- (unparse `(dotted
- ,(string->symbol (string-head string n)))
- symbol-substs uptable)
- (make-box-with-bp 190 string))))
- ((string-search-forward primeprime-string string)
- => (lambda (n)
- (if (= (+ n primeprime-string-length) ;terminal primeprime
- (string-length string))
- (unparse `(primeprimed
- ,(string->symbol (string-head string n)))
- symbol-substs uptable)
- (make-box-with-bp 190 string))))
- ((string-search-forward prime-string string)
- => (lambda (n)
- (if (= (+ n prime-string-length) ;terminal prime
- (string-length string))
- (unparse `(primed
- ,(string->symbol (string-head string n)))
- symbol-substs uptable)
- (make-box-with-bp 190 string))))
- (else
- (make-box-with-bp 190 string)))))
- |#
- (define (unparse-string string symbol-substs uptable)
- (define (for-terminal special-string special-string-length special-symbol)
- (let ((n (string-search-forward special-string string)))
- (if (and n (= (+ n special-string-length) (string-length string)))
- (unparse `(,special-symbol
- ,(string->symbol (string-head string n)))
- symbol-substs uptable)
- #f)))
- (cond ((= (string-length string) 1) string)
- ((for-terminal dotdot-string dotdot-string-length 'dotdotted))
- ((for-terminal dot-string dot-string-length 'dotted))
- ((for-terminal primeprime-string primeprime-string-length 'primeprimed))
- ((for-terminal prime-string prime-string-length 'primed))
- (else (make-box-with-bp 190 string))))
- #|
- (define (split-at-underscore-or-caret string cont)
- ;;cont = (lambda (before after) ...)
- (let ((index (string-find-next-char string #\_)))
- (if (not index)
- (cont #f #f)
- (cont (string-head string index)
- (string-tail string (+ index 1))))))
- |#
- (define (split-at-underscore-or-caret string cont)
- ;;cont = (lambda (before at after) ...)
- (let ((index (string-find-next-char-in-set string (char-set #\^ #\_))))
- (if (not index)
- (cont #f #f #f)
- (cont (string-head string index)
- (if (char=? (string-ref string index) #\^)
- 'superscript
- 'subscript)
- (string-tail string (+ index 1))))))
- ;;; Some forms have funny rules. For example, ((expt A 2) f) would
- ;;; 2
- ;;; unparse to A (f), but ((expt derivative 2) f) is traditionally
- ;;; 2
- ;;; written without parens, as D f. Partial derivatives are also
- ;;; funny, since we will generally convert them to subscripts. The
- ;;; following procedure catches these special forms. If there were
- ;;; more of these, we would use a pattern matcher here.
- (define (unparse-special-convert exp)
- (cond ((and
- ;;((expt derivative n) f) --> (nth-derivative f n)
- (pair? exp)
- (pair? (car exp))
- (= (length exp) 2)
- (= (length (car exp)) 3)
- (eq? (caar exp) 'expt)
- (or (eq? (cadar exp) 'derivative)
- (eq? (cadar exp) derivative-symbol)))
- (let ((exponent (list-ref (car exp) 2))
- (base (cadr exp)))
- (if (eq? exponent 2)
- `(second-derivative ,base)
- `(nth-derivative ,base ,exponent))))
- ((and
- ;;((partial x) f) --> (partial-derivative f x)
- (pair? exp)
- (pair? (car exp))
- (= (length exp) 2)
- (eq? (caar exp) 'partial))
- `(partial-derivative ,(cadr exp) ,@(cdr (car exp))))
- ((and
- ;;(- x) --> (negation x)
- (pair? exp)
- (eq? (car exp) '-)
- (eq? (length exp) 2))
- `(negation ,(cadr exp)))
- (else exp)))
- ;;; for a sum, find all terms of the form (* -1 .....) and make them
- ;;; appear without the -1 and with a negative sign in the sum
- (define (process-sum exp symbol-substs uptable)
- (let ((terms (cdr exp)))
- (cond ((null? terms)
- (unparse 0 symbol-substs uptable))
- ((null? (cdr terms))
- (unparse (car terms) symbol-substs uptable))
- (else
- (let ((signed-terms
- (map (lambda (term)
- (cond ((and (pair? term) (eq? (car term) '*))
- (let ((first-factor (cadr term)))
- (if (and (real? first-factor) (negative? first-factor))
- (if (and (= first-factor -1) (not (null? (cddr term))))
- (list '- (cons '* (cddr term)))
- (list '- (cons '* (cons (- first-factor) (cddr term)))))
- (list '+ term))))
- ((and (pair? term) (eq? (car term) '/))
- (let ((numer (cadr term)))
- (cond ((and (real? numer) (negative? numer))
- (list '- (cons '/ (cons (- numer) (cddr term)))))
- ((and (pair? numer) (eq? (car numer) '*))
- (let ((first-factor (cadr numer)))
- (if (and (real? first-factor) (negative? first-factor))
- (if (and (= first-factor -1) (not (null? (cddr numer))))
- (list '-
- (cons '/
- (cons (cons '* (cddr numer))
- (cddr term))))
- (list '-
- (cons '/
- (cons (cons '*
- (cons (- first-factor)
- (cddr numer)))
- (cddr term)))))
- (list '+ term))))
- (else
- (list '+ term)))))
- (else
- (list '+ term))))
- terms)))
- (let ((processed-terms
- (map (lambda (exp) (unparse exp symbol-substs uptable))
- (map cadr signed-terms))))
- ((cadr (assq 'signed-sum uptable))
- uptable
- (map car signed-terms)
- processed-terms
- )))))))
- (define internal-show-expression
- (lambda (exp)
- (last-tex-string-generated (expression->tex-string exp))
- (let ((name (graphics-type-name (graphics-type #f))))
- (if (and (eq? name 'X) enable-tex-display)
- (begin (display-in-screen-window (last-tex-string-generated))
- (newline)
- (newline)
- ;; (display tex-string)
- ;; (newline)
- ;; (newline)
- )
- (2d-show-expression exp)))))
- (define 2d-show-expression
- (lambda (exp)
- (2d-display-box
- (unparse exp 2d:symbol-substs 2d:unparse-table))))
- (define expression->tex-string
- (lambda (exp)
- (let* ((one-line-box (unparse exp tex:symbol-substs tex:unparse-table))
- (tex-string
- (with-output-to-string
- (lambda ()
- (for-each display
- (line-elements (car (box-lines one-line-box))))))))
- (string-append "\\boxit{ " "$$" tex-string "$$" "}"))))
- #|
- ;;; Beal's folly.
- (set! expression->tex-string
- (lambda (exp)
- (let* ((one-line-box (unparse exp tex:symbol-substs tex:unparse-table))
- (tex-string
- (with-output-to-string
- (lambda ()
- (for-each display
- (line-elements (car (box-lines one-line-box))))))))
- (string-append "\\boxit{ " "$" tex-string "$" "}"))))
- |#
- (define display-tex-string display-in-screen-window)
- ;;) ;end module
- ;;;(define left-up-delimiter "\\left \\lceil \\matrix{ ")
- ;;;(define right-up-delimiter "} \\right \\rceil")
- ;;;(define left-down-delimiter "\\left \\lfloor \\matrix{ ")
- ;;;(define right-down-delimiter "} \\right \\rfloor")
- (define left-up-delimiter "\\left( \\matrix{ ")
- (define right-up-delimiter "} \\right)")
- (define left-down-delimiter "\\left[ \\matrix{ ")
- (define right-down-delimiter "} \\right]")
- #|
- (define test
- '(/
- (+ alpha (/ ((derivative f) b) (+ alpha beta)))
- (+ (/ (+ x y) 2) (expt (/ (+ a c (/ 2 x)) (* d e)) (+ f (/ g h))))))
- |#
|