mathpr.red 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. module mathpr; % Header module for mathpr package.
  2. % Author: Anthony C. Hearn.
  3. create!-package('(mathpr mprint sqprint ratprin dfprin % prend specprin
  4. fortpri),
  5. nil);
  6. endmodule;
  7. module mprint; % Basic output package for symbolic expressions.
  8. % Authors: Anthony C. Hearn and Arthur C. Norman.
  9. % Copyright (c) 1991 RAND. All rights reserved.
  10. fluid '(!*fort
  11. !*list
  12. !*nat
  13. !*nosplit
  14. !*ratpri
  15. !*revpri
  16. overflowed!*
  17. orig!*
  18. pline!*
  19. posn!*
  20. p!*!*
  21. testing!-width!*
  22. ycoord!*
  23. ymax!*
  24. ymin!*);
  25. global '(!*eraise initl!* nat!*!* obrkp!* spare!*);
  26. switch list,ratpri,revpri,nosplit;
  27. % Global variables initialized in this section.
  28. % SPARE!* should be set in the system dependent code module.
  29. !*eraise := t;
  30. !*nat := nat!*!* := t;
  31. !*nosplit := t; % Expensive, maybe??
  32. obrkp!* := t;
  33. orig!*:=0;
  34. posn!* := 0;
  35. ycoord!* := 0;
  36. ymax!* := 0;
  37. ymin!* := 0;
  38. initl!* := append('(orig!* pline!*),initl!*);
  39. put('orig!*,'initl,0);
  40. flag('(linelength),'opfn); %to make it a symbolic operator;
  41. symbolic procedure mathprint l;
  42. << terpri!* t;
  43. maprin l;
  44. terpri!* t >>;
  45. symbolic procedure maprin u;
  46. if not overflowed!* then maprint(u,0);
  47. symbolic procedure maprint(l,p!*!*);
  48. % Print expression l at bracket level p!*!* without terminating
  49. % print line. Special cases are handled by:
  50. % pprifn: a print function that includes bracket level as 2nd arg.
  51. % prifn: a print function with one argument.
  52. begin scalar p,x,y;
  53. p := p!*!*; % p!*!* needed for (expt a (quotient ...)) case.
  54. if null l then return nil
  55. else if atom l
  56. then <<if not numberp l or (not l<0 or p<=get('minus,'infix))
  57. then prin2!* l
  58. else <<prin2!* "("; prin2!* l; prin2!* ")">>;
  59. return l >>
  60. else if stringp l then return prin2!* l
  61. else if not atom car l then maprint(car l,p)
  62. else if ((x := get(car l,'pprifn)) and
  63. not(apply2(x,l,p) eq 'failed)) or
  64. ((x := get(car l,'prifn)) and
  65. not(apply1(x,l) eq 'failed))
  66. then return l
  67. else if x := get(car l,'infix) then <<
  68. p := not x>p;
  69. if p then <<
  70. y := orig!*;
  71. prin2!* "(";
  72. orig!* := if posn!*<18 then posn!* else orig!*+3 >>;
  73. % (expt a b) was dealt with using a pprifn sometime earlier than this
  74. inprint(car l,x,cdr l);
  75. if p then <<
  76. prin2!* ")";
  77. orig!* := y >>;
  78. return l >>
  79. else prin2!* car l;
  80. prin2!* "(";
  81. obrkp!* := nil;
  82. y := orig!*;
  83. orig!* := if posn!*<18 then posn!* else orig!*+3;
  84. if cdr l then inprint('!*comma!*,0,cdr l);
  85. obrkp!* := t;
  86. orig!* := y;
  87. prin2!* ")";
  88. return l
  89. end;
  90. symbolic procedure exptpri(l,p);
  91. % Prints expression in an exponent notation.
  92. begin scalar !*list,x,pp,q,w1,w2;
  93. if not !*nat or !*fort then return 'failed;
  94. pp := not((q:=get('expt,'infix))>p); % Need to parenthesize
  95. w1 := cadr l;
  96. w2 := caddr l;
  97. if !*eraise and not atom w1 and
  98. (x := get(car w1, 'prifn)) and
  99. get(x, 'expt) = 'inbrackets then
  100. % Special treatment here to avoid muddle between exponents and
  101. % raised indices
  102. w1 := layout!-formula(w1, 0, 'inbrackets)
  103. % Very special treatment for things that will be displayed with
  104. % subscripts
  105. else if x = 'indexprin and not (indexpower(w1, w2)='failed)
  106. then return nil
  107. else w1 := layout!-formula(w1, q, nil);
  108. if null w1 then return 'failed;
  109. begin scalar !*ratpri;
  110. % I do not display fractions with fraction bars in exponent
  111. % expressions, since it usually seems excessive. Also (-p)/q gets
  112. % turned into -(p/q) for printing here
  113. if eqcar(w2,'quotient) and eqcar(cadr w2,'minus)
  114. then w2 := list('minus,list(car w2,cadadr w2,caddr w2))
  115. else w2 := negnumberchk w2;
  116. w2 := layout!-formula(w2, if !*eraise then 0 else q, nil)
  117. end;
  118. if null w2 then return 'failed;
  119. l := cdar w1 + cdar w2;
  120. if pp then l := l + 2;
  121. if l > linelength nil - spare!* - orig!* then return 'failed;
  122. if l > linelength nil - spare!* - posn!* then terpri!* t;
  123. if pp then prin2!* "(";
  124. putpline w1;
  125. if !*eraise then l := 1 - cadr w2
  126. else << oprin 'expt; l := 0 >>;
  127. putpline ((update!-pline(0, l, caar w2) . cdar w2) .
  128. ((cadr w2 + l) . (cddr w2 + l)));
  129. if pp then prin2!* ")"
  130. end;
  131. put('expt,'pprifn,'exptpri);
  132. symbolic procedure inprint(op,p,l);
  133. begin scalar x,y;
  134. if op eq 'plus and !*revpri then l := reverse l;
  135. % print sum arguments in reverse order.
  136. if not get(op,'alt) then <<
  137. if op eq 'setq and not atom (x := car reverse l)
  138. and idp car x and (y := getrtype x)
  139. and (y := get(get(y,'tag),'setprifn))
  140. then return apply2(y,car l,x);
  141. if null atom car l and idp caar l
  142. and !*nat and
  143. ((x := get(caar l,'prifn)) or (x := get(caar l,'pprifn)))
  144. and (get(x,op) eq 'inbrackets)
  145. % to avoid mix up of indices and exponents.
  146. then<<prin2!* "("; maprint(car l,p); prin2!* ")">>
  147. else if !*nosplit and not testing!-width!* then
  148. prinfit(car l, p, nil)
  149. else maprint(car l, p);
  150. l := cdr l >>;
  151. if !*nosplit and not testing!-width!* then
  152. % The code here goes to a certain amount of trouble to try to arrange
  153. % that terms are never split across lines. This will slow
  154. % printing down a bit, but I hope the improvement in formatting will
  155. % be worth that.
  156. for each v in l do
  157. if atom v or not(op eq get(car v,'alt))
  158. then <<
  159. % It seems to me that it looks nicer to put +, - etc on the second
  160. % line, but := and comma usually look better on the first one when I
  161. % need to split things.
  162. if op memq '(setq !*comma!*) then <<
  163. oprin op;
  164. prinfit(negnumberchk v, p, nil) >>
  165. else prinfit(negnumberchk v, p, op) >>
  166. else prinfit(v, p, nil)
  167. else for each v in l do <<
  168. if atom v or not(op eq get(car v,'alt))
  169. then <<oprin op; maprint(negnumberchk v,p)>>
  170. % difficult problem of negative numbers needing to be in
  171. % prefix form for pattern matching.
  172. else maprint(v,p) >>
  173. end;
  174. symbolic procedure flatsizec u;
  175. if null u then 0
  176. else if atom u then lengthc u
  177. else flatsizec car u + flatsizec cdr u + 1;
  178. symbolic procedure oprin op;
  179. (lambda x;
  180. if null x then <<prin2!* " "; prin2!* op; prin2!* " ">>
  181. else if !*fort then prin2!* x
  182. else if !*list and obrkp!* and op memq '(plus minus)
  183. then if testing!-width!* then overflowed!* := t
  184. else <<terpri!* t; prin2!* x>>
  185. else if flagp(op,'spaced)
  186. then <<prin2!* " "; prin2!* x; prin2!* " ">>
  187. else prin2!* x)
  188. get(op,'prtch);
  189. symbolic procedure prin2!* u;
  190. begin integer m,n;
  191. if overflowed!* then return 'overflowed
  192. else if !*fort then return fprin2 u
  193. else if !*nat then <<
  194. if u = 'pi then u := symbol '!.pi
  195. else if u = 'infinity then u := symbol 'infinity >>;
  196. n := lengthc u;
  197. if n<=(linelength nil-spare!*) then <<
  198. m := posn!*+n;
  199. % I somewhat dislike having the side-effect of a call to
  200. % terpri!* in the condition tested here, but that is maybe what
  201. % the problem calls for.
  202. if m<=(linelength nil-spare!*) or
  203. (not testing!-width!* and
  204. << terpri!* t;
  205. (m := posn!*+n)<=(linelength nil-spare!*) >>)
  206. then <<if not !*nat then %fjw% prin2 u
  207. % output should be REDUCE-readable %% begin{fjw}
  208. if stringp u or get(u,'switch!*) or digit u
  209. or get(car explode2 u,'switch!*) then prin2 u
  210. else prin1 u %% end{fjw}
  211. else pline!* := (((posn!* . m) . ycoord!*) . u)
  212. . pline!*;
  213. return (posn!* := m)>>>>;
  214. %identifier longer than one line;
  215. if testing!-width!* then <<
  216. overflowed!* := t;
  217. return 'overflowed >>
  218. else if !*fort
  219. then rerror(mathpr,1,list(u,"too long for FORTRAN"));
  220. % Let LISP print the atom.
  221. terpri!* nil;
  222. prin2t u;
  223. % if !*clisp then m := posn() else
  224. % I think this is what is really wanted.
  225. m := remainder(n,(linelength nil-spare!*));
  226. return (posn!* := m)
  227. end;
  228. symbolic procedure terpri!* u;
  229. begin integer n;
  230. if testing!-width!* then return overflowed!* := t
  231. else if !*fort then return fterpri(u)
  232. else if !*nat and pline!*
  233. then <<
  234. pline!* := reverse pline!*;
  235. for n := ymax!* step -1 until ymin!* do <<
  236. scprint(pline!*,n);
  237. terpri() >>;
  238. pline!* := nil >>;
  239. if u then terpri();
  240. posn!* := orig!*;
  241. ycoord!* := ymax!* := ymin!* := 0
  242. end;
  243. symbolic procedure scprint(u,n);
  244. begin scalar m;
  245. posn!* := 0;
  246. for each v in u do <<
  247. if cdar v=n then <<
  248. if not((m:= caaar v-posn!*)<0) then spaces m;
  249. prin2 cdr v;
  250. posn!* := cdaar v >> >>
  251. end;
  252. % Definition of some symbols and their access function.
  253. symbolic procedure symbol s;
  254. get(s,'symbol!-character);
  255. put('!.pi, 'symbol!-character, 'pi);
  256. put('bar, 'symbol!-character, '!-);
  257. put('int!-top, 'symbol!-character, '!/);
  258. put('int!-mid, 'symbol!-character, '!|);
  259. put('int!-low, 'symbol!-character, '!/);
  260. put('d, 'symbol!-character, '!d); % This MUST be lower case
  261. %%put('sqrt, 'symbol!-character, 'sqrt);% No useful fallback here
  262. put('vbar, 'symbol!-character, '!|);
  263. put('sum!-top, 'symbol!-character, "---");
  264. put('sum!-mid, 'symbol!-character, "> ");
  265. put('sum!-low, 'symbol!-character, "---");
  266. put('prod!-top, 'symbol!-character, "---");
  267. put('prod!-mid, 'symbol!-character, "| |");
  268. put('prod!-low, 'symbol!-character, "| |");
  269. put('infinity, 'symbol!-character, 'infinity);
  270. % In effect nothing special
  271. put('mat!-top!-l, 'symbol!-character, '![);
  272. put('mat!-top!-r, 'symbol!-character, '!]);
  273. put('mat!-low!-l, 'symbol!-character, '![);
  274. put('mat!-low!-r, 'symbol!-character, '!]);
  275. % The following definitions allow for more natural printing of
  276. % conditional expressions within rule lists.
  277. symbolic procedure condpri(u,p);
  278. <<if p>0 then prin2!* "(";
  279. while (u := cdr u) do
  280. <<if not(caar u eq 't)
  281. then <<prin2!* 'if; prin2!* " "; maprin caar u;
  282. prin2!* " "; prin2!* 'then; prin2!* " ">>;
  283. maprin cadar u;
  284. if cdr u then <<prin2!* " "; prin2!* 'else; prin2!* " ">>>>;
  285. if p>0 then prin2!* ")">>;
  286. put('cond,'pprifn,'condpri);
  287. symbolic procedure revalpri u;
  288. maprin eval cadr u;
  289. put('aeval,'prifn,'revalpri);
  290. put('reval,'prifn,'revalpri);
  291. symbolic procedure boolvalpri u;
  292. maprin cadr u;
  293. put('boolvalue!*,'prifn,'boolvalpri);
  294. endmodule;
  295. module sqprint; % Routines for printing standard forms and quotients.
  296. % Author: Anthony C. Hearn.
  297. % Copyright (c) 1991 RAND. All rights reserved.
  298. % Modified by A. C. Norman, 1987.
  299. fluid '(!*fort
  300. !*nat
  301. !*nero
  302. !*pri
  303. !*prin!#
  304. overflowed!*
  305. orig!*
  306. posn!*
  307. testing!-width!*
  308. ycoord!*
  309. ymax!*
  310. ymin!*
  311. wtl!*);
  312. testing!-width!* := overflowed!* := nil;
  313. global '(!*eraise !*horner);
  314. % When nat is enabled I use some programmable characters to
  315. % draw pi, fraction bars and integral signs. (symbol 's) returns
  316. % a character-object, and I use
  317. % .pi pi
  318. % bar solid horizontal bar -
  319. % int-top top hook of integral sign /
  320. % int-mid vertical mid-stroke of integral sign |
  321. % int-low lower hook of integral sign /
  322. % d curly-d for use with integral display d
  323. % sqrt square root sign sqrt
  324. % sum-top ---
  325. % sum-mid > for summation
  326. % sum-low ---
  327. % prod-top ---
  328. % prod-mid | | for products
  329. % prod-low | |
  330. % infinity infinity sign
  331. % mat!-top!-l / for display of matrices
  332. % mat!-top!-r \
  333. % mat!-low!-l \
  334. % mat!-low!-r /
  335. % vbar |
  336. symbolic procedure !*sqprint u;
  337. sqprint cadr u;
  338. put('!*sq, 'prifn, '!*sqprint);
  339. symbolic procedure printsq u;
  340. << terpri!* t;
  341. sqprint u;
  342. terpri!* u;
  343. u >>;
  344. symbolic procedure sqprint u;
  345. %mathprints the standard quotient U;
  346. begin scalar flg,w,z,!*prin!#;
  347. !*prin!# := t;
  348. z := orig!*;
  349. if !*nat and posn!*<20 then orig!* := posn!*;
  350. if !*pri or wtl!* then <<
  351. if null !*horner
  352. or errorp(w:=errorset!*(list('horner,mkquote u),nil))
  353. then w := prepsq!* u
  354. else w := prepsq car w;
  355. maprin w >>
  356. else if cdr u neq 1 then <<
  357. flg := not domainp numr u and red numr u;
  358. if flg then prin2!* "(";
  359. xprinf(car u,nil,nil);
  360. if flg then prin2!* ")";
  361. prin2!* " / ";
  362. flg:= not domainp denr u and (red denr u or lc denr u neq 1);
  363. % flg:= not domainp denr u and red denr u;
  364. if flg then prin2!* "(";
  365. xprinf(cdr u,nil,nil);
  366. if flg then prin2!* ")" >>
  367. else xprinf(car u,nil,nil);
  368. return (orig!* := z)
  369. end;
  370. symbolic procedure printsf u;
  371. << prinsf u;
  372. terpri!* nil;
  373. u >>;
  374. symbolic procedure prinsf u;
  375. if null u then prin2!* 0 else xprinf(u,nil,nil);
  376. symbolic procedure xprinf(u,v,w);
  377. %U is a standard form.
  378. %V is a flag which is true if a term has preceded current form.
  379. %W is a flag which is true if form is part of a standard term;
  380. %Procedure prints the form and returns NIL;
  381. << while not domainp u do <<
  382. xprint(lt u,v);
  383. u := red u;
  384. v := t >>;
  385. if not null u then xprid(u,v,w)
  386. else nil >>;
  387. symbolic procedure xprid(u,v,w);
  388. %U is a domain element.
  389. %V is a flag which is true if a term has preceded element.
  390. %W is a flag which is true if U is part of a standard term.
  391. %Procedure prints element and returns NIL;
  392. begin
  393. if minusf u then <<oprin 'minus; u := !:minus u>>
  394. else if v then oprin 'plus;
  395. if not w or u neq 1
  396. then if atom u then prin2!* u else maprin u
  397. end;
  398. symbolic procedure xprint(u,v);
  399. %U is a standard term.
  400. %V is a flag which is true if a term has preceded this term.
  401. %Procedure prints the term and returns NIL;
  402. begin scalar flg,w;
  403. flg := not domainp tc u and red tc u;
  404. if flg then <<
  405. if v then oprin 'plus;
  406. prin2!* "(" >>;
  407. xprinf(tc u,if flg then nil else v,not flg);
  408. if flg then prin2!* ")";
  409. if not atom tc u or not abs tc u=1 then oprin 'times;
  410. w := tpow u;
  411. if atom car w then prin2!* car w
  412. else if not atom caar w or caar w eq '!*sq then <<
  413. prin2!* "(";
  414. if not atom caar w then xprinf(car w,nil,nil)
  415. else sqprint cadar w;
  416. prin2!* ")" >>
  417. else if caar w eq 'plus then maprint(car w,100)
  418. else maprin car w;
  419. if not (cdr w=1) then <<
  420. if !*nat and !*eraise
  421. then <<ycoord!* := ycoord!*+1;
  422. if ycoord!*>ymax!* then ymax!* := ycoord!*>>
  423. else prin2!* get('expt,'prtch);
  424. prin2!* if numberp cdr w and minusp cdr w then list cdr w
  425. else cdr w;
  426. if !*nat and !*eraise
  427. then <<ycoord!* := ycoord!*-1;
  428. if ymin!*>ycoord!* then ymin!* := ycoord!*>> >>
  429. end;
  430. symbolic procedure varpri(u,v,w);
  431. begin scalar x;
  432. %U is expression being printed
  433. %V is the original form that was evaluated.
  434. %W is an id that indicates if U is the first, only or last element
  435. % in the current set (or NIL otherwise).
  436. testing!-width!* := overflowed!* := nil;
  437. if null u then u := 0;
  438. if !*nero and u=0 then return nil;
  439. v := setvars v;
  440. if (x := getrtype u) and flagp(x,'sprifn)
  441. then return if null v then apply1(get(get(x,'tag),'prifn),u)
  442. else maprin list('setq,car v,u);
  443. if w memq '(first only) then terpri!* t;
  444. if !*fort then return fvarpri(u,v,w);
  445. if v then u := 'setq . aconc(v,u);
  446. maprin u;
  447. if null w or w eq 'first then return nil
  448. else if not !*nat then prin2!* "$";
  449. terpri!*(not !*nat);
  450. return nil
  451. end;
  452. symbolic procedure setvars u;
  453. if atom u then nil
  454. else if car u memq '(setel setk)
  455. then lispeval cadr u . setvars caddr u
  456. else if car u eq 'setq then cadr u . setvars caddr u
  457. else nil;
  458. endmodule;
  459. module ratprin; % Printing standard quotients.
  460. % Author: Eberhard Schruefer.
  461. % Modifications by: Anthony C. Hearn & A. C. Norman.
  462. fluid '(!*fort
  463. !*list
  464. !*mcd
  465. !*nat
  466. !*ratpri
  467. dmode!*
  468. ycoord!*
  469. ymin!*
  470. ymax!*
  471. orig!*
  472. pline!*
  473. posn!*
  474. p!*!*);
  475. global '(spare!*);
  476. switch ratpri;
  477. !*ratpri := t; % default value if this module is loaded.
  478. put('quotient,'prifn,'quotpri);
  479. put('quotpri, 'expt, 'inbrackets);
  480. symbolic procedure quotpri u;
  481. % *mcd is included here since it uses rational domain elements.
  482. begin scalar dmode;
  483. if null !*ratpri or null !*nat or !*fort or !*list or null !*mcd
  484. then return 'failed
  485. else if flagp(dmode!*,'ratmode)
  486. then <<dmode := dmode!*; dmode!* := nil>>;
  487. u := ratfunpri1 u;
  488. if dmode then dmode!* := dmode;
  489. return u
  490. end;
  491. symbolic procedure ratfunpri1 u;
  492. begin scalar x,y,ch,pln,pld;
  493. integer heightnum,heightden,orgnum,orgden,fl,w;
  494. spare!* := spare!* + 2;
  495. if (pln := layout!-formula(cadr u, 0, nil)) and
  496. (pld := layout!-formula(caddr u, 0, nil)) then <<
  497. spare!* := spare!* - 2;
  498. fl := 2 + max(cdar pln, cdar pld);
  499. if fl>(linelength nil - spare!* - posn!*) then terpri!* t;
  500. w := (cdar pln - cdar pld); % Width difference num vs. den
  501. if w > 0 then << orgnum := 0; orgden := w / 2 >>
  502. else << orgnum := (-w) / 2; orgden := 0 >>;
  503. heightnum := cddr pln - cadr pln + 1;
  504. heightden := cddr pld - cadr pld + 1;
  505. pline!* :=
  506. append(
  507. update!-pline(orgnum + posn!* + 1 - orig!*,
  508. 1 - cadr pln + ycoord!*,
  509. caar pln),
  510. append(update!-pline(orgden + posn!* + 1 - orig!*,
  511. ycoord!* - cddr pld - 1,
  512. caar pld),
  513. pline!*));
  514. ymin!* := min(ymin!*, ycoord!* - heightden);
  515. ymax!* := max(ymax!*, ycoord!* + heightnum);
  516. ch := symbol 'bar;
  517. for j := 1:fl do prin2!* ch >>
  518. else <<
  519. % Here the miserable thing will not fit on one line
  520. spare!* := spare!* - 2; % Restore
  521. u := cdr u;
  522. x := get('quotient,'infix);
  523. if p!*!* then y := p!*!*>x else y := nil;
  524. if y then prin2!* "(";
  525. maprint(car u,x);
  526. oprin 'quotient;
  527. maprint(negnumberchk cadr u,x);
  528. if y then prin2!* ")">>
  529. end;
  530. symbolic procedure layout!-formula(u, p, op);
  531. % This procedure forms a pline!* structure for an expression that
  532. % will fit upon a single line. It returns the pline* together with
  533. % height, depth and width information. If the line would not fit
  534. % it returns nil. Note funny treatment of orig!* and width here.
  535. % If op is non-nil oprin it too - if it is 'inbrackets do that.
  536. begin
  537. scalar ycoord!*, ymin!*, ymax!*, posn!*, pline!*,
  538. testing!-width!*, overflowed!*;
  539. pline!* := overflowed!* := nil;
  540. ycoord!* := ymin!* := ymax!* := 0;
  541. posn!* := orig!*;
  542. testing!-width!* := t;
  543. if op then <<
  544. if op = 'inbrackets then prin2!* "("
  545. else oprin op >>;
  546. maprint(u, p);
  547. if op = 'inbrackets then prin2!* ")";
  548. if overflowed!* then return nil
  549. else return (pline!* . (posn!* - orig!*)) . (ymin!* . ymax!*)
  550. end;
  551. symbolic procedure update!-pline(x,y,pline);
  552. % Adjusts origin of expression in pline by (x,y).
  553. if x=0 and y=0 then pline
  554. else for each j in pline collect
  555. (((caaar j + x) . (cdaar j + x)) . (cdar j + y)) . cdr j;
  556. symbolic procedure prinfit(u, p, op);
  557. % Display u (as with maprint) with op in front of it, but starting
  558. % a new line before it if there would be overflow otherwise.
  559. begin
  560. scalar w;
  561. if not !*nat or testing!-width!* then <<
  562. if op then oprin op;
  563. return maprint(u, p) >>;
  564. w := layout!-formula(u, p, op);
  565. if w = nil then <<
  566. if op then oprin op;
  567. return maprint(u, p) >>;
  568. putpline w
  569. end;
  570. symbolic procedure putpline w;
  571. begin
  572. if posn!* + cdar w > linelength nil - spare!* then terpri!* t;
  573. pline!* :=
  574. append(update!-pline(posn!* - orig!*, ycoord!*, caar w),
  575. pline!*);
  576. posn!* := posn!* + cdar w;
  577. ymin!* := min(ymin!*, cadr w + ycoord!*);
  578. ymax!* := max(ymax!*, cddr w + ycoord!*)
  579. end;
  580. endmodule;
  581. module dfprin; % Printing for derivatives plus other options
  582. % suggested by the Twente group
  583. % Author: A. C. Norman, reconstructing ideas from Ben Hulshof,
  584. % Pim van den Heuvel and Hans van Hulzen.
  585. fluid '(!*fort !*nat depl!* posn!*);
  586. global '(!*dfprint
  587. !*noarg
  588. farglist!*);
  589. switch dfprint,noarg;
  590. !*dfprint := nil; % This is OFF by default because switching it on
  591. % changes Reduce output in a way that might upset
  592. % customers who have not found out about this switch.
  593. % Perhaps in later releases of the code (and when the
  594. % manual reflects this upgrade) it will be possible
  595. % to make 'on dfprint' the default. Some sites may of
  596. % course wish to arrange things otherwise...
  597. !*noarg := t; % If dfprint is enabled I am happy for noarg to be
  598. % the expected option.
  599. farglist!* := nil;
  600. symbolic procedure dfprintfn u;
  601. % Display derivatives - if suitable flags are set this uses
  602. % subscripts to denote differentiation and loses the arguments to
  603. % functions.
  604. if not !*nat or !*fort or not !*dfprint then 'failed
  605. else begin
  606. scalar w;
  607. w := layout!-formula('!!df!! . cdr u, 0, nil);
  608. if w = nil then return 'failed
  609. else putpline w
  610. end;
  611. put('df, 'prifn, 'dfprintfn);
  612. symbolic procedure dflayout u;
  613. % This is a prifn for !!df!!, which is used internally when I am
  614. % formatting derivatives, but which should only ever be seen in
  615. % testing!-width!* mode and never at all by the end-user.
  616. begin
  617. scalar op, args, w;
  618. w := car (u := cdr u);
  619. u := cdr u;
  620. if !*noarg then <<
  621. if atom w then <<
  622. op := w;
  623. args := assoc(op, depl!*); % Implicit args
  624. if args then args := cdr args >>
  625. else <<
  626. op := car w;
  627. args := cdr w >>; % Explicit args
  628. remember!-args(op, args);
  629. w := op >>;
  630. maprin w;
  631. if u then <<
  632. u := layout!-formula('!!dfsub!! . u, 0, nil); % subscript line
  633. if null u then return 'failed;
  634. w := 1 + cddr u;
  635. putpline((update!-pline(0, -w, caar u) . cdar u) .
  636. ((cadr u - w) . (cddr u - w))) >>
  637. end;
  638. symbolic procedure dfsublayout u;
  639. % This is a prifn for !!dfsub!!, which is used internally when I am
  640. % formatting derivatives, but which should only ever be seen in
  641. % testing!-width!* mode and never at all by the end-user.
  642. begin
  643. scalar dfcase, firstflag, w;
  644. % This is used as a prifn for both df and other things with
  645. % subscripts - dfcase remembers which.
  646. dfcase := (car u = '!!dfsub!!);
  647. u := cdr u;
  648. firstflag := t;
  649. while u do <<
  650. w := car u;
  651. u := cdr u;
  652. if firstflag then firstflag := nil
  653. else prin2!* ",";
  654. if dfcase and u and numberp car u then <<
  655. prin2!* car u;
  656. u := cdr u >>;
  657. maprin w >>
  658. end;
  659. put('!!df!!, 'prifn, 'dflayout);
  660. put('!!dfsub!!, 'prifn, 'dfsublayout);
  661. symbolic procedure remember!-args(op, args);
  662. % This records information that can be displayed by the user
  663. % issuing the command 'FARG'.
  664. begin
  665. scalar w;
  666. w := assoc(op, farglist!*);
  667. if null w then farglist!* := (op . args) . farglist!*
  668. end;
  669. symbolic procedure farg;
  670. % Implementation of FARG: display implicit argument data
  671. begin
  672. scalar newname;
  673. prin2!* "The operators have the following ";
  674. prin2!* "arguments or dependencies";
  675. terpri!* t;
  676. for each p in farglist!* do <<
  677. prin2!* car p;
  678. prin2!* "=";
  679. % To avoid clever pieces of code getting rid of argument displays
  680. % here I convert the name of the function into a string so that
  681. % maprin produces a simple but complete display. Since I expect
  682. % farg to be called but rarely this does not seem overexpensive
  683. newname := compress ('!" . append(explodec car p, '(!")));
  684. maprin(newname . cdr p);
  685. terpri!* t >>
  686. end;
  687. put('farg, 'stat, 'endstat);
  688. symbolic procedure clfarg;
  689. % Clear record of implicit args
  690. farglist!* := nil;
  691. put('clfarg, 'stat, 'endstat);
  692. symbolic procedure setprifn(u, fn);
  693. % Establish (or clear) prifn property for a list of symbols
  694. for each n in u do
  695. if idp n then <<
  696. % Things listed here will be declared operators now if they have
  697. % not been so declared earlier.
  698. if not operatorp n then mkop n;
  699. if fn then put(n, 'prifn, fn)
  700. else remprop(n, 'prifn) >>
  701. else lprim list(n, "not an identifier");
  702. symbolic procedure indexprin u;
  703. % Print helper-function when integer-valued arguments are to be shown as
  704. % subscripts
  705. if not !*nat or !*fort then 'failed
  706. else begin
  707. scalar w;
  708. w := layout!-formula('!!index!! . u, 0, nil);
  709. if w = nil then return 'failed
  710. else putpline w
  711. end;
  712. symbolic procedure indexpower(u, n);
  713. % Print helper-function when integer-valued arguments are to be shown as
  714. % subscripts with exponent n
  715. begin
  716. scalar w;
  717. w := layout!-formula('!!indexpower!! . n . u, 0, nil);
  718. if w = nil then return 'failed
  719. else putpline w
  720. end;
  721. symbolic procedure indexlayout u;
  722. % This is a prifn for !!index!!, which is used internally when I am
  723. % formatting index forms, but which should only ever be seen in
  724. % testing!-width!* mode and never at all by the end-user.
  725. begin
  726. scalar w;
  727. w := car (u := cdr u);
  728. u := cdr u;
  729. maprin w;
  730. if u then <<
  731. u := layout!-formula('!!indexsub!! . u, 0, nil);
  732. % subscript line
  733. if null u then return 'failed;
  734. w := 1 + cddr u;
  735. putpline((update!-pline(0, -w, caar u) . cdar u) .
  736. ((cadr u - w) . (cddr u - w))) >>
  737. end;
  738. symbolic procedure indexpowerlayout u;
  739. % Format a subscripted object raised to some power.
  740. begin
  741. scalar n, w, pos, maxpos;
  742. n := car (u := cdr u); % The exponent
  743. w := car (u := cdr u);
  744. u := cdr u;
  745. maprin w;
  746. w := layout!-formula(n, 0, nil);
  747. pos := posn!*;
  748. putpline((update!-pline(0, 1 - cadr w, caar w) . cdar w) .
  749. (1 . (1 + cddr w - cadr w)));
  750. maxpos := posn!*;
  751. posn!* := pos;
  752. if u then <<
  753. u := layout!-formula('!!indexsub!! . u, 0,nil);
  754. % subscript line
  755. if null u then return 'failed;
  756. w := 1 + cddr u;
  757. putpline((update!-pline(0, -w, caar u) . cdar u) .
  758. ((cadr u - w) . (cddr u - w))) >>;
  759. posn!* := max(posn!*, maxpos)
  760. end;
  761. put('!!index!!, 'prifn, 'indexlayout);
  762. put('!!indexpower!!, 'prifn, 'indexpowerlayout);
  763. put('!!indexsub!!, 'prifn, 'dfsublayout);
  764. symbolic procedure noargsprin u;
  765. % Print helper-function when arguments for a function are to be hidden,
  766. % but remembered for display via farg
  767. if not !*nat or !*fort then 'failed
  768. else <<
  769. remember!-args(car u, cdr u);
  770. maprin car u >>;
  771. symbolic procedure doindex u;
  772. % Establish some function names to have args treated as index values
  773. setprifn(u, 'indexprin);
  774. symbolic procedure offindex u;
  775. % Clear effect of doindex
  776. setprifn(u, nil);
  777. symbolic procedure donoargs u;
  778. % Identify functions where args are to be hidden
  779. setprifn(u, 'noargsprin);
  780. symbolic procedure offnoargs u;
  781. % Clear effect of donoargs
  782. setprifn(u, nil);
  783. put('doindex, 'stat, 'rlis);
  784. put('offindex, 'stat, 'rlis);
  785. put('donoargs, 'stat, 'rlis);
  786. put('offnoargs, 'stat, 'rlis);
  787. endmodule;
  788. module fortpri; % FORTRAN output package for expressions.
  789. % Author: Anthony C. Hearn.
  790. % Modified by: James Davenport after Francoise Richard, April 1988.
  791. % Copyright (c) 1991 RAND. All rights reserved.
  792. fluid '(!*fort
  793. !*period
  794. scountr
  795. explis
  796. fbrkt
  797. fvar
  798. nchars
  799. svar
  800. posn!*);
  801. global '(cardno!*
  802. fortwidth!*
  803. spare!*
  804. varnam!*);
  805. %Global variables initialized in this section;
  806. % SPARE!* should be set in the system dependent code module.
  807. cardno!*:=20;
  808. fortwidth!* := 70;
  809. posn!* := 0;
  810. varnam!* := 'ans;
  811. flag ('(cardno!* fortwidth!*),'share);
  812. symbolic procedure varname u;
  813. %sets the default variable assignment name;
  814. varnam!* := car u;
  815. rlistat '(varname);
  816. symbolic procedure flength(u,chars);
  817. if chars<0 then chars
  818. else if atom u
  819. then chars-if numberp u then if fixp u then flatsizec u+1
  820. else flatsizec u
  821. else flatsizec((lambda x; if x then x else u)
  822. get(u,'prtch))
  823. else flength(car u,flenlis(cdr u,chars)-2);
  824. symbolic procedure flenlis(u,chars);
  825. if null u then chars
  826. else if chars<0 then chars
  827. else if atom u then flength(u,chars)
  828. else flenlis(cdr u,flength(car u,chars));
  829. symbolic procedure fmprint(l,p);
  830. begin scalar x;
  831. if null l then return nil
  832. else if atom l then <<
  833. if l eq 'e then return fprin2 "EXP(1.0)";
  834. if not numberp l or
  835. not l<0 then return fprin2 l;
  836. fprin2 "(";
  837. fbrkt := nil . fbrkt;
  838. fprin2 l;
  839. fprin2 ")";
  840. return fbrkt := cdr fbrkt >>
  841. else if stringp l then return fprin2 l
  842. else if not atom car l then fmprint(car l,p)
  843. % else if x := get(car l,'specprn)
  844. % then return apply1(x,cdr l)
  845. else if ((x := get(car l,'pprifn))
  846. and not((x := apply2(x,l,p)) eq 'failed)) or
  847. ((x := get(car l,'prifn))
  848. and not((x := apply1(x,l)) eq 'failed))
  849. then return x
  850. else if x := get(car l,'infix) then <<
  851. p := not x>p;
  852. if p then <<fprin2 "("; fbrkt := nil . fbrkt>>;
  853. fnprint(car l,x,cdr l);
  854. if p then <<fprin2 ")"; fbrkt := cdr fbrkt>>;
  855. return >>
  856. else fprin2 car l;
  857. fprin2 "(";
  858. fbrkt := nil . fbrkt;
  859. x := !*period;
  860. % Assume no period printing for non-operators (e.g., matrices).
  861. if gettype car l neq 'operator then !*period := nil;
  862. if cdr l then fnprint('!*comma!*,0,cdr l);
  863. !*period := x;
  864. fprin2 ")";
  865. return fbrkt := cdr fbrkt
  866. end;
  867. symbolic procedure fnprint(op,p,l);
  868. begin
  869. if op eq 'expt then return fexppri(p,l)
  870. else if not get(op,'alt) then <<
  871. fmprint(car l,p);
  872. l := cdr l >>;
  873. for each v in l do <<
  874. if atom v or not (op eq get(car v,'alt)) then foprin op;
  875. fmprint(v,p) >>
  876. end;
  877. symbolic procedure fexppri(p,l);
  878. % Next line added by James Davenport after Francoise Richard.
  879. if car l eq 'e then fmprint('exp . cdr l,p)
  880. else begin scalar pperiod;
  881. fmprint(car l,p);
  882. foprin 'expt;
  883. pperiod := !*period;
  884. if numberp cadr l then !*period := nil else !*period := t;
  885. fmprint(cadr l,p);
  886. !*period := pperiod
  887. end;
  888. symbolic procedure foprin op;
  889. (lambda x; if null x then fprin2 op else fprin2 x) get(op,'prtch);
  890. symbolic procedure fvarpri(u,v,w);
  891. %prints an assignment in FORTRAN notation;
  892. begin integer scountr,llength,nchars; scalar explis,fvar,svar;
  893. llength := linelength nil;
  894. if not posintegerp cardno!*
  895. then typerr(cardno!*,"FORTRAN card number");
  896. if not posintegerp fortwidth!*
  897. then typerr(fortwidth!*,"FORTRAN line width");
  898. linelength fortwidth!*;
  899. if stringp u
  900. then return <<fprin2 u;
  901. if w eq 'only then fterpri(t);
  902. linelength llength>>;
  903. if eqcar(u,'!*sq) then u := prepsq!* cadr u;
  904. scountr := 0;
  905. nchars := ((linelength nil-spare!*)-12)*cardno!*;
  906. %12 is to allow for indentation and end of line effects;
  907. svar := varnam!*;
  908. fvar := if null v then svar else car v;
  909. if posn!*=0 and w then fortpri(fvar,u,w)
  910. else fortpri(nil,u,w);
  911. % should mean expression preceded by a string.
  912. linelength llength
  913. end;
  914. symbolic procedure fortpri(fvar,xexp,w);
  915. begin scalar fbrkt;
  916. if eqcar(xexp,'list)
  917. then <<posn!* := 0;
  918. fprin2 "C ***** INVALID FORTRAN CONSTRUCT (";
  919. fprin2 car xexp;
  920. return fprin2 ") NOT PRINTED">>;
  921. if flength(xexp,nchars)<0
  922. then xexp := car xexp . fout(cdr xexp,car xexp,w);
  923. if fvar
  924. then <<posn!* := 0;
  925. fprin2 " ";
  926. fmprint(fvar,0);
  927. fprin2 "=">>;
  928. fmprint(xexp,0);
  929. if w then fterpri(w)
  930. end;
  931. symbolic procedure fout(args,op,w);
  932. begin integer ncharsl; scalar distop,x,z;
  933. ncharsl := nchars;
  934. if op memq '(plus times) then distop := op;
  935. while args do
  936. <<x := car args;
  937. if atom x and (ncharsl := flength(x,ncharsl))
  938. or (null cdr args or distop)
  939. and (ncharsl := flength(x,ncharsl))>0
  940. then z := x . z
  941. else if distop and flength(x,nchars)>0
  942. then <<z := fout1(distop . args,w) . z;
  943. args := list nil>>
  944. else <<z := fout1(x,w) . z;
  945. ncharsl := flength(op,ncharsl)>>;
  946. ncharsl := flength(op,ncharsl);
  947. args := cdr args>>;
  948. return reversip!* z
  949. end;
  950. symbolic procedure fout1(xexp,w);
  951. begin scalar fvar;
  952. fvar := genvar();
  953. explis := (xexp . fvar) . explis;
  954. fortpri(fvar,xexp,w);
  955. return fvar
  956. end;
  957. % If we are in a comment, we want to continue to stay in one,
  958. % Even if there's a formula. That's the purpose of this flag
  959. % Added by James Davenport after Francoise Richard.
  960. global '(Comment!*);
  961. symbolic procedure fprin2 u;
  962. % FORTRAN output of U;
  963. begin integer m,n;
  964. if posn!*=0 then Comment!*:=
  965. stringp u and cadr(explode u) eq 'C;
  966. n := flatsizec u;
  967. m := posn!*+n;
  968. if fixp u and !*period then m := m+1;
  969. if m<(linelength nil-spare!*) then posn!* := m
  970. else <<terpri();
  971. if Comment!* then << prin2 "C"; spaces 4 >>
  972. else spaces 5;
  973. prin2 ". "; posn!* := n+7>>;
  974. prin2 u;
  975. if fixp u and !*period then prin2 "."
  976. end;
  977. symbolic procedure fterpri(u);
  978. <<if not posn!*=0 and u then terpri();
  979. posn!* := 0>>;
  980. symbolic procedure genvar;
  981. intern compress append(explode svar,explode(scountr := scountr + 1));
  982. endmodule;
  983. end;