fbe-exdisplay.scm 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. #!fold-case
  21. ;;;; DISPLAY-EXPRESSION
  22. ;;; This is a package of expression display programs for Scmutils.
  23. ;;; This printer is a modified version of code developed by Aubrey
  24. ;;; Jaffer for the JACAL symbolic mathematics system. It also uses
  25. ;;; ideas from a printer developed by Kleanthes Koniaris.
  26. ;;; SHOW-EXPRESSION uses Tex to put up a window with the displayed
  27. ;;; expression. It also pretty-prints the expression in the Scheme
  28. ;;; buffer. It also prints the tex string used togenerate the tex output.
  29. ;;; The window is displayed using xdvi. Type Q in the window to get rid
  30. ;;; of it. If you quit in other ways (e.g., quitting from Scheme) this
  31. ;;; may leave garbage temp files in your directory. The garbage files are
  32. ;;; named temp-display<n>.
  33. ;;; EXPRESSION->TEX-STRING returns the string that is input to tex
  34. ;;; 2D-SHOW-EXPRESSION is a simple 2D ASCII character printer for
  35. ;;; mathematical expressions.
  36. ;;; Example:
  37. ;;; (define test
  38. ;;; '(/
  39. ;;; (+ alpha (/ ((derivative f) b) (+ alpha beta)))
  40. ;;; (+ (/ (+ x y) 2) (expt (/ (+ a c (/ 2 x)) (* d e)) (+ f (/ g h))))))
  41. ;;; (display (expression->tex-string test))
  42. ;;; $${{\alpha + {{Df\left( b \right)}\over {\alpha + \beta}}}
  43. ;;; \over {{{x + y}\over {2}} + \left( {{a + c + {{2}\over {x}}}\over {d e}} \right)
  44. ;;; ^{f + {{g}\over {h}}}}}$$
  45. ;;; (2d-show-expression test)
  46. ;;; Df(b)
  47. ;;; alpha + ------------
  48. ;;; alpha + beta
  49. ;;; ----------------------------
  50. ;;; g
  51. ;;; f + -
  52. ;;; / 2 \ h
  53. ;;; | a + c + - |
  54. ;;; x + y | x |
  55. ;;; ----- + | --------- |
  56. ;;; 2 \ d e /
  57. ;;; Unlike Jaffer's code, this version does not handle line breaks. We
  58. ;;; can extend it some day.
  59. #|
  60. ;;; To make this stand-alone must add:
  61. (define derivative-symbol 'D)
  62. (define (up-maker? expr) (and (pair? expr) (eq? (car expr) 'up)))
  63. (define (vector-maker? expr) (and (pair? expr) (eq? (car expr) 'vector)))
  64. (define (down-maker? expr) (and (pair? expr) (eq? (car expr) 'down)))
  65. (define (matrix-by-rows-maker? expr)
  66. (and (pair? expr) (eq? (car expr) 'matrix-by-rows)))
  67. |#
  68. (declare (usual-integrations))
  69. ;;; exported functions
  70. (define enable-tex-display #t)
  71. ;;; FBE: we may have to move this to the end of the file.
  72. ;; (module exdisplay-module (internal-show-expression
  73. ;; 2d-show-expression
  74. ;; expression->tex-string
  75. ;; display-tex-string
  76. ;;
  77. ;; last-tex-string-generated)
  78. ;;(define internal-show-expression)
  79. ;;(define 2d-show-expression)
  80. ;;(define expression->tex-string)
  81. ;;(define display-tex-string)
  82. ;;; FBE: make a parameter
  83. (define last-tex-string-generated (make-parameter (void)))
  84. (define display-in-screen-window
  85. (let ((count 0))
  86. (lambda (tex-string)
  87. (let* ((dirname (->namestring (user-homedir-pathname)))
  88. (file-name (string-append dirname
  89. "temp-display"
  90. (number->string count)))
  91. (complete-tex-input (string-append
  92. ;;" \\magnification=\\magstep2\n"
  93. ;;"\\hsize=48pc \\hoffset=-4pc "
  94. "\\voffset=-6pc "
  95. "\\hsize=48pc " " \\hoffset=-6pc "
  96. boxit-string "\n"
  97. tex-string
  98. "\\vfil\\bye")))
  99. (with-output-to-file
  100. (string-append file-name ".tex")
  101. (lambda () (display complete-tex-input)))
  102. #|
  103. (working-unix/system (string-append "cd " dirname ";"
  104. " tex " file-name
  105. " > //dev//null 2>&1 "))
  106. (working-unix/system
  107. (string-append "xdvi " file-name ".dvi "
  108. "-s 4 "
  109. "-yoffset 3.5 "
  110. "-geometry 900x400+1+1; "
  111. "//bin//rm " file-name ".*"
  112. ))
  113. |#
  114. (run-shell-command
  115. (string-append "cd " dirname ";"
  116. " tex " file-name
  117. " > /dev/null 2>&1 ")
  118. 'output #f
  119. 'shell-file-name "/bin/sh")
  120. (run-shell-command
  121. (string-append "xdvi " file-name ".dvi "
  122. "-s 4 "
  123. "-yoffset 3.5 "
  124. "-geometry 900x400+1+1"
  125. " > /dev/null 2>&1; "
  126. "/bin/rm " file-name ".*"
  127. )
  128. 'output #f
  129. 'shell-file-name "/bin/sh")
  130. (set! count (+ count 1))
  131. ))))
  132. (define boxit-string
  133. "\\def\\boxit#1{\\vbox{\\hrule\\hbox{\\vrule\\kern5pt
  134. \\vbox{\\kern5pt#1\\kern5pt}\\kern3pt\\vrule}\\hrule}}\n")
  135. ;;; A couple of utility procedures:
  136. #|
  137. ;;some magic from Jinx
  138. (define (working-unix/system string)
  139. (let ((old #f))
  140. (dynamic-wind
  141. (lambda ()
  142. (set! old (thread-timer-interval))
  143. (set-thread-timer-interval! #f))
  144. (lambda ()
  145. (unix/system string))
  146. (lambda ()
  147. (set-thread-timer-interval! old)))))
  148. |#
  149. (define (2d-display-box box)
  150. (newline)
  151. (newline)
  152. (for-each (lambda (line)
  153. (for-each display (line-elements line))
  154. (newline))
  155. (box-lines box))
  156. (newline))
  157. ;;; The program works by gluing together boxes, which are lists of
  158. ;;; lines, all of the same width (the box-width). A box also has a
  159. ;;; vertical offset (box-voffset), which is used to align boxes when
  160. ;;; gluing them together horizontally--the vertical offset represents
  161. ;;; the height of the top line of the box with respect to a designated
  162. ;;; "zero" line. There is also a binding power (box-binding-power)
  163. ;;; that is used in unparsing expressions from infix to prefix. The
  164. ;;; binding power represents how how tightly the box is "held together". If
  165. ;;; the binding power is less than the required binding power, the box
  166. ;;; will be enclosed in parentheses.
  167. ;;; A character string is considered to be a special kind of box with
  168. ;;; voffset 0 and binding power the maximum binding power.
  169. ;;; Data structure definitions for boxes
  170. (define (make-box voffset width binding-power lines)
  171. (append (list 'box voffset width binding-power)
  172. lines))
  173. (define (explicit-box? elt)
  174. (and (pair? elt)
  175. (eq? (car elt) 'BOX)))
  176. (define (box-voffset box)
  177. (if (explicit-box? box)
  178. (list-ref box 1)
  179. 0))
  180. (define (box-width box)
  181. (if (explicit-box? box)
  182. (list-ref box 2)
  183. (string-length box)))
  184. (define (box-binding-power box)
  185. (if (explicit-box? box)
  186. (list-ref box 3)
  187. max-bp))
  188. (define (box-lines box)
  189. (if (explicit-box? box)
  190. (list-tail box 4)
  191. (list (make-line (list box)))))
  192. (define (box-nlines box)
  193. (length (box-lines box)))
  194. ;;;make a box just like the given one, but with the designated binding
  195. ;;;power
  196. (define (make-box-with-bp bp box)
  197. (make-box (box-voffset box)
  198. (box-width box)
  199. bp
  200. (box-lines box)))
  201. (define (make-empty-box width height)
  202. (let ((lines (make-list height (make-blank-line width))))
  203. (make-box 0 ;v-offset arbitrary
  204. width
  205. max-bp ;binding power arbitrary
  206. lines)))
  207. ;;; A LINE is a list of strings (the line-elements of the line)
  208. (define (make-line elements)
  209. (cons 'line elements))
  210. (define (line-elements line)
  211. (cdr line))
  212. (define (make-blank-line width)
  213. (make-line (make-blank-line-elts width)))
  214. (define (make-blank-line-elts width)
  215. (if (= width 0)
  216. '()
  217. (list (make-string width #\SPACE))))
  218. ;;;; Operations for combining boxes
  219. ;;;Join boxes horizontally, aligned according to the vertical offsets.
  220. ;;;Resulting box will have the binding power of the first box and a
  221. ;;;v-offset equal to the max of the v-offsets
  222. (define (glue-horiz boxes)
  223. (if (null? (cdr boxes))
  224. (car boxes)
  225. (join2-right (car boxes) (glue-horiz (cdr boxes)))))
  226. (define (join2-right box1 box2)
  227. (let ((v1 (box-voffset box1))
  228. (v2 (box-voffset box2))
  229. (blank1 (make-blank-line (box-width box1)))
  230. (blank2 (make-blank-line (box-width box2))))
  231. (make-box (max v1 v2)
  232. (+ (box-width box1) (box-width box2))
  233. (box-binding-power box1)
  234. (cond ((> v1 v2)
  235. ;;must pad box2 on top to start
  236. (join-lines-horiz
  237. (box-lines box1)
  238. (append (make-list (- v1 v2) blank2)
  239. (box-lines box2))
  240. blank1
  241. blank2))
  242. ((> v2 v1)
  243. ;;must pad box1 on top
  244. (join-lines-horiz
  245. (append (make-list (- v2 v1) blank1)
  246. (box-lines box1))
  247. (box-lines box2)
  248. blank1
  249. blank2))
  250. (else (join-lines-horiz (box-lines box1)
  251. (box-lines box2)
  252. blank1
  253. blank2))))))
  254. (define (join-lines-horiz lines1 lines2 blank1 blank2)
  255. (cond ((null? lines1)
  256. (map (lambda (line2) (make-line (append (line-elements blank1)
  257. (line-elements line2))))
  258. lines2))
  259. ((null? lines2)
  260. (map (lambda (line1) (make-line (append (line-elements line1)
  261. (line-elements blank2))))
  262. lines1))
  263. (else (cons (make-line (append (line-elements (car lines1))
  264. (line-elements (car lines2))))
  265. (join-lines-horiz (cdr lines1) (cdr lines2) blank1 blank2)))))
  266. ;;; Glue boxes vertically. The boxes will all be extended to the
  267. ;;; width of the maximum width box, and centered within that width.
  268. ;;; The voffset will be the voffset of the first box. (I.e., the
  269. ;;; first box will stay at the same level, and the other boxes will be
  270. ;;; appended below it.) The binding power will be the binding power
  271. ;;; of the first box.
  272. (define (glue-vert boxes)
  273. (if (null? (cdr boxes))
  274. (car boxes)
  275. (glue-below (car boxes) (glue-vert (cdr boxes)))))
  276. (define (glue-below box1 box2)
  277. (let* ((new-width (max (box-width box1) (box-width box2)))
  278. (nbox1 (pad-box-centered-to-width new-width box1))
  279. (nbox2 (pad-box-centered-to-width new-width box2)))
  280. (make-box
  281. (box-voffset box1)
  282. new-width
  283. (box-binding-power box1)
  284. (append (box-lines nbox1) (box-lines nbox2)))))
  285. ;;; Glue-above is similar to glue-below below, except that the
  286. ;;; v-offset of the top line in box2 remains
  287. ;;; what it was, and box1 is glued in above it.
  288. (define (glue-above box1 box2)
  289. (let* ((new-width (max (box-width box1) (box-width box2)))
  290. (nbox1 (pad-box-centered-to-width new-width box1))
  291. (nbox2 (pad-box-centered-to-width new-width box2)))
  292. (make-box
  293. (+ (box-voffset box2) (length (box-lines box1)))
  294. new-width
  295. (box-binding-power box1)
  296. (append (box-lines nbox1) (box-lines nbox2)))))
  297. ;;;pad the box on both the left and the right so it is centered in a
  298. ;;;box of the given width
  299. (define (pad-box-centered-to-width width box)
  300. (let* ((extra (- width (box-width box)))
  301. (extra-left (floor->exact (/ extra 2)))
  302. (extra-right (- extra extra-left))
  303. (pad-left (make-blank-line-elts extra-left))
  304. (pad-right (make-blank-line-elts extra-right)))
  305. (make-box (box-voffset box)
  306. width
  307. (box-binding-power box)
  308. (map (lambda (line)
  309. (make-line
  310. (append pad-left
  311. (line-elements line)
  312. pad-right)))
  313. (box-lines box)))))
  314. ;;; pad the box on both the top and the bottom so it will be centeted
  315. ;;; in a box of the given height. "Centered" here means that the box
  316. ;;; will appear in the center of the expanded box, regardles of where
  317. ;;; the zero line was.
  318. (define (pad-box-centered-to-height height box)
  319. (let* ((extra (- height (box-nlines box)))
  320. (extra-top (floor->exact (/ extra 2)))
  321. (extra-bottom (- extra extra-top))
  322. (width (box-width box)))
  323. (let ((padded-box
  324. (glue-below (glue-above (make-empty-box width extra-top)
  325. box)
  326. (make-empty-box width extra-bottom))))
  327. (shift-top-to (- (box-nlines padded-box) 1)
  328. padded-box))))
  329. ;;; Offsetting boxes vertically
  330. ;;; Make the voffset of the bottom of the box be at n
  331. (define (shift-bottom-to n box)
  332. (shift-top-to (+ n -1 (box-nlines box)) box))
  333. ;;; Shift the box so that its zero line is now at n
  334. (define (shift-zero-to n box)
  335. (shift-top-to (+ n (box-voffset box)) box))
  336. ;;; Shift the box so that the top of the box is now at n
  337. (define (shift-top-to n box)
  338. (make-box n
  339. (box-width box)
  340. (box-binding-power box)
  341. (box-lines box)))
  342. ;;;Create a box from a list of strings, on string per line. The
  343. ;;;strings are padded on the right to be all the same width.
  344. (define (strings->vbox voffset strings)
  345. (let* ((width (apply max (map string-length strings)))
  346. (padded-strings
  347. (map (lambda (string)
  348. (string-append (make-string
  349. (- width (string-length string))
  350. #\SPACE)
  351. string))
  352. strings))
  353. (lines (map (lambda (string)
  354. (make-line (list string)))
  355. padded-strings)))
  356. (make-box voffset
  357. width
  358. max-bp
  359. lines)))
  360. ;;; List utility:
  361. ;;;Interpolate element between all items in the list
  362. (define (interpolate element list)
  363. (cond ((null? list) '())
  364. ((null? (cdr list)) list)
  365. (else (cons (car list)
  366. (cons element
  367. (interpolate element (cdr list)))))))
  368. ;;; Binding powers of elements, and required binding powers. An element
  369. ;;; on the left will be parenthesized if it is used in a context on the
  370. ;;; right that appears above it in the table.
  371. ;;;
  372. ;;; max-bp 200
  373. ;;; one-char symbol 200
  374. ;;; parenthesized thing 200
  375. ;;;
  376. ;;; n-char symbol 190 product set off with dots in Tex
  377. ;;;
  378. ;;; subscripted 140
  379. ;;; superscripted 140
  380. ;;; derivative 140
  381. ;;; 2nd derviv 140
  382. ;;; partial deriv 140
  383. ;;; nth deriv 140
  384. ;;; base of exponentiation 140
  385. ;;; item to be subscripted 140
  386. ;;; subscript 140
  387. ;;; item to be differentiated 140
  388. ;;; expt 130
  389. ;;; application 130
  390. ;;; operator of application 130
  391. ;;; product 120
  392. ;;; quotient 120
  393. ;;; term in product 120
  394. ;;; sum/diff 100
  395. ;;; exponent of exponentiation 100
  396. ;;; term in sum 100
  397. ;;; negation 99
  398. (define max-bp 200)
  399. ;;; Enclose the box in parentheses if its binding power is less than
  400. ;;; the required bp. Uptable is the unparsing table (needed in order
  401. ;;; to know how to parenthesize).
  402. (define (insure-bp uptable required box)
  403. (if (< (box-binding-power box) required)
  404. ((cadr (assq 'parenthesize uptable)) uptable box)
  405. box))
  406. ;;; Create a new box by enclosing the given box in vertically
  407. ;;; expanding parentheses. The binding power of the new box is the
  408. ;;; maximum binding power. The voffset will be the voffset of the
  409. ;;; original box.
  410. (define (2d:parenthesize uptable box)
  411. (let ((n (box-nlines box)))
  412. (cond ((= n 0) "()")
  413. ((<= n 2)
  414. (make-box-with-bp max-bp
  415. (glue-horiz (list "(" box ")"))))
  416. (else
  417. (let ((left-paren
  418. (strings->vbox
  419. (box-voffset box)
  420. (append '(" / ")
  421. (make-list (- n 2) "| ")
  422. '(" \\ "))))
  423. (right-paren
  424. (strings->vbox
  425. (box-voffset box)
  426. (append '(" \\ ")
  427. (make-list (- n 2) " |")
  428. '(" / ")))))
  429. (make-box-with-bp max-bp (glue-horiz (list left-paren box right-paren))))))))
  430. (define (tex:parenthesize uptable box)
  431. (make-box-with-bp max-bp (glue-horiz (list "\\left( " box " \\right)"))))
  432. ;;;; Unparsing handlers. Each handler takes the expression and the
  433. ;;;; unparsing table.
  434. ;;; Some of the handlers here work both for tex-display and for
  435. ;;; 2d-display, others are specific to one or the other.
  436. (define (unparse-default uptable args)
  437. (make-box-with-bp 130
  438. (glue-horiz
  439. (list (insure-bp uptable 130 (car args))
  440. ((cadr (assq 'parenthesize uptable))
  441. uptable
  442. (if (null? (cdr args))
  443. ""
  444. (glue-horiz (interpolate ", " (cdr args)))))))))
  445. (define (unparse-sum uptable args)
  446. (let ((args (map (lambda (a) (insure-bp uptable 100 a)) args)))
  447. (make-box-with-bp 100 (glue-horiz (interpolate " + " args)))))
  448. (define (unparse-difference uptable args)
  449. (let ((args (map (lambda (a) (insure-bp uptable 100 a)) args)))
  450. (make-box-with-bp 100 (glue-horiz (interpolate " - " args)))))
  451. (define (unparse-negation uptable args)
  452. (make-box-with-bp 99
  453. (glue-horiz
  454. (list "- " (insure-bp uptable 101 (car args))))))
  455. (define (unparse-signed-sum uptable signs terms)
  456. (let ((args (map (lambda (a) (insure-bp uptable 100 a)) terms)))
  457. (make-box-with-bp 100 (glue-horiz (interpolate-signs signs args)))))
  458. ;;number of signs should equal number of args
  459. (define (interpolate-signs signs args)
  460. (define (interp signs args)
  461. (cond ((null? args) '())
  462. ((null? (cdr args)) args)
  463. (else (cons (car args)
  464. (cons (if (eq? (car signs) '-) " - " " + ")
  465. (interp (cdr signs) (cdr args)))))))
  466. (let ((after-first-sign (interp (cdr signs) args)))
  467. (if (eq? (car signs) '-)
  468. (cons " - " after-first-sign)
  469. after-first-sign)))
  470. (define (2d:unparse-product uptable args)
  471. (let ((args (map (lambda (a) (insure-bp uptable 120 a)) args)))
  472. (make-box-with-bp 120 (glue-horiz (interpolate " " args)))))
  473. ;;; For a product, if an element is a >1-char symbol (binding power
  474. ;;; 190), we set it off from the other factors by dots
  475. (define (tex:unparse-product uptable args)
  476. (let ((args (map (lambda (a) (insure-bp uptable 120 a)) args)))
  477. (make-box-with-bp 120 (glue-horiz (interpolate-for-tex-product args)))))
  478. (define (interpolate-for-tex-product list)
  479. (define (separator a1 a2)
  480. (if (or (= (box-binding-power a1) 190)
  481. (= (box-binding-power a2) 190))
  482. " \\cdot "
  483. " "))
  484. (cond ((null? list) '())
  485. ((null? (cdr list)) list)
  486. (else (cons (car list)
  487. (cons (separator (car list) (cadr list))
  488. (interpolate-for-tex-product (cdr list)))))))
  489. (define (2d:unparse-quotient uptable args)
  490. (let* ((box1 (car args))
  491. (box2 (cadr args))
  492. (width (max (box-width box1) (box-width box2)))
  493. (rule-box (make-string width #\-)))
  494. (make-box-with-bp 120
  495. (glue-below
  496. (glue-above box1 rule-box)
  497. box2))))
  498. (define (tex:unparse-quotient uptable args)
  499. (let ((box1 (car args))
  500. (box2 (cadr args)))
  501. (make-box-with-bp 120
  502. (glue-horiz
  503. (list "{" "{" box1 "}"
  504. "\\over "
  505. "{" box2 "}" "}")))))
  506. (define (2d:unparse-expt uptable args)
  507. ;;if base is not shorter than expt, raise expt
  508. ;;so that its zero is one above the top of the base.
  509. ;;otherwise raise so that bottom of expt is one above the top of the
  510. ;;base
  511. (let* ((base (insure-bp uptable 140 (car args)))
  512. (expt (insure-bp uptable 100 (cadr args)))
  513. (shift-expt
  514. (if (>= (box-nlines base) (box-nlines expt))
  515. (shift-zero-to (+ (box-voffset base) 1)
  516. expt)
  517. (shift-bottom-to (+ (box-voffset base) 1)
  518. expt))))
  519. (make-box-with-bp
  520. 130
  521. (glue-horiz (list base shift-expt)))))
  522. (define (tex:unparse-expt uptable args)
  523. (let ((base (insure-bp uptable 140 (car args)))
  524. (expt (insure-bp uptable 100 (cadr args))))
  525. (make-box-with-bp
  526. 130
  527. (glue-horiz (list "{" base "}^{" expt "}")))))
  528. (define (2d:unparse-superscript uptable args)
  529. (let ((top (insure-bp uptable 140 (car args)))
  530. (script (insure-bp uptable 140 (cadr args))))
  531. (make-box-with-bp
  532. 140
  533. (glue-horiz
  534. (list top
  535. (shift-top-to (+ (box-voffset top) (box-nlines top))
  536. script))))))
  537. (define (tex:unparse-superscript uptable args)
  538. (let ((top (insure-bp uptable 140 (car args)))
  539. (scripts
  540. (map (lambda (ss)
  541. (insure-bp uptable 140 ss))
  542. (cdr args))))
  543. (make-box-with-bp
  544. 140
  545. (glue-horiz
  546. (append (list "{")
  547. (list top)
  548. (list "}^{")
  549. (let lp ((scripts scripts))
  550. (if (null? (cdr scripts))
  551. (list (car scripts))
  552. (append (list (car scripts))
  553. (list ", ")
  554. (lp (cdr scripts)))))
  555. (list "}"))))))
  556. (define (2d:unparse-subscript uptable args)
  557. (let ((top (insure-bp uptable 140 (car args)))
  558. (script (insure-bp uptable 140 (cadr args))))
  559. (make-box-with-bp
  560. 140
  561. (glue-horiz
  562. (list top
  563. (shift-top-to (- (box-voffset top) (box-nlines top))
  564. script))))))
  565. (define (tex:unparse-subscript uptable args)
  566. (let ((top (insure-bp uptable 140 (car args)))
  567. (scripts
  568. (map (lambda (ss)
  569. (insure-bp uptable 140 ss))
  570. (cdr args))))
  571. (make-box-with-bp
  572. 140
  573. (glue-horiz
  574. (append (list "{")
  575. (list top)
  576. (list "}_{")
  577. (let lp ((scripts scripts))
  578. (if (null? (cdr scripts))
  579. (list (car scripts))
  580. (append (list (car scripts))
  581. (list ", ")
  582. (lp (cdr scripts)))))
  583. (list "}"))))))
  584. #|
  585. (define (tex:unparse-subscript uptable args)
  586. (let ((top (insure-bp uptable 140 (car args)))
  587. (script (insure-bp uptable 140 (cadr args))))
  588. (make-box-with-bp
  589. 140
  590. (glue-horiz (list top "_{" script "}")))))
  591. |#
  592. (define (unparse-derivative uptable args)
  593. (make-box-with-bp
  594. 140
  595. (glue-horiz (list "D" (insure-bp uptable 140 (car args))))))
  596. #|
  597. (define (unparse-derivative uptable args)
  598. (make-box-with-bp
  599. 140
  600. (glue-horiz (list (insure-bp uptable 140 (car args)) "'"))))
  601. |#
  602. (define (tex:unparse-sqrt uptable args)
  603. (make-box-with-bp
  604. 140
  605. (glue-horiz (list "\\sqrt{" (insure-bp uptable 90 (car args)) "}"))))
  606. (define (tex:unparse-dotted uptable args)
  607. (make-box-with-bp
  608. 140
  609. (glue-horiz (list "\\dot{" (insure-bp uptable 140 (car args)) "}"))))
  610. (define (2d:unparse-dotted uptable args)
  611. (make-box-with-bp
  612. 140
  613. (glue-horiz (list "(dot " (insure-bp uptable 140 (car args)) ")"))))
  614. (define (tex:unparse-dotdotted uptable args)
  615. (make-box-with-bp
  616. 140
  617. (glue-horiz (list "\\ddot{" (insure-bp uptable 140 (car args)) "}"))))
  618. (define (2d:unparse-dotdotted uptable args)
  619. (make-box-with-bp
  620. 140
  621. (glue-horiz (list "(ddot " (insure-bp uptable 140 (car args)) ")"))))
  622. (define (tex:unparse-primed uptable args)
  623. (let ((top (insure-bp uptable 140 (car args))))
  624. (make-box-with-bp 140
  625. (glue-horiz (list "{" top "}^\\prime")))))
  626. (define (2d:unparse-primed uptable args)
  627. (make-box-with-bp
  628. 140
  629. (glue-horiz (list "(prime " (insure-bp uptable 140 (car args)) ")"))))
  630. (define (tex:unparse-primeprimed uptable args)
  631. (let ((top (insure-bp uptable 140 (car args))))
  632. (make-box-with-bp 140
  633. (glue-horiz (list "{" top "}^{\\prime\\prime}")))))
  634. (define (2d:unparse-primeprimed uptable args)
  635. (make-box-with-bp
  636. 140
  637. (glue-horiz (list "(primeprime " (insure-bp uptable 140 (car args)) ")"))))
  638. #|
  639. (define (unparse-second-derivative uptable args)
  640. (make-box-with-bp
  641. 140
  642. (glue-horiz (list (insure-bp uptable 140 (car args)) "''"))))
  643. |#
  644. (define (2d:unparse-second-derivative uptable args)
  645. (make-box-with-bp
  646. 140
  647. (glue-horiz (list (2d:unparse-expt uptable (list "D" "2"))
  648. (insure-bp uptable 140 (car args))))))
  649. (define (tex:unparse-second-derivative uptable args)
  650. (make-box-with-bp
  651. 140
  652. (glue-horiz (list (tex:unparse-expt uptable (list "D" "2"))
  653. (insure-bp uptable 140 (car args))))))
  654. ;;; This does not work with multiple subscripts
  655. (define (2d:unparse-partial-derivative uptable args)
  656. (make-box-with-bp
  657. 140
  658. (glue-horiz (list (2d:unparse-subscript uptable (list "D" (cadr args)))
  659. (insure-bp uptable 140 (car args))))))
  660. (define (tex:unparse-partial-derivative uptable args)
  661. (make-box-with-bp
  662. 140
  663. (glue-horiz
  664. (list (tex:unparse-subscript uptable (cons "\\partial" (cdr args)))
  665. (insure-bp uptable 140 (car args))))))
  666. (define (2d:unparse-nth-derivative uptable args)
  667. (let ((op (2d:unparse-expt uptable (list "D" (cadr args)))))
  668. (make-box-with-bp
  669. 140
  670. (glue-horiz (list op (insure-bp uptable 140 (car args)))))))
  671. (define (tex:unparse-nth-derivative uptable args)
  672. (let ((op (tex:unparse-expt uptable (list "D" (cadr args)))))
  673. (make-box-with-bp
  674. 140
  675. (glue-horiz (list op (insure-bp uptable 140 (car args)))))))
  676. ;;; vector is printed as column matrix
  677. (define (2d:unparse-vector uptable args)
  678. (2d:unparse-matrix uptable
  679. (map list args)))
  680. ;;; a vector will be displayed as a 1-column matrix
  681. (define (tex:unparse-vector uptable args)
  682. ;;args here is the list of vector elements
  683. (tex:unparse-matrix uptable
  684. (map list args)))
  685. ;;; matrix list is a list of rows where each row is a list
  686. (define (2d:unparse-matrix uptable matrix-list)
  687. ;;first pad all elements in each column to the max width in the
  688. ;;column
  689. (define (transpose matrix-lists)
  690. (apply map (cons list matrix-lists)))
  691. (let* ((matrix-with-widended-columns
  692. (transpose
  693. (map (lambda (column)
  694. (let ((width (apply max (map box-width column))))
  695. (map (lambda (element)
  696. (pad-box-centered-to-width width element))
  697. column)))
  698. (transpose matrix-list))))
  699. ;;pad all elts in each row to the max height
  700. (matrix-with-lengthened-rows
  701. (map (lambda (row)
  702. (let ((height (apply max (map box-nlines row))))
  703. (map (lambda (element)
  704. (pad-box-centered-to-height height element))
  705. row)))
  706. matrix-with-widended-columns))
  707. ;;glue elts in each row together, separated by two spaces
  708. (row-boxes
  709. (map (lambda (row) (glue-horiz (interpolate " " row)))
  710. matrix-with-lengthened-rows))
  711. ;;glue the rows together, with separated by blank lines
  712. (separated-row-boxes
  713. (interpolate (make-empty-box (box-width (car row-boxes)) 1)
  714. row-boxes))
  715. (all-elts
  716. (glue-vert separated-row-boxes))
  717. ;;surround matrix by brackets
  718. (with-brackets
  719. (glue-horiz
  720. (list (strings->vbox (box-voffset all-elts)
  721. (make-list (box-nlines all-elts) "["))
  722. all-elts
  723. (strings->vbox (box-voffset all-elts)
  724. (make-list (box-nlines all-elts) "]"))))))
  725. ;;center matrix vertically
  726. (shift-top-to
  727. (floor->exact (/ (box-nlines with-brackets) 2))
  728. with-brackets)))
  729. (define (tex:unparse-matrix uptable matrix-list)
  730. (let* ((displaystyle-rows
  731. (map (lambda (row)
  732. (map (lambda (elt)
  733. (glue-horiz (list "\\displaystyle{ "
  734. elt
  735. "}")))
  736. row))
  737. matrix-list))
  738. (separated-rows
  739. (map (lambda (row) (glue-horiz (interpolate " & " row)))
  740. displaystyle-rows))
  741. (separated-columns
  742. (glue-horiz (interpolate " \\cr \\cr " separated-rows))))
  743. #;
  744. (glue-horiz
  745. (list "\\left\\{ \\matrix{ "
  746. separated-columns
  747. "} \\right\\}"))
  748. (glue-horiz
  749. (list "\\left\\lgroup \\matrix{ "
  750. separated-columns
  751. "} \\right\\rgroup"))))
  752. (define (tex:unparse-up uptable matrix-list)
  753. (let* ((displaystyle-rows
  754. (map (lambda (row)
  755. (map (lambda (elt)
  756. (glue-horiz (list "\\displaystyle{ "
  757. elt
  758. "}")))
  759. row))
  760. matrix-list))
  761. (separated-rows
  762. (map (lambda (row) (glue-horiz (interpolate " & " row)))
  763. displaystyle-rows))
  764. (separated-columns
  765. (glue-horiz (interpolate " \\cr \\cr " separated-rows))))
  766. (glue-horiz
  767. (list left-up-delimiter separated-columns right-up-delimiter))))
  768. (define (tex:unparse-down uptable matrix-list)
  769. (let* ((displaystyle-rows
  770. (map (lambda (row)
  771. (map (lambda (elt)
  772. (glue-horiz (list "\\displaystyle{ "
  773. elt
  774. "}")))
  775. row))
  776. matrix-list))
  777. (separated-rows
  778. (map (lambda (row) (glue-horiz (interpolate " & " row)))
  779. displaystyle-rows))
  780. (separated-columns
  781. (glue-horiz (interpolate " \\cr \\cr " separated-rows))))
  782. (glue-horiz
  783. (list left-down-delimiter separated-columns right-down-delimiter))))
  784. ;;; Unparsing table for 2D displays
  785. (define 2d:unparse-table
  786. `((parenthesize ,2d:parenthesize)
  787. (default ,unparse-default)
  788. (+ ,unparse-sum)
  789. ;;need sum (in addition to +) as an internal hook for
  790. ;;process-sum
  791. (sum ,unparse-sum)
  792. (- ,unparse-difference)
  793. (* ,2d:unparse-product)
  794. (negation ,unparse-negation)
  795. (/ ,2d:unparse-quotient)
  796. (signed-sum ,unparse-signed-sum)
  797. (expt ,2d:unparse-expt)
  798. (,derivative-symbol ,unparse-derivative)
  799. (derivative ,unparse-derivative)
  800. (second-derivative ,2d:unparse-second-derivative)
  801. (nth-derivative ,2d:unparse-nth-derivative)
  802. (partial-derivative ,2d:unparse-partial-derivative)
  803. (subscript ,2d:unparse-subscript)
  804. (superscript ,2d:unparse-superscript)
  805. (vector ,2d:unparse-vector)
  806. (row ,2d:unparse-matrix)
  807. (column ,2d:unparse-matrix)
  808. (down ,2d:unparse-matrix)
  809. (up ,2d:unparse-matrix)
  810. (matrix ,2d:unparse-matrix)
  811. (dotted ,2d:unparse-dotted)
  812. (dotdotted ,2d:unparse-dotdotted)
  813. (primed ,2d:unparse-primed)
  814. (primeprimed ,2d:unparse-primeprimed)
  815. ))
  816. (define 2d:symbol-substs
  817. `((derivative "D")
  818. ))
  819. (define tex:unparse-table
  820. `((parenthesize ,tex:parenthesize)
  821. (default ,unparse-default)
  822. (+ ,unparse-sum)
  823. ;;need sum (in addition to +) as an internal hook for
  824. ;;process-sum
  825. (sum ,unparse-sum)
  826. (- ,unparse-difference)
  827. (* ,tex:unparse-product)
  828. (& ,tex:unparse-product)
  829. (negation ,unparse-negation)
  830. (/ ,tex:unparse-quotient)
  831. (signed-sum ,unparse-signed-sum)
  832. (expt ,tex:unparse-expt)
  833. (,derivative-symbol ,unparse-derivative)
  834. (derivative ,unparse-derivative)
  835. (second-derivative ,tex:unparse-second-derivative)
  836. (nth-derivative ,tex:unparse-nth-derivative)
  837. (partial-derivative ,tex:unparse-partial-derivative)
  838. (subscript ,tex:unparse-subscript)
  839. (superscript ,tex:unparse-superscript)
  840. (vector ,tex:unparse-vector)
  841. (column ,tex:unparse-up)
  842. (row ,tex:unparse-down)
  843. (up ,tex:unparse-up)
  844. (down ,tex:unparse-down)
  845. (matrix ,tex:unparse-matrix)
  846. (sqrt ,tex:unparse-sqrt)
  847. (dotted ,tex:unparse-dotted)
  848. (dotdotted ,tex:unparse-dotdotted)
  849. (primed ,tex:unparse-primed)
  850. (primeprimed ,tex:unparse-primeprimed)
  851. ))
  852. (define tex:symbol-substs
  853. (append `((derivative "D")
  854. (acos "\\arccos")
  855. (asin "\\arcsin")
  856. (atan "\\arctan")
  857. )
  858. (map (lambda (string)
  859. (list (string->symbol string)
  860. (string-append "\\" string)))
  861. '(
  862. "alpha" "beta" "gamma" "delta" "epsilon" "zeta" "eta" "theta"
  863. "iota" "kappa" "lambda" "mu" "nu" "xi"
  864. ;; "omicron" does not appear in tex
  865. "pi" "rho" "tau" "upsilon" "phi" "chi" "psi" "omega"
  866. "varepsilon" "vartheta" "varpi" "varrho" "varsigma" "varphi"
  867. ;;"Alpha" "Beta"
  868. "Gamma" "Delta"
  869. ;;"Epsilon" "Zeta" "Eta"
  870. "Theta"
  871. ;;"Iota" "Kappa"
  872. "Lambda"
  873. ;;"Mu" "Nu"
  874. "Xi"
  875. ;;"Omicron"
  876. "Pi"
  877. ;;"Rho" "Tau"
  878. "Upsilon" "Phi"
  879. ;;"Chi"
  880. "Psi" "Omega"
  881. "aleph" "hbar" "nabla" "top" "bot" "mho" "Re" "Im"
  882. "infty" "Box" "diamond" "Diamond" "triangle"
  883. "sin" "cos" "tan" "cot" "sec" "csc" "log" "exp"
  884. ))
  885. (map (lambda (string)
  886. (list (string->symbol string)
  887. (string-append "{\\rm\\ " string " }")))
  888. '("&meter" "&kilogram" "&second"
  889. "&ampere" "&kelvin" "&mole"
  890. "&candela" "&radian"
  891. "&newton" "&joule" "&coulomb"
  892. "&watt" "&volt" "&ohm"
  893. "&siemens" "&farad" "&weber"
  894. "&henry" "&hertz" "&tesla"
  895. "&pascal" "&katal" "&becquerel"
  896. "&gray" "&sievert" "&inch"
  897. "&pound" "&slug" "&foot"
  898. "&mile" "&dyne" "&calorie"
  899. "&day" "&year" "&sidereal-year"
  900. "&AU" "&arcsec" "&pc"
  901. "&ly" "&esu" "&ev"))))
  902. ;;; Actual unparsing procedure. Symbol-substs is a table of special symbols
  903. ;;; to be substituted for. UPtable is an unparsing table.
  904. (define (unparse exp symbol-substs uptable)
  905. (let ((exp (unparse-special-convert exp))
  906. (up (lambda (exp) (unparse exp symbol-substs uptable))))
  907. (cond ((null? exp) "")
  908. ((number? exp) (unparse-number exp symbol-substs uptable))
  909. ((symbol? exp) (unparse-symbol exp symbol-substs uptable))
  910. ((up-maker? exp)
  911. ((cadr (assq 'column uptable))
  912. uptable
  913. (map list (map up (cdr exp)))))
  914. ((down-maker? exp)
  915. ((cadr (assq 'row uptable))
  916. uptable
  917. ;; For horizontal format
  918. ;;(list (map up (cdr exp)))
  919. ;; For vertical format
  920. (map list (map up (cdr exp)))))
  921. ((vector-maker? exp)
  922. ((cadr (assq 'vector uptable))
  923. uptable
  924. (map up (cdr exp))))
  925. ((matrix-by-rows-maker? exp)
  926. ((cadr (assq 'matrix uptable))
  927. uptable
  928. (map (lambda (row) (cdr (map up row)))
  929. (cdr exp))))
  930. ((eq? (car exp) '+)
  931. (process-sum exp symbol-substs uptable))
  932. ((symbol? (car exp))
  933. (let ((proc (assq (car exp) uptable)))
  934. (if proc
  935. ((cadr proc) uptable (map up (cdr exp)))
  936. ((cadr (assq 'default uptable)) uptable (map up exp)))))
  937. (else
  938. (let ((proc (assq 'default uptable)))
  939. ((cadr proc) uptable (map up exp)))))))
  940. (define (unparse-number n symbol-substs uptable)
  941. (cond ((and (real? n) (< n 0))
  942. (unparse `(- ,(- n)) symbol-substs uptable))
  943. ((and (rational? n) (exact? n) (not (= (denominator n) 1)))
  944. (unparse `(/ ,(numerator n) ,(denominator n))
  945. symbol-substs
  946. uptable))
  947. (else (number->string n))))
  948. ;;; symbols are treated as follows: some symbols are looked for and
  949. ;;; substituted specially (e.g., alpha turns into \alpha for tex).
  950. ;;; Other symbols have implied subscripts, e.g., m_1. Symbols that
  951. ;;; are more than one character long have a lower binding power than
  952. ;;; symbols that are one character long, so that the product of foo
  953. ;;; and x, for example, will be written as foo <dot> x in Tex, or the
  954. ;;; square of dt will be (dt)^2.
  955. (define (unparse-symbol symbol symbol-substs uptable)
  956. (let ((s (assq symbol symbol-substs)))
  957. (if s
  958. (cadr s)
  959. (let ((string (symbol->string symbol)))
  960. (split-at-underscore-or-caret
  961. string
  962. (lambda (before at after)
  963. (if (not before) ;no underscore or caret in symbol
  964. (unparse-string string symbol-substs uptable)
  965. (unparse `(,at ,(string->symbol before) ,(string->symbol after))
  966. symbol-substs
  967. uptable))))))))
  968. (define dotdot-string "dotdot")
  969. (define dotdot-string-length (string-length dotdot-string))
  970. (define dot-string "dot")
  971. (define dot-string-length (string-length dot-string))
  972. (define primeprime-string "primeprime")
  973. (define primeprime-string-length (string-length primeprime-string))
  974. (define prime-string "prime")
  975. (define prime-string-length (string-length prime-string))
  976. #|
  977. (define (unparse-string string symbol-substs uptable)
  978. (if (= (string-length string) 1)
  979. string
  980. (cond ((string-search-forward dotdot-string string)
  981. => (lambda (n)
  982. (if (= (+ n dotdot-string-length) ;terminal dotdot
  983. (string-length string))
  984. (unparse `(dotdotted
  985. ,(string->symbol (string-head string n)))
  986. symbol-substs uptable)
  987. (make-box-with-bp 190 string))))
  988. ((string-search-forward dot-string string)
  989. => (lambda (n)
  990. (if (= (+ n dot-string-length) ;terminal dot
  991. (string-length string))
  992. (unparse `(dotted
  993. ,(string->symbol (string-head string n)))
  994. symbol-substs uptable)
  995. (make-box-with-bp 190 string))))
  996. ((string-search-forward primeprime-string string)
  997. => (lambda (n)
  998. (if (= (+ n primeprime-string-length) ;terminal primeprime
  999. (string-length string))
  1000. (unparse `(primeprimed
  1001. ,(string->symbol (string-head string n)))
  1002. symbol-substs uptable)
  1003. (make-box-with-bp 190 string))))
  1004. ((string-search-forward prime-string string)
  1005. => (lambda (n)
  1006. (if (= (+ n prime-string-length) ;terminal prime
  1007. (string-length string))
  1008. (unparse `(primed
  1009. ,(string->symbol (string-head string n)))
  1010. symbol-substs uptable)
  1011. (make-box-with-bp 190 string))))
  1012. (else
  1013. (make-box-with-bp 190 string)))))
  1014. |#
  1015. (define (unparse-string string symbol-substs uptable)
  1016. (define (for-terminal special-string special-string-length special-symbol)
  1017. (let ((n (string-search-forward special-string string)))
  1018. (if (and n (= (+ n special-string-length) (string-length string)))
  1019. (unparse `(,special-symbol
  1020. ,(string->symbol (string-head string n)))
  1021. symbol-substs uptable)
  1022. #f)))
  1023. (cond ((= (string-length string) 1) string)
  1024. ((for-terminal dotdot-string dotdot-string-length 'dotdotted))
  1025. ((for-terminal dot-string dot-string-length 'dotted))
  1026. ((for-terminal primeprime-string primeprime-string-length 'primeprimed))
  1027. ((for-terminal prime-string prime-string-length 'primed))
  1028. (else (make-box-with-bp 190 string))))
  1029. #|
  1030. (define (split-at-underscore-or-caret string cont)
  1031. ;;cont = (lambda (before after) ...)
  1032. (let ((index (string-find-next-char string #\_)))
  1033. (if (not index)
  1034. (cont #f #f)
  1035. (cont (string-head string index)
  1036. (string-tail string (+ index 1))))))
  1037. |#
  1038. (define (split-at-underscore-or-caret string cont)
  1039. ;;cont = (lambda (before at after) ...)
  1040. (let ((index (string-find-next-char-in-set string (char-set #\^ #\_))))
  1041. (if (not index)
  1042. (cont #f #f #f)
  1043. (cont (string-head string index)
  1044. (if (char=? (string-ref string index) #\^)
  1045. 'superscript
  1046. 'subscript)
  1047. (string-tail string (+ index 1))))))
  1048. ;;; Some forms have funny rules. For example, ((expt A 2) f) would
  1049. ;;; 2
  1050. ;;; unparse to A (f), but ((expt derivative 2) f) is traditionally
  1051. ;;; 2
  1052. ;;; written without parens, as D f. Partial derivatives are also
  1053. ;;; funny, since we will generally convert them to subscripts. The
  1054. ;;; following procedure catches these special forms. If there were
  1055. ;;; more of these, we would use a pattern matcher here.
  1056. (define (unparse-special-convert exp)
  1057. (cond ((and
  1058. ;;((expt derivative n) f) --> (nth-derivative f n)
  1059. (pair? exp)
  1060. (pair? (car exp))
  1061. (= (length exp) 2)
  1062. (= (length (car exp)) 3)
  1063. (eq? (caar exp) 'expt)
  1064. (or (eq? (cadar exp) 'derivative)
  1065. (eq? (cadar exp) derivative-symbol)))
  1066. (let ((exponent (list-ref (car exp) 2))
  1067. (base (cadr exp)))
  1068. (if (eq? exponent 2)
  1069. `(second-derivative ,base)
  1070. `(nth-derivative ,base ,exponent))))
  1071. ((and
  1072. ;;((partial x) f) --> (partial-derivative f x)
  1073. (pair? exp)
  1074. (pair? (car exp))
  1075. (= (length exp) 2)
  1076. (eq? (caar exp) 'partial))
  1077. `(partial-derivative ,(cadr exp) ,@(cdr (car exp))))
  1078. ((and
  1079. ;;(- x) --> (negation x)
  1080. (pair? exp)
  1081. (eq? (car exp) '-)
  1082. (eq? (length exp) 2))
  1083. `(negation ,(cadr exp)))
  1084. (else exp)))
  1085. ;;; for a sum, find all terms of the form (* -1 .....) and make them
  1086. ;;; appear without the -1 and with a negative sign in the sum
  1087. (define (process-sum exp symbol-substs uptable)
  1088. (let ((terms (cdr exp)))
  1089. (cond ((null? terms)
  1090. (unparse 0 symbol-substs uptable))
  1091. ((null? (cdr terms))
  1092. (unparse (car terms) symbol-substs uptable))
  1093. (else
  1094. (let ((signed-terms
  1095. (map (lambda (term)
  1096. (cond ((and (pair? term) (eq? (car term) '*))
  1097. (let ((first-factor (cadr term)))
  1098. (if (and (real? first-factor) (negative? first-factor))
  1099. (if (and (= first-factor -1) (not (null? (cddr term))))
  1100. (list '- (cons '* (cddr term)))
  1101. (list '- (cons '* (cons (- first-factor) (cddr term)))))
  1102. (list '+ term))))
  1103. ((and (pair? term) (eq? (car term) '/))
  1104. (let ((numer (cadr term)))
  1105. (cond ((and (real? numer) (negative? numer))
  1106. (list '- (cons '/ (cons (- numer) (cddr term)))))
  1107. ((and (pair? numer) (eq? (car numer) '*))
  1108. (let ((first-factor (cadr numer)))
  1109. (if (and (real? first-factor) (negative? first-factor))
  1110. (if (and (= first-factor -1) (not (null? (cddr numer))))
  1111. (list '-
  1112. (cons '/
  1113. (cons (cons '* (cddr numer))
  1114. (cddr term))))
  1115. (list '-
  1116. (cons '/
  1117. (cons (cons '*
  1118. (cons (- first-factor)
  1119. (cddr numer)))
  1120. (cddr term)))))
  1121. (list '+ term))))
  1122. (else
  1123. (list '+ term)))))
  1124. (else
  1125. (list '+ term))))
  1126. terms)))
  1127. (let ((processed-terms
  1128. (map (lambda (exp) (unparse exp symbol-substs uptable))
  1129. (map cadr signed-terms))))
  1130. ((cadr (assq 'signed-sum uptable))
  1131. uptable
  1132. (map car signed-terms)
  1133. processed-terms
  1134. )))))))
  1135. (define internal-show-expression
  1136. (lambda (exp)
  1137. (last-tex-string-generated (expression->tex-string exp))
  1138. (let ((name (graphics-type-name (graphics-type #f))))
  1139. (if (and (eq? name 'X) enable-tex-display)
  1140. (begin (display-in-screen-window (last-tex-string-generated))
  1141. (newline)
  1142. (newline)
  1143. ;; (display tex-string)
  1144. ;; (newline)
  1145. ;; (newline)
  1146. )
  1147. (2d-show-expression exp)))))
  1148. (define 2d-show-expression
  1149. (lambda (exp)
  1150. (2d-display-box
  1151. (unparse exp 2d:symbol-substs 2d:unparse-table))))
  1152. (define expression->tex-string
  1153. (lambda (exp)
  1154. (let* ((one-line-box (unparse exp tex:symbol-substs tex:unparse-table))
  1155. (tex-string
  1156. (with-output-to-string
  1157. (lambda ()
  1158. (for-each display
  1159. (line-elements (car (box-lines one-line-box))))))))
  1160. (string-append "\\boxit{ " "$$" tex-string "$$" "}"))))
  1161. #|
  1162. ;;; Beal's folly.
  1163. (set! expression->tex-string
  1164. (lambda (exp)
  1165. (let* ((one-line-box (unparse exp tex:symbol-substs tex:unparse-table))
  1166. (tex-string
  1167. (with-output-to-string
  1168. (lambda ()
  1169. (for-each display
  1170. (line-elements (car (box-lines one-line-box))))))))
  1171. (string-append "\\boxit{ " "$" tex-string "$" "}"))))
  1172. |#
  1173. (define display-tex-string display-in-screen-window)
  1174. ;;) ;end module
  1175. ;;;(define left-up-delimiter "\\left \\lceil \\matrix{ ")
  1176. ;;;(define right-up-delimiter "} \\right \\rceil")
  1177. ;;;(define left-down-delimiter "\\left \\lfloor \\matrix{ ")
  1178. ;;;(define right-down-delimiter "} \\right \\rfloor")
  1179. (define left-up-delimiter "\\left( \\matrix{ ")
  1180. (define right-up-delimiter "} \\right)")
  1181. (define left-down-delimiter "\\left[ \\matrix{ ")
  1182. (define right-down-delimiter "} \\right]")
  1183. #|
  1184. (define test
  1185. '(/
  1186. (+ alpha (/ ((derivative f) b) (+ alpha beta)))
  1187. (+ (/ (+ x y) 2) (expt (/ (+ a c (/ 2 x)) (* d e)) (+ f (/ g h))))))
  1188. |#