codmat.red 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. module codmat; % Support for matrix optimization.
  2. % -------------------------------------------------------------------- ;
  3. % Copyright : J.A. van Hulzen, Twente University, Dept. of Computer ;
  4. % Science, P.O.Box 217, 7500 AE Enschede, the Netherlands. ;
  5. % Authors : J.A. van Hulzen, B.J.A. Hulshof, M.C. van Heerwaarden, ;
  6. % J.C.A. Smit, W.N. Borst. ;
  7. % -------------------------------------------------------------------- ;
  8. % -------------------------------------------------------------------- ;
  9. % The module CODMAT consists of two parts: ;
  10. % 1 - A collection of Extended Access Functions to the CODMAT-matrix ;
  11. % and the associated hashvector CODHISTO. ;
  12. % 2 - Routines for constructing the incidence matrix CODMAT via par- ;
  13. % sing and storage of a set of input expressions. ;
  14. % 3 - Routines for removing gcd's from quotients. ;
  15. % -------------------------------------------------------------------- ;
  16. % ;
  17. % -------------------------------------------------------------------- ;
  18. % PART 1 : EXTENDED ACCESS FUNCTIONS ;
  19. % -------------------------------------------------------------------- ;
  20. % ;
  21. % These functions allow to STORE,RETRIEVE or MODIFY information stored ;
  22. % in CODMAT and CODHISTO, used for hashing. ;
  23. % Remark:A detailed description of the vectors CODMAT and CODHISTO and ;
  24. % their DIRECT ACCESS FUNCTIONS, heavily used here, is given in the ;
  25. % module COSYMP. ;
  26. % ;
  27. % ------ A CLASSIFICATION OF THE EXTENDED ACCESS FUNCTIONS ------ ;
  28. % ;
  29. % - STORAGE : SetRow,InsZZZ,InsZZZn,InsZZZr,PnthXZZ. ;
  30. % - HISTOGRAM OPERATIONS : InsHisto,DelHisto,Downwght,Downwght1,Upwght,;
  31. % Upwght1,Initwght. ;
  32. % - MODIFICATION : Rowdel,Rowins,RemZZZZ,Chdel,DelYZZ,Clearrow. ;
  33. % - PRINTING TESTRUNS : ChkCodMat. ;
  34. % ;
  35. % ------ TERMINOLOGY USED ------ ;
  36. % ZZ stands for a Zstrt and Z for a single item in ZZ. A Zstrt is a ;
  37. % list of pairs (row(column)index . coeff(exponent)information).Hence a;
  38. % double linked list representation is used. Both X and Y denote indi- ;
  39. % ces.The Cdr-part of a Z-element is in fact again a dotted pair (IVal.;
  40. % BVal). The BValue however is only used in CODPRI.RED for printing ;
  41. % purposes,related to the finishing touch. Therefore we only take IVal ;
  42. % as Cdr-part in the ;
  43. % Example : +| a b c d ;
  44. % Let -+--------- ;
  45. % f = a + 2*b + 3*c f| 1 2 3 ;
  46. % g =2*a + 4*b + 5*d g| 2 4 5 ;
  47. % ;
  48. % Taking MaxVar=4 results in : ;
  49. % ;
  50. % CODMAT index=|I| |Zstrt ZZ | ;
  51. % -------------+-+-+--------------------+----------------------------- ;
  52. % ....... | | | |Rows: Structure created by ;
  53. % ....... | | | |Fvar or FFvar using I=MaxVar+ ;
  54. % ....... | | | |RowMax (See Row and FillRow, ;
  55. % Rowmax= 1 |5|g|((-4.5)(-2.4)(-1.2))|defined in module COSYMP ;
  56. % Rowmax= 0 |4|f|((-3.3)(-2.2)(-1.1))|and used in SETROW). ;
  57. % -------------+-+-+--------------------+----------------------------- ;
  58. % Rowmin=-1 |3|a|((1.2)(0.1)) |Columns:Created by SSetVars( ;
  59. % Rowmin=-2 |2|b|((1.4)(0.2)) |part 2 of this module) : I= ;
  60. % Rowmin=-3 |1|c|((0.3)) |Maxvar+Rowmin. The Zstrts of ;
  61. % Rowmin=-4 |0|d|((1.5)) | the rows are also completed ;
  62. % ....... | | | | by SSetvars. ;
  63. % -------------------------------------------------------------------- ;
  64. % ;
  65. % Remarks : ;
  66. % -1- The CODMAT index I used in the above example is thus the physical;
  67. % value of the subscript. This in contrast to the indices used when;
  68. % calling routines like SETROW, which operate on Rowmax or Rowmin ;
  69. % values (details are given in CODCTL.RED and in the routine ROW in;
  70. % COSYMP.RED). ;
  71. % -2- A similar picture is produced for f=a*b^2*c^3 and g=a^2*b^4*d^5. ;
  72. % When introducing monomials as terms or sum as factors also the ;
  73. % Child-facilities have to be used like done for operators other ;
  74. % than + or *. ;
  75. % -------------------------------------------------------------------- ;
  76. symbolic$
  77. global '(codmat maxvar rowmin rowmax endmat codhisto headhisto
  78. !*vectorc !*inputc known rhsaliases);
  79. fluid '(preprefixlist prefixlist);
  80. switch vectorc$
  81. !*vectorc := nil$
  82. % ____________________________________________________________________ ;
  83. % A description of these globals is given in the module CODCTL ;
  84. % -------------------------------------------------------------------- ;
  85. symbolic procedure setrow(n,op,fa,s,zz);
  86. % -------------------------------------------------------------------- ;
  87. % arg : N : Row(column)index of the row(column) of which the value has ;
  88. % to be (re)set. Physically we need MaxVar + N(see ROW in ;
  89. % COSYMP.RED). ;
  90. % Op: Operator value to be stored in Opval,i.e. 'PLUS,'TIMES or ;
  91. % some other operator. ;
  92. % Fa: For a row the name (toplevel) or index (subexpression) of ;
  93. % the father.For a column the template of the column variable;
  94. % S : Compiled code demands atmost 5 parameters,atleast for some ;
  95. % REDUCE implementations. Therefore S stands for a list of ;
  96. % Chrow information,if necessary extended with the monomial ;
  97. % coefficient(Opval='TIMES) or the exponent of a linear ex- ;
  98. % pression(Opval='PLUS),to be stored in the CofExp-field. ;
  99. % ZZ: The Z-street. ;
  100. % eff : Row(column) N is created and set. If necessary,i.e. if N>MaxVar;
  101. % then CODMAT is doubled in size. ;
  102. % -------------------------------------------------------------------- ;
  103. begin scalar codmat1;
  104. if abs(n)>maxvar
  105. then % Double the size of CODMAT.
  106. <<codmat1:=mkvect(4*maxvar);
  107. for x:=max(rowmin,-maxvar):min(rowmax,maxvar) do
  108. putv(codmat1,x+2*maxvar,row x);
  109. codmat:=codmat1;
  110. maxvar:=2*maxvar;
  111. >>;
  112. % --------------------------------------------------------------------;
  113. % Now the values are set,using LenCol=4 and LenRow=8,i.e. the fields ;
  114. % Chrow,CofExp,HiR and Ordr are not in use for columns because: ;
  115. % - Chrow and CofExp are irrelevant for storing information about ;
  116. % variable occurrences. ;
  117. % - Hashing(HiR) and CSE-insertion(Ordr) are based on row-information ;
  118. % only. ;
  119. % --------------------------------------------------------------------;
  120. if n<0
  121. then fillrow(n,mkvect lencol)
  122. else
  123. <<fillrow(n,mkvect lenrow);
  124. setchrow(n,car s);
  125. if cdr s
  126. then setexpcof(n,cadr s)
  127. else setexpcof(n,1)>>;
  128. setfree(n);
  129. setopval(n,op);
  130. setfarvar(n,fa);
  131. setzstrt(n,zz)
  132. end;
  133. symbolic procedure inszzz(z,zz);
  134. % -------------------------------------------------------------------- ;
  135. % arg : Z : A matrix element. ;
  136. % ZZ: A set of matrix elements with indices in descending order. ;
  137. % eff : A set of matrix elements including Z and ZZ,again in ascending ;
  138. % order,such that in case Z's index already exists the Ival- ;
  139. % parts of both elements are added together. ;
  140. % -------------------------------------------------------------------- ;
  141. if null zz or xind(car zz)<xind(z)
  142. then z.zz
  143. else
  144. if xind(car zz)=xind(z)
  145. then <<setival(car zz,dm!-plus(ival(car zz),ival(z)));
  146. if zeropp(ival car zz)
  147. then cdr(zz)
  148. else zz>>
  149. else car(zz).inszzz(z,cdr zz);
  150. symbolic procedure inszzzn(z,zz);
  151. % -------------------------------------------------------------------- ;
  152. % eff : Similar to InsZZZ.However,Z is only inserted if its index is ;
  153. % not occuring as car-part of one of the elements of ZZ. ;
  154. % -------------------------------------------------------------------- ;
  155. if null(zz) or xind(car zz)<xind(z)
  156. then z.zz
  157. else
  158. if xind(car zz)=xind(z)
  159. then zz
  160. else car(zz).inszzzn(z,cdr zz);
  161. symbolic procedure inszzzr(z,zz);
  162. % -------------------------------------------------------------------- ;
  163. % eff : Similar to InsZZZ,but the indices of ZZ are now given in as- ;
  164. % cending order. ;
  165. % -------------------------------------------------------------------- ;
  166. if null(zz) or xind(car zz)>xind(z)
  167. then z.zz
  168. else
  169. if xind(car zz)=xind(z)
  170. then <<setival(car zz,dm!-plus(ival(car zz),ival(z)));
  171. % We have to test whether the result of dm!-plus was zero.
  172. % Storing a zero leads to errors. Hvh 06-04-95.
  173. if zeropp(ival car zz)
  174. then cdr(zz)
  175. else zz>>
  176. else car(zz).inszzzr(z,cdr zz);
  177. symbolic procedure pnthxzz(x,zz);
  178. % -------------------------------------------------------------------- ;
  179. % arg : X is a row(column)index and ZZ a Z-street. ;
  180. % res : A sublist of ZZ such that Caar ZZ = X. ;
  181. % -------------------------------------------------------------------- ;
  182. if null(zz) or xind(car zz)=x
  183. then zz
  184. else pnthxzz(x,cdr zz);
  185. symbolic procedure inshisto(x);
  186. % -------------------------------------------------------------------- ;
  187. % arg : Rowindex X. ;
  188. % eff : X is inserted in the Histogram-hierarchy. ;
  189. % ;
  190. % The insertion can be vizualized in the following way : ;
  191. % ;
  192. % CODHISTO CODMAT ;
  193. % ;
  194. % index value Row Hwght HiR ;
  195. % 200 +---+ index (PHiR . NHiR) ;
  196. % | | . . . ;
  197. % : : : : : ;
  198. % | | : : : ;
  199. % +---+ | | | ;
  200. % i | k | <--> +---+---+---------------+ ;
  201. % +---+ | k | i | Nil . m | ;
  202. % | | +---+---+---------------+ ;
  203. % : : | | | | ;
  204. % | | : : : : ;
  205. % +---+ | | | | ;
  206. % 0 | | +---+---+---------------+ ;
  207. % +---+ | m | i | k . p | ;
  208. % +---+---+---------------+ ;
  209. % | | | | ;
  210. % : : : : ;
  211. % | | | | ;
  212. % +---+---+---------------+ ;
  213. % | p | i | m . Nil | ;
  214. % +---+---+---------------+ ;
  215. % : : : : ;
  216. % ;
  217. % -------------------------------------------------------------------- ;
  218. if free(x) and x>=0
  219. then
  220. begin scalar y,hv;
  221. if y:=histo(hv:=min(hwght x,histolen))
  222. then setphir(y,x)
  223. else
  224. if hv>headhisto
  225. then headhisto:=hv;
  226. sethir(x,nil.y);
  227. sethisto(hv,x)
  228. end;
  229. symbolic procedure delhisto(x);
  230. % -------------------------------------------------------------------- ;
  231. % arg : Rowindex X. ;
  232. % eff : Removes X from the histogram-hierarchy. ;
  233. % -------------------------------------------------------------------- ;
  234. if free(x) and x>=0
  235. then
  236. begin scalar y,z,hv;
  237. y:=phir x;
  238. z:=nhir x;
  239. hv:=min(hwght(x),histolen);
  240. if y then setnhir(y,z) else sethisto(hv,z);
  241. if z then setphir(z,y);
  242. end;
  243. symbolic procedure rowdel x;
  244. % -------------------------------------------------------------------- ;
  245. % arg : Row(column)index X. ;
  246. % eff : Row X is deleted from CODMAT. SetOccup ensures that row X is ;
  247. % disregarded until further notice. Although the Zstrt remains, ;
  248. % the weights of the corresponding columns are reset like the ;
  249. % Histogram info. ;
  250. % -------------------------------------------------------------------- ;
  251. <<delhisto(x);
  252. setoccup(x);
  253. foreach z in zstrt(x) do
  254. downwght(yind z,ival z)>>;
  255. symbolic procedure rowins x;
  256. % -------------------------------------------------------------------- ;
  257. % arg : Row(column)index X. ;
  258. % eff : Reverse of the Rowdel operations. ;
  259. % -------------------------------------------------------------------- ;
  260. <<setfree(x);
  261. inshisto(x);
  262. foreach z in zstrt(x) do
  263. upwght(yind z,ival z)>>;
  264. symbolic procedure downwght(x,iv);
  265. % -------------------------------------------------------------------- ;
  266. % arg : Row(column)index X. Value IV. ;
  267. % eff : The weight of row X is adapted because an element with value IV;
  268. % has been deleted. ;
  269. % -------------------------------------------------------------------- ;
  270. <<delhisto(x);
  271. downwght1(x,iv);
  272. inshisto(x)>>;
  273. symbolic procedure downwght1(x,iv);
  274. % -------------------------------------------------------------------- ;
  275. % eff : Weight values reset in accordance with defining rules given in;
  276. % COSYMP.RED and further argumented in CODOPT.RED. ;
  277. % -------------------------------------------------------------------- ;
  278. if not(!:onep dm!-abs(iv))
  279. then setwght(x,((awght(x)-1).(mwght(x)-1)).(hwght(x)-4))
  280. else setwght(x,((awght(x)-1).mwght(x)).(hwght(x)-1));
  281. symbolic procedure upwght(x,iv);
  282. % -------------------------------------------------------------------- ;
  283. % arg : Row(column)index X. value IV. ;
  284. % eff : The weight of row X is adapted because an element with value IV;
  285. % is brought into the matrix. ;
  286. % -------------------------------------------------------------------- ;
  287. <<delhisto(x);
  288. upwght1(x,iv);
  289. inshisto(x)>>;
  290. symbolic procedure upwght1(x,iv);
  291. % -------------------------------------------------------------------- ;
  292. % eff : Functioning similar to Downwght1. ;
  293. % -------------------------------------------------------------------- ;
  294. if not(!:onep dm!-abs(iv))
  295. then setwght(x,((awght(x)+1).(mwght(x)+1)).min(hwght(x)+4,histolen))
  296. else setwght(x,((awght(x)+1).mwght(x)).min(hwght(x)+1,histolen));
  297. symbolic procedure initwght(x);
  298. % -------------------------------------------------------------------- ;
  299. % arg : Row(column)index X. ;
  300. % eff : The weight of row(column) X is initialized. ;
  301. % -------------------------------------------------------------------- ;
  302. begin scalar an,mn;
  303. an:=mn:=0;
  304. foreach z in zstrt(x) do
  305. if free(xind z)
  306. then
  307. << if not(!:onep dm!-abs(ival z)) then mn:=mn+1;
  308. an:=an+1>>;
  309. setwght(x,(an.mn).(an+3*mn));
  310. end;
  311. symbolic procedure remzzzz(zz1,zz2);
  312. % -------------------------------------------------------------------- ;
  313. % arg : Zstrt ZZ1 and ZZ2, where ZZ1 is a part of ZZ2. ;
  314. % res : All elements of ZZ2, without the elements of ZZ2. ;
  315. % -------------------------------------------------------------------- ;
  316. if null(zz1)
  317. then zz2
  318. else
  319. if yind(car zz1)=yind(car zz2)
  320. then remzzzz(cdr zz1,cdr zz2)
  321. else car(zz2).remzzzz(zz1,cdr zz2);
  322. symbolic procedure chdel(fa,x);
  323. % -------------------------------------------------------------------- ;
  324. % arg : Father Fa of child X. ;
  325. % eff : Child X is removed from the Chrow of Fa. ;
  326. % -------------------------------------------------------------------- ;
  327. setchrow(fa,delete(x,chrow fa));
  328. symbolic procedure delyzz(y,zz);
  329. % -------------------------------------------------------------------- ;
  330. % arg : Column(row)index Y. Zstrt ZZ. ;
  331. % res : Zstrt without the element corresponding with Y. ;
  332. % -------------------------------------------------------------------- ;
  333. if y=yind(car zz)
  334. then cdr(zz)
  335. else car(zz).delyzz(y,cdr zz);
  336. symbolic procedure clearrow(x);
  337. % -------------------------------------------------------------------- ;
  338. % arg : Rowindex X. ;
  339. % eff : Row X is cleared. This can be recognized since the father is ;
  340. % set to -1. ;
  341. % -------------------------------------------------------------------- ;
  342. <<setzstrt(x,nil);
  343. if x>=0
  344. then
  345. <<setchrow(x,nil);
  346. if not numberp(farvar x)
  347. then remprop(farvar x,'rowindex)
  348. >>;
  349. setwght(x,nil);
  350. setfarvar(x,-1)
  351. >>;
  352. % -------------------------------------------------------------------- ;
  353. % PART 2 : PROCEDURES FOR THE CONSTRUCTION OF THE MATRIX CODMAT,i.e. ;
  354. % FOR INPUT PARSING ;
  355. % -------------------------------------------------------------------- ;
  356. % ;
  357. % ------ GENERAL STRATEGY ------ ;
  358. % REDUCE assignment statements of the form "Nex:=Expression" are trans-;
  359. % formed into pairs (Nex,Ex(= prefixform of the Expression)), using ;
  360. % GENTRAN-facilities.The assignment operator := defines a literal trans;
  361. % lation of both Nex and Ex. Replacing this operator by :=: results in;
  362. % translation of the simplified form of Ex. When taking ::=: or ::= the;
  363. % Nex is evaluated before translation, i.e. the subscripts occurring in;
  364. % Nex are evaluated before the translation is performed. ;
  365. % Once input reading is completed(i.e. when calling CALC) the data- ;
  366. % structures can and have to be completed (column info and the like) ;
  367. % using SSETVARS (called in OPTIMIZE (see CODCTL.RED)) before the CSE- ;
  368. % search actually starts. ;
  369. % ;
  370. % ------ PRESUMED EXPRESSION STRUCTURE ------ ;
  371. % Each expression is considered to be an (exponentiated) sum,a product ;
  372. % or something else and to consist of an (eventually empty) primitive ;
  373. % part and an (also eventually empty) composite part. The primitive ;
  374. % part of a sum is a linear combination of atoms(variables) and its ;
  375. % composite part consists of terms which are products or functions. The;
  376. % primitive part of a product is a monomial in atoms and its composite ;
  377. % part is formed by factors which are again expressions(Think of OFF ;
  378. % EXP).Primitive parts are stored in Zstrts as lists of pairs (RCindex.;
  379. % COFEXP). Composite parts are stored in and via Chrows. ;
  380. % The RCindex denotes a Row(Column)index in CODMAT if the Zstrt defines;
  381. % a column(row). Rows describe primitive parts. Due to the assumption ;
  382. % that the commutative law holds column information is not completely ;
  383. % available as long as input processing is not finished. ;
  384. % Conclusion : Zstrts cannot be completed (by SSETVARS in CALC or in ;
  385. % HUGE (see CODCTL.RED)) before input processing is completed,i.e.tools;
  386. % to temporarily store Zstrt info are required. They consist of certain;
  387. % lists,which are built up during parsing, being : ;
  388. % The identifiers Varlst!+, Varlst!* and Kvarlst play a double role. ;
  389. % They are used as indicators in certain propertylists and also as glo-;
  390. % bal variables carrying information during parsing and optimization. ;
  391. % To distinguish between these two roles we quote the indicator name ;
  392. % in the comment given below. ;
  393. % -- Varlst!+ : A list of atoms occuring in primitive sum parts of the;
  394. % input expressions,i.e. variables used to construct the;
  395. % sum part of CODMAT. ;
  396. % -- 'Varlst!+ : The value of this indicator,associated with each atom ;
  397. % of Varlst!+, is a list of dotted pairs (X,IV),where X ;
  398. % is a rowindex and IV a coefficient,i.e.IV*atom occurs ;
  399. % as term of a primitive part of some input expression ;
  400. % defined by row X. ;
  401. % -- Varlst!* : Similar to Varlst!+ when replacing the word sum by mo-;
  402. % nomial and the word coefficient by exponent. ;
  403. % -- 'Varlst!* : The value of this indicator,occuring on the property ;
  404. % list of each element of Varlst!*, is a list of dotted;
  405. % pairs of the form (X.IV),where X is a rowindex and IV ;
  406. % an exponent,i.e. atom^IV occurs as factor in a mono- ;
  407. % mial,being a primitive (sub)product,defined through ;
  408. % row X. ;
  409. % Remark : Observe that it is possible that an atom possesses both ;
  410. % 'Varlst!+ and 'Varlst!*,i.e. plays a role in the + - and in the * - ;
  411. % part of CODMAT. ;
  412. % -- Kvarlst : A list of dotted pairs (var.F),where var is an identi-;
  413. % fier (system selected via FNEWSYM,if necessary) and ;
  414. % where F is a list of the form (Functionname . (First ;
  415. % argument ... Last argument)). The arguments are either;
  416. % atoms or composite,and in the latter case replaced by ;
  417. % a system selected identifier. This identifier is asso-;
  418. % ciated with the CODMAT-row which is used to define the;
  419. % composite argument. ;
  420. % Remark : Kvarlst is also used in CODPRI.RED to guaran-;
  421. % tee the F's to be printed in due time,i.e.directly ;
  422. % after all its composite arguments. ;
  423. % -- 'Kvarlst : This indicator is associated with each operator name ;
  424. % during input processing. Its value consists of a list ;
  425. % of pairs os the form (F.var). To avoid needless name- ;
  426. % selections this list if values is consulted whenever ;
  427. % necessary to see of an expression of the form F is ;
  428. % already associated with a system selected identifier. ;
  429. % As soon as input processing is completed the 'Kvarlst ;
  430. % values are removed. ;
  431. % -- Prevlst : This list is also constructed during input processing.;
  432. % It is a list of dotted pairs (Father.Child),where ;
  433. % Child is like Father a rowindex or a system selected ;
  434. % identifier name. Prevlst is employed,using SETPREV,to ;
  435. % store in the ORDR-field of CODMAT-rows relevant info ;
  436. % about the structure of the input expressions. During ;
  437. % the iterative CSE-search the ORDR-info is updated when;
  438. % ever necessary. ;
  439. % -- CodBexpl!*: A list consisting of CODMAT-row indices associated ;
  440. % with input expression toplevel(i.e. the FarVar-field ;
  441. % contains the expression name). ;
  442. % This list is used on output to obtain a correct input ;
  443. % reflection (see procedures MAKEPREFIXL and PRIRESULT ;
  444. % in CODCTL.RED). ;
  445. % ;
  446. % ------ PARSING PATHS and PROCEDURE CLASSIFICATION ------ ;
  447. % A prefix-form parsing is performed via FFVAR!!,FFVAR!* and FFVAR!+. ;
  448. % During parsing,entered via FFVAR!!, the procedure FVAROP is used to ;
  449. % analyse and transform functions( Operators in the REDUCE terminology);
  450. % and thus also to construct Kvarlst and Prevlst. FVAROP is indirectly ;
  451. % activated through the routines PVARLST!* and PVARLST!+, which assist ;
  452. % in preparing (')Varlst!* and (')Varlst!+,respectively. ;
  453. % FCOFTRM ,assisting in detecting prim.parts, is used in FFVAR!!2. ;
  454. % PPRINTF is used (in FFVAR!!) to obtain an input echo on the terminal ;
  455. % (when ON ACINFO, the default setting, holds). ;
  456. % RESTORECSEINFO serves to restore the CSE-info when combining the re- ;
  457. % sult of a previous session with the present one( see also CODCTL.RED);
  458. % SSETVARS,and thus SSETVARS1, serves to complete CODMAT once input ;
  459. % processing is finished. PREPMULTMAT is used to preprocess *-columns ;
  460. % if one of the exponents, occuring in it, is rational, i.e. when the ;
  461. % with this column corresponding indentifier has the flag Ratexp. ;
  462. % SETPREV is used for maintaining consistency in input expression orde-;
  463. % ring and thus for consequent information retrieval at a later stage, ;
  464. % such as during printing. ;
  465. % -------------------------------------------------------------------- ;
  466. global '(varlst!+ varlst!* kvarlst prevlst codbexl!* )$
  467. fluid '(preprefixlist prefixlist);
  468. varlst!+:=varlst!*:=kvarlst:=nil;
  469. % -------------------------------------------------------------------- ;
  470. % ------ THE PREFIX FORM PARSING ------ ;
  471. % FFvar!! is the main procedure activating parsing. Besides some house-;
  472. % keeping,information is send to either FFvar!* (either a product (but ;
  473. % not a prim. term) or a 'EXPT-application) or FFvar!+(a sum or a ;
  474. % function application). ;
  475. % The parsing is based on the following Prefix-Form syntax: ;
  476. % -------------------------------------------------------------------- ;
  477. % This syntax needs some revision!!! ;
  478. % -------------------------------------------------------------------- ;
  479. % <expression> ::= <sumform>|<productform> ;
  480. % <sumform> ::= <sum>|('EXPT <sum> <exponent>) ;
  481. % <productform> ::= <product>| ;
  482. % ('TIMES <constant> <factor>)| ;
  483. % ('TIMES <constant> <list of factors>)| ;
  484. % ('MINUS <productform>) ;
  485. % <sum> ::= <term>|('PLUS.<list of terms>) ;
  486. % <list of terms> ::= (<term> <term>)|(<term> <list of terms>) ;
  487. % <term> ::= <primitive term>|<productform>|<sumform> ;
  488. % <primitive term> ::= <constant>|<variable>| ;
  489. % ('TIMES <constant> <variable>)| ;
  490. % <function application> ;
  491. % <product> ::= <factor>|('TIMES.<list of factors>) ;
  492. % <list of factors> ::= (<factor> <factor>)|(<factor> <list of ;
  493. % factors>);
  494. % <factor> ::= <primitive factor>|<sumform>|<productform>;
  495. % <primitive factor> ::= <variable>|('EXPT <variable> <exponent>)| ;
  496. % <function application> ;
  497. % <function application> ::= <function symbol>.<list of expressions> ;
  498. % <function symbol> ::= identifier, where identifier is not ;
  499. % in {'PLUS,'TIMES,'EXPT,'MINUS,'DIFFERENCE,;
  500. % 'SQRT,dmode!*}. ;
  501. % Obvious elements are sin,cos,tan,etc. ;
  502. % The function applications are further ;
  503. % analyzed in FvarOp. ;
  504. % <list of expressions> ::= (<expression>)|<expression>.<list of ;
  505. % expressions>;
  506. % <variable> ::= element of the set of variable names, ;
  507. % either delivered as input or produced by ;
  508. % the Optimizer when the need to introduce :
  509. % cse-names exists. This is done with the ;
  510. % procedure FNewSym(see CODCTL.RED) which is;
  511. % initiated either using the result of the ;
  512. % procedure INAME(see CODCTL.RED) or simply ;
  513. % by using GENSYM(). ;
  514. % <constant> ::= element of the set of integers ;
  515. % representable by REDUCE | domain element ;
  516. % <exponent> ::= element of the set of integer an rational ;
  517. % numbers representable by REDUCE. ;
  518. % -------------------------------------------------------------------- ;
  519. symbolic procedure ffvar!!(nex,ex,prefixlist);
  520. % -------------------------------------------------------------------- ;
  521. % arg : An expression Ex in Prefix-Form, and its associated name NEx. ;
  522. % eff : The expression Ex is added to the incidence matrix CODMAT. ;
  523. % Parsing is based on the above given syntax. ;
  524. % -------------------------------------------------------------------- ;
  525. begin scalar n, nnex, argtype, var, s;
  526. prefixlist:=cons(nex,ex).prefixlist;
  527. % if nex memq '(cses gsym) % deleted : binf no more used. JB 13/4/94
  528. % then restorecseinfo(nex,ex)
  529. n:=rowmax:=rowmax+1;
  530. codbexl!*:=n.codbexl!*;
  531. if flagp(nex,'newsym)
  532. then put(nex,'rowindex,n);
  533. put(nex,'rowocc, list n);
  534. ffvar!!2(n,nex,remdiff ex);
  535. return prefixlist
  536. end;
  537. symbolic procedure restorecseinfo(nex,ex);
  538. % -------------------------------------------------------------------- ;
  539. % arg : Nex is an element of the set {CSES,GSYM,BINF} and Ex a corres- ;
  540. % pondig information carrier. ;
  541. % eff : RestoreCseInfo is called in FFvar!! when during input parsing ;
  542. % name Nex belongs to the above given set. In this case the input;
  543. % is coming from a file which is prepared during a previous run. ;
  544. % It contains all output from this previous run, preceded by ;
  545. % system prepared cse-info stored as value of the 4 system ;
  546. % variables CSES,GSYM and BINF (see the function SaveCseInfo in ;
  547. % CODCTL.RED for further information). ;
  548. % -------------------------------------------------------------------- ;
  549. begin scalar inb,nb,s;
  550. if nex eq 'cses
  551. then (if atom(ex) then flag(list ex,'newsym)
  552. else foreach el in cdr(ex) do flag(list el,'newsym))
  553. % Ammendments to increase robustness:
  554. % More strict control over what cse-name is going to be used,
  555. % starting from which index.
  556. % This prevents scope from generating a cse twice, thus overwriting
  557. % earlier occurrences and introducing strange erronous output.
  558. % JB 13/4/94
  559. else if eq(letterpart(ex),'g)
  560. then if eq((s:=letterpart fnewsym()),'g)
  561. then iname s
  562. else<< nb:=digitpart(ex);
  563. inb:=digitpart(fnewsym());
  564. for j:=inb:nb do gensym() >>
  565. else if eq(letterpart(ex), letterpart(s:= fnewsym())) and
  566. digitpart(ex) > digitpart(s)
  567. then iname ex
  568. else iname s
  569. end;
  570. symbolic procedure remdiff f;
  571. % -------------------------------------------------------------------- ;
  572. % Replace all occurrences of (DIFFERENCE A B) in F for arbitrary A and ;
  573. % B by (PLUS A (MINUS B)). ;
  574. % -------------------------------------------------------------------- ;
  575. if idp(f) or constp(f) then f
  576. else
  577. << if car(f) eq 'difference
  578. then f:=list('plus,remdiff cadr f,list('minus,remdiff caddr f))
  579. else car(f) . (foreach op in cdr(f) collect remdiff(op))
  580. >>;
  581. symbolic procedure ffvar!!2(n, nex, ex);
  582. % -------------------------------------------------------------------- ;
  583. % Serviceroutine used in FFvar!!. ;
  584. % -------------------------------------------------------------------- ;
  585. if eqcar(ex, 'times) and not fcoftrm ex
  586. then setrow(n, 'times, nex, ffvar!*(cdr ex, n), nil)
  587. else
  588. if eqcar(ex, 'expt) and (integerp(caddr ex) or rationalexponent(ex))
  589. then setrow(n, 'times, nex, ffvar!*(list ex, n), nil)
  590. else setrow(n, 'plus, nex, ffvar!+(list ex, n), nil);
  591. symbolic procedure fcoftrm f;
  592. % -------------------------------------------------------------------- ;
  593. % arg : A prefix form F. ;
  594. % res : T if F is a (simple) term with an integer coefficient, NIL ;
  595. % otherwise. ;
  596. % -------------------------------------------------------------------- ;
  597. (null(cdddr f) and cddr f) and
  598. (constp(cadr f) and not (pairp(caddr f) and
  599. caaddr(f) memq '(expt times plus difference minus)));
  600. symbolic procedure rationalexponent(f);
  601. % -------------------------------------------------------------------- ;
  602. % arg : F is an atom or a prefixform. ;
  603. % res : T if F is an 'EXPT with a rational exponent. ;
  604. % -------------------------------------------------------------------- ;
  605. rationalp caddr f;
  606. %(pairp caddr f) and (caaddr f eq 'quotient) and (integerp(cadr caddr f)
  607. % and integerp(caddr caddr f));
  608. symbolic procedure rationalp f;
  609. eqcar(f,'quotient) and integerp(cadr f) and integerp(caddr f);
  610. symbolic procedure ffvar!+(f,ri);
  611. % -------------------------------------------------------------------- ;
  612. % arg : F is a list of terms,i.e. th sum SF='PLUS.F is parsed. Info ;
  613. % storage starts in row RI resulting in ;
  614. % res : a list (CH) formed by all the indices of rows where the descrip;
  615. % tion of children(composite terms) starts. As a by product(via ;
  616. % eff : PVARLST!+) the required Zstrt info is made. ;
  617. % N.B.: Possible forms for the terms of SF( the elements of F) are: ;
  618. % -a sum - which is recursively managed after minus-symbol ;
  619. % distribution. ;
  620. % -a product - of the form constant*atom : which is as term of a ;
  621. % prim. sum treated by PVARLST!+. ;
  622. % of another form : which is managed via FFVAR!*. ;
  623. % -a constant ;
  624. % power - of a product of atoms : is transformed into a prim;
  625. % product and then treated as such. ;
  626. % of something else : is always parsed via FFVAR!*. ;
  627. % -a function- application is managed via PVARLST!+,i.e. via ;
  628. % FVAROP with additional Varlst!+ storage of system ;
  629. % selected subexpression names. ;
  630. % -------------------------------------------------------------------- ;
  631. begin scalar ch,n,s,b,s1,nn;
  632. foreach trm in f do
  633. <<b:=s:=nil;
  634. while pairp(trm) and (s:=car trm) eq 'minus do
  635. <<trm:=cadr trm;
  636. b:=not b>>;
  637. if s eq 'difference
  638. then
  639. <<trm:=list('plus,cadr trm,list('minus,caddr trm));
  640. s:='plus>>;
  641. if s eq 'plus
  642. then
  643. <<s1:=ffvar!+(if b
  644. then foreach el in cdr(trm) collect list('minus,el)
  645. else cdr trm,ri);
  646. ch:=append(ch,car s1)>>
  647. else
  648. if s eq 'times
  649. then
  650. <<% ------------------------------------------------------------ ;
  651. % Trm is a <productform>, which might have the form ;
  652. % ('TIMES <constant> <function application>). Here the ;
  653. % <function application> can be ('SQRT <expression>) , i.e. has;
  654. % to be changed into : ;
  655. % ('TIMES <constant> ('EXPT <expression> ('QUOTIENT 1 2))) ;
  656. % ------------------------------------------------------------ ;
  657. if pairp caddr trm and caaddr trm eq 'sqrt and null cdddr trm
  658. then
  659. trm := list('times,cadr trm,list('expt,cadr caddr trm,
  660. list('quotient,1,2)));
  661. if fcoftrm trm
  662. % ---------------------------------------------------------- ;
  663. % Trm is ('TIMES <constant> <variable>) ;
  664. % ---------------------------------------------------------- ;
  665. then pvarlst!+(caddr trm,ri,if b then dm!-minus(cadr trm)
  666. else cadr trm)
  667. else
  668. % ---------------------------------------------------------- ;
  669. % Trm is a <productform> ;
  670. % ---------------------------------------------------------- ;
  671. <<n:=rowmax:=rowmax+1;
  672. s1:=ffvar!*(cdr trm,n);
  673. if b
  674. then setrow(n,'times,ri,list(car s1,dm!-minus cadr s1),nil)
  675. else setrow(n,'times,ri,s1,nil);
  676. ch:=n.ch>>
  677. >>
  678. else
  679. <<if s eq 'sqrt
  680. then
  681. % ---------------------------------------------------------- ;
  682. % Trm is a <primitive term> which is a <function application>;
  683. % which is ('SQRT <expression>) which is of course ;
  684. % ('EXPT <expression> <exponent>) ;
  685. % ---------------------------------------------------------- ;
  686. <<trm := cons('expt,cons(cadr trm,list list('quotient,1,2)));
  687. s := 'expt
  688. >>;
  689. if s eq 'expt and eqcar(caddr trm,'minus) and
  690. (integerp(cadr caddr trm) or rationalp(cadr caddr trm))
  691. then
  692. << trm:=list('quotient,1,list('expt,cadr trm,cadr caddr trm));
  693. s:='quotient
  694. >>;
  695. if s eq 'expt and
  696. (integerp(caddr trm) or rationalexponent(trm))
  697. then
  698. <<n:=rowmax:=rowmax+1;
  699. s1:=ffvar!*(list trm,n);
  700. if b
  701. then setrow(n,'times,ri,list(car s1,-1),nil)
  702. else setrow(n,'times,ri,s1,nil);
  703. ch:=n.ch
  704. >>
  705. else pvarlst!+(trm,ri,if b then -1 else 1)
  706. >>;
  707. >>;
  708. return list(ch)
  709. end;
  710. symbolic procedure pvarlst!+(var,x,iv);
  711. % -------------------------------------------------------------------- ;
  712. % arg : Var is one of the first 2 alternatives for a kernel,i.e. a vari;
  713. % able or an operator with a simplified list of arguments (like ;
  714. % sin(x)) with a coefficient IV,belonging to a Zstrt which will ;
  715. % be stored in row X. ;
  716. % eff : If the variable happens to be a constant a special internal var;
  717. % !+ONE is introduced to assist in defining the constant contribu;
  718. % tions to primitive sumparts in accordance with the chosen data-;
  719. % structures. ;
  720. % When Var is an operator(etc.) Fvarop is used for a further ana-;
  721. % lysis and a system selected name for var is returned. Then this;
  722. % name,!+ONE or the variable name Var are used to eventually ;
  723. % extend Varlst!+ with a new name.The pair (rowindex.coeff.value);
  724. % is stored on the property list of this var as pair of the list ;
  725. % 'Varlst!+,which is used in SSETVARS1 to built the Zstrts associ;
  726. % ated with this variable. ;
  727. % -------------------------------------------------------------------- ;
  728. begin scalar l,s,nvar;
  729. if constp var then <<iv:=dm!-times(iv,var); var:='!+one>>;
  730. if not (idp(var) or constp(var)) then var:=fvarop(var,x);
  731. if null(s:=get(var,'varlst!+)) then varlst!+:=var.varlst!+;
  732. put(var,'varlst!+,(x.iv).s)
  733. end;
  734. symbolic procedure ffvar!*(f,ri);
  735. % -------------------------------------------------------------------- ;
  736. % arg : F is a list of factors,i.e. the product PF='TIMES.F is parsed. ;
  737. % Info storage starts in row RI,resulting in ;
  738. % res : a list (CH COF),where CH is a list of all the indices of rows ;
  739. % where the description of children of PF(composite factors) ;
  740. % eff : starts. As a by product(via the procedure PVARLST!*) Zstrt info;
  741. % is made. ;
  742. % N.B.: Possible forms for the factors of PF( the elements of F) are: ;
  743. % -a constant- contributing as factor to COF. ;
  744. % -a variable- contributing as factor to a prim.product,stored in;
  745. % a Zstrt(via SSETVARS) after initial management via;
  746. % PVARLST!* and storage in Varlst!* and 'Varlst!*'s.;
  747. % -a product - Recursively managed via FFVAR!*,implying that CH:=;
  748. % Append(CH,latest version created via FFVAR!* and ;
  749. % denoted by Car S). ;
  750. % -a sum - (or difference or negation) contributing as comp. ;
  751. % factor and demanding a subexpression row N to ;
  752. % start its description. Storage management is done ;
  753. % via FFVAR!+,implying that CH:=N.CH. ;
  754. % -a power - of the form sum^integer : and managed like a sum. ;
  755. % of the form atom^integer: and managed like single ;
  756. % atom as part of a prim. product. ;
  757. % -a function- application,which is managed via PVARLST!*,i.e.via;
  758. % FVAROP with additional Varlst!* storage of system ;
  759. % selected subexpression names. ;
  760. % -------------------------------------------------------------------- ;
  761. begin scalar cof,ch,n,s,b,rownr,pr,nr,dm;
  762. cof:=1;
  763. foreach fac in f do
  764. if constp fac
  765. then cof:=dm!-times(fac,cof)
  766. else
  767. if atom fac
  768. then pvarlst!*(fac,ri,1)
  769. else
  770. if (s:=car fac) eq 'times
  771. then
  772. <<s:=ffvar!*(cdr fac,ri);
  773. ch:=append(ch,car s);
  774. cof:=dm!-times(cof,cadr(s))
  775. >>
  776. else
  777. if s memq '(plus difference minus)
  778. then
  779. << if s eq 'minus and constp(cadr fac) and null cddr fac
  780. then cof:=dm!-minus dm!-times(cof,cadr(fac))
  781. else <<n:=rowmax:=rowmax+1;
  782. if (not b) then <<b:=t; rownr:=n>>;
  783. setrow(n,'plus,ri,ffvar!+(list fac,n),nil);
  784. ch:=n.ch
  785. >>
  786. >>
  787. else
  788. <<if s eq 'sqrt
  789. then
  790. % -------------------------------------------------------- ;
  791. % The primitive factor is a <function application>. In this;
  792. % case a ('SQRT <expression>) which is of course ;
  793. % ('EXPT <expression> ('QUOTIENT 1 2)). ;
  794. % -------------------------------------------------------- ;
  795. <<fac:=cons('expt,cons(cadr fac,list list('quotient,1,2)));
  796. s:='expt
  797. >>;
  798. if s eq 'expt and eqcar(caddr fac,'minus) and
  799. (integerp(cadr caddr fac) or rationalp(cadr caddr fac))
  800. then
  801. <<fac:=list('quotient,1,
  802. list('expt,cadr fac,cadr caddr fac));
  803. s:='quotient
  804. >>;
  805. if s eq 'expt and
  806. (integerp(caddr fac) or (nr:=rationalexponent(fac)))
  807. then % --------------------------------------------------- ;
  808. % Fac = (EXPT <expression or variable> ;
  809. % <integer or rational number>) ;
  810. % --------------------------------------------------- ;
  811. (if pairp(cadr fac) and caadr(fac) eq 'sqrt
  812. then
  813. << if nr then <<nr:=cadr caddr fac;
  814. dm:=2*(caddr caddr fac)>>
  815. else <<nr:=1; dm:=2>>;
  816. pvarlst!*(cadr cadr fac,ri,cons(nr,dm))
  817. >>
  818. else
  819. pvarlst!*(cadr fac,ri,
  820. if integerp(caddr fac)
  821. then caddr fac
  822. else (cadr caddr fac . caddr caddr fac)))
  823. else pvarlst!*(fac,ri,1)
  824. >>;
  825. if b and not(!:onep dm!-abs(cof))
  826. then
  827. % ---------------------------------------------------------------- ;
  828. % The product Cof*....*(c1*a+....+cn*z) is replaced by ;
  829. % the product ....*({Cof*c1}*a+...+{Cof*cn}*z), assuming Cof, c1,..;
  830. % ..,cn are numerical constants. ;
  831. % ---------------------------------------------------------------- ;
  832. << foreach el in chrow(rownr) do
  833. setexpcof(el,dm!-times(cof,expcof(el)));
  834. foreach var in varlst!+ do
  835. if (pr:=assoc(rownr,get(var,'varlst!+)))
  836. then rplacd(pr,dm!-times(cdr(pr),cof));
  837. cof:=1;
  838. >>;
  839. return list(ch,cof)
  840. end;
  841. symbolic procedure pvarlst!*(var,x,iv);
  842. % -------------------------------------------------------------------- ;
  843. % eff : Similar to Pvarlst!+. ;
  844. % : The flag Ratexp is associated with Var if one of its exponents;
  845. % is rational. This flag is used in the function PrepMultMat. ;
  846. % -------------------------------------------------------------------- ;
  847. begin scalar l,s,bvar,bval;
  848. if constp(var)
  849. then
  850. << var:=fvarop(if iv='(1 . 2)
  851. then list('sqrt,var)
  852. else list('expt,var,
  853. if pairp iv
  854. then list('quotient,car iv,cdr iv)
  855. else iv),x);
  856. iv:=1
  857. >>;
  858. if not(atom(var) or constp(var))
  859. then << s:=get('!*bases!*,'kvarlst);
  860. if s then bvar:=assoc(bval:=reval var,s);
  861. if bvar then var:=cdr bvar
  862. else << var:=fvarop(var,x);
  863. put('!*bases!*,'kvarlst,(bval.var).s)
  864. >>
  865. >>;
  866. if null(s:=get(var,'varlst!*)) then varlst!*:=var.varlst!*;
  867. if pairp(iv) and not(constp iv) then flag(list(var),'ratexp);
  868. put(var,'varlst!*,(x.iv).s)
  869. end;
  870. symbolic procedure fvarop(f,x);
  871. % ------------------------------------------------------------------- ;
  872. % arg : F is a prefixform, being <operator>.<list of arguments>. X is ;
  873. % the index of the CODMAT row where the description of F has to ;
  874. % start. ;
  875. % ------------------------------------------------------------------- ;
  876. begin scalar svp,varf,valf,n,fargl,s,b;
  877. if eqcar(f,'sqrt) and not(constp(cadr f))
  878. then f:=list('expt,cadr f,list('quotient,1,2));
  879. b:=(not (car f memq '(plus minus times expt)))
  880. or
  881. (car(f) eq 'expt
  882. and
  883. (not (numberp(caddr f) or rationalexponent(f))
  884. or
  885. ((cadr(f) eq 'e) or constp(cadr(f)))));
  886. svp:=subscriptedvarp car f;
  887. s:=get(car f, 'kvarlst);
  888. %------------------------------------------------------------
  889. % b tells us whether f is a regular function (NIL) or
  890. % not (T). So b=T for everything but ye ordinary expressions.
  891. % We've got to check whether we deal with an array variable
  892. % and if so, whether there is a valid cse-name for this
  893. % variable.
  894. % We also want to recognize a valid index-expression, for
  895. % wich `not b' holds.
  896. %------------------------------------------------------------
  897. varf := if svp then assoc(ireval(f),s)
  898. else assoc(f,s);
  899. if (varf and svp) or
  900. (b and varf and allconst(cdr f, cdr varf))
  901. %---------------------------------------------------------
  902. % This condition states that in order to allow the current
  903. % and a previous expression to be regarded as equal, the
  904. % expression should denote a subscripted variable, or a
  905. % use of an function with constant parameters, i.e.
  906. % numerical parameters.
  907. %---------------------------------------------------------
  908. then varf:=cdr varf
  909. else
  910. << varf:=fnewsym();
  911. put(car f,'kvarlst,((if svp then ireval f else f).varf).s);
  912. if not b
  913. then
  914. << put(varf,'rowindex,n:=rowmax:=rowmax+1);
  915. if not(eqcar(f,'expt) and
  916. rationalexponent(f) or flagp(cadr f,'ratexp))
  917. then prevlst:=(x.n).prevlst;
  918. ffvar!!2(n,varf,f)
  919. >>
  920. else
  921. << if not (!*vectorc and svp)
  922. then << foreach arg in cdr(f) do
  923. if not(constp(arg) or atom(arg))
  924. then fargl:=fvarop(if svp then reval arg
  925. else arg,x).fargl
  926. else fargl:=arg.fargl;
  927. f:=car(f).reverse(fargl);
  928. >>;
  929. kvarlst:=(varf.f).kvarlst
  930. >>
  931. >>;
  932. prevlst:=(x.varf).prevlst;
  933. return varf
  934. end;
  935. symbolic procedure allconst (l,f);
  936. not (nil member foreach el in l collect jbconstp (el,f));
  937. symbolic procedure jbconstp (item,ref);
  938. if constp item
  939. then % some numerical value
  940. T
  941. else if atom item
  942. then % some id
  943. if get(item,'rowocc)
  944. then % item parsed as lefthandside.
  945. if (car(get(item,'rowocc))< findvardef(ref))
  946. then % This use and the previous are in the
  947. % scope of one definition of item.
  948. T
  949. else % This use and the previous are in
  950. % scopes of diferent definitions of
  951. % item.
  952. NIL
  953. else % some input id used twice ore more on rhs.
  954. T
  955. else not(NIL member foreach el in cdr item
  956. collect jbconstp(el,ref));
  957. symbolic procedure findvardef v;
  958. begin
  959. scalar r,vp,vt;
  960. r:=get(v,'rowocc);
  961. vt:=get(v,'varlst!*);
  962. vp:=get(v,'varlst!+);
  963. if r
  964. then r:= car r
  965. else if vt
  966. then if vp
  967. then
  968. if ((vt := caar reverse vt) > (vp := caar reverse vp))
  969. then r:= vt
  970. else r:= vp
  971. else r:= caar reverse vt
  972. else r:= caar reverse vp;
  973. return r;
  974. end;
  975. symbolic procedure ssetvars(preprefixlist);
  976. % -------------------------------------------------------------------- ;
  977. % eff : The information stored on the property lists of the elements of;
  978. % the lists Varlst!+ and Varlst!* is stored in the matrix CODMAT,;
  979. % i.e.the Z-streets are produced via the SSetvars1 calls. ;
  980. % Before doing so PrepMultMat is used to modify, if necessary,the;
  981. % Varlst!* information by incorporating information about ratio- ;
  982. % nal exponents. ;
  983. % Furthermore the elements of Prevlst are used to store the hier-;
  984. % archy information in the ORDR-fields in the matrix CODMAT. In ;
  985. % addition some bookkeeping activities are performed: Needless ;
  986. % information is removed from property lists and not longer need-;
  987. % ed lists are cleared. EndMat is also initialized. ;
  988. % -------------------------------------------------------------------- ;
  989. <<
  990. preprefixlist:=prepmultmat(preprefixlist);
  991. %--------------------------------------------------------------------
  992. % From now on preprefixlist has the following structure :
  993. %
  994. % ((var1 aliases )(var2 aliases )...)
  995. %
  996. %--------------------------------------------------------------------
  997. ssetvars1('varlst!+,'plus);
  998. ssetvars1('varlst!*,'times);
  999. varlst!+:=varlst!*:=nil;
  1000. foreach el in reverse(prevlst) do setprev(car el,cdr el);
  1001. foreach el in kvarlst do remprop(cadr el,'kvarlst);
  1002. foreach el in '(plus minus difference times sqrt expt) do
  1003. remprop(el,'kvarlst);
  1004. remprop('!*bases!*,'kvarlst);
  1005. endmat:=rowmax;
  1006. preprefixlist
  1007. >>;
  1008. symbolic procedure revise2 (f,d);
  1009. begin
  1010. scalar res;
  1011. if atom f
  1012. then if constp f
  1013. then return f
  1014. else if get(f,'aliaslist)
  1015. then return get(f,'finalalias)
  1016. else << if not(member(f,known))
  1017. then known:=f . known;
  1018. return f;
  1019. >>
  1020. else if not constp f
  1021. then % car f is operator or indexed var
  1022. if subscriptedvarp car f
  1023. then % We have to search d to rewrite f.
  1024. % Then we check `known' for an alias.
  1025. if get(car f,'aliaslist)
  1026. then <<f:= car f . foreach el in cdr ireval f
  1027. collect revise2 (el,d);
  1028. if (res:=assoc(f,get(car f,'finalalias)))
  1029. then return cadr res
  1030. else if !*vectorc
  1031. then % rhs-alias introduction.
  1032. <<rhsaliases :=
  1033. (introduce!-alias f . f)
  1034. . rhsaliases;
  1035. return caar rhsaliases>>
  1036. else return f >>
  1037. else if !*vectorc
  1038. then % rhs-alias introduction.
  1039. <<rhsaliases := (introduce!-alias f . f) .
  1040. rhsaliases;
  1041. return caar rhsaliases>>
  1042. else return f
  1043. else if res:=assoc(f,d)
  1044. then return cadr res
  1045. else return car f . foreach el in cdr f
  1046. collect revise2 (el,d)
  1047. else return f;
  1048. end;
  1049. symbolic procedure revise (f,d);
  1050. car f . (cadr f . foreach l in cddr f collect revise2 (l,d));
  1051. symbolic procedure preremdep forms;
  1052. %----------------------------------------------------------------------
  1053. % We remove dependencies and indexed variables in forms by introducing
  1054. % aliases.
  1055. % ABOUT ALIASES.
  1056. %
  1057. % In search for common subexpressions, scope does not, ironically,
  1058. % bother for rules of scope. This means that :
  1059. %
  1060. % a:=x+y
  1061. % ..
  1062. % a:=cos(x)
  1063. % z:=x+y
  1064. %
  1065. % is going to be optimized into:
  1066. %
  1067. % a:=x+y,
  1068. % ..
  1069. % a:=cos(x),
  1070. % z:=a.
  1071. %
  1072. % We solve this anomaly by replacing every occurrence of `a', starting
  1073. % from the second definition, by a generated name; so
  1074. %
  1075. % a := ...
  1076. % := ... a ...
  1077. % a := ... a ...
  1078. % a := ...
  1079. % := ... a ...
  1080. %
  1081. % becomes :
  1082. %
  1083. % a := ...
  1084. % := ... a ...
  1085. % a1:= ... a ...
  1086. % a2:= ...
  1087. % := ... a2 ...
  1088. %
  1089. % This prevents scope from finding c.s.e.'s where there aren't any. At
  1090. % the end of the optimization process, these aliases are backsubstitu-
  1091. % ted, with their original values, (provided these are atomic!)
  1092. % Secondly the aliasmechanism is usefull in the storage process:
  1093. % When dealing with nonatomic, i.e. subscripted variables, problems
  1094. % arise in storing these variables in codmat, and putting all kind of
  1095. % info as properties on them. A variable is subscripted when declared
  1096. % as such by the option `declare' or `vectorcode', or when encountered
  1097. % as lhs of an assignment.
  1098. % We alias subscripted variables by an atomic, generated variable:
  1099. %
  1100. % a(i) := ...
  1101. % ... := ... a(i) ...
  1102. %
  1103. % becomes:
  1104. %
  1105. % g1 := ...
  1106. % ... := ... g1 ...
  1107. %
  1108. % When the indexexpressions are not atomic, i.e. they could be or con-
  1109. % tain c.s.e.'s, we put an assignment right in front of their first
  1110. % use (when the switch VECTORC is off!!!):
  1111. %
  1112. % a(x+y):= ...
  1113. % ... := ... a(x+y) ...
  1114. %
  1115. % becomes:
  1116. %
  1117. % g0 := x+y
  1118. % g1 := ...
  1119. % ... := ... g1 ...
  1120. %
  1121. % We only backsubstitute the output-definition of a sub'ted variable,
  1122. % i.e. the last definition, thus saving some memorymanagementoverhead.
  1123. % Atomic originals are all backsubstituted, for economy in allocation
  1124. % of variables.
  1125. %
  1126. % TECHNICAL DETAILS ALIASMECHANISM
  1127. %
  1128. % Aliasing is performed by a double linking mechanism:
  1129. % The original has properties `aliaslist'(a list of all aliases for
  1130. % this variable) and `finalalias' (the alias to be used in the current
  1131. % or final scope).
  1132. %
  1133. % Original ------[finalalias]--------> Aliasxx
  1134. % | <-----[alias ]---------/ ^
  1135. % | |
  1136. % [aliaslist] |
  1137. % | |
  1138. % *------------------------------------/
  1139. % |
  1140. % *-------------------------------> Aliasyy
  1141. % | .
  1142. % . .
  1143. % | .
  1144. % *-------------------------------> Aliaszz
  1145. %
  1146. % All aliases of the original are linked to the original by their
  1147. % property `alias' with value Original. (This is left out of above pic.
  1148. % for Aliasyy .. Aliaszz.)
  1149. % Finally, all generated assignments, stemming from indexexpressions,
  1150. % have the property `inalias', which links them to the variable they
  1151. % arose from. This property can be updated during optimization, or even
  1152. % be copied onto other variables, due to finding of c.s.e.'s.
  1153. %
  1154. % Generated Assignment:
  1155. % Aliasxx := indexexpression.
  1156. % |
  1157. % [ inalias ]
  1158. % |
  1159. % V
  1160. % Original: <----[alias]---Aliasyy
  1161. % A(.., Aliasxx, ..)
  1162. %
  1163. % All variables generated in the aliasing process obtain a flag
  1164. % `aliasnewsym'.
  1165. % All aliasinfo is removed after the optimization process.
  1166. %----------------------------------------------------------------------
  1167. begin
  1168. scalar defs,var,alias,res,currall;
  1169. known:=nil;
  1170. foreach f in forms do
  1171. <<if !*inputc then pprintf(caddr f,cadr f);
  1172. if !*complex then f := remcomplex f;
  1173. if not(cadr f member '(cses gsym))
  1174. then
  1175. if car f member '(equal setq)
  1176. then << f:=revise(f,defs);
  1177. if atom(var:=cadr f)
  1178. then <<if member(var,known)
  1179. then % This is a redefinition.
  1180. % Introduce an alias
  1181. << alias:=introduce!-alias var;
  1182. rplaca(cdr f,alias);
  1183. %remflag(list alias,'newsym);
  1184. >>
  1185. else known:= var . known;
  1186. res:=f . res;
  1187. >>
  1188. else if !*vectorc or flagp(car var, 'vectorvar)
  1189. then % Switch vectorc is set,or this is just
  1190. % `vectorcode-marked' variable.
  1191. % No further analization of var needed.
  1192. % For output purposes we apply remdiff to
  1193. % the subscripts.
  1194. % Then just introduce aliases.
  1195. <<flag(list car var,'subscripted);
  1196. var :=(car var). foreach idx in cdr var
  1197. collect remdiff idx;
  1198. alias:=introduce!-alias var;
  1199. rplaca(cdr f,alias);
  1200. res:= f . res;
  1201. >>
  1202. else % Introduce cse's for the non-atomic
  1203. % index-expressions,
  1204. % prepend this to current assignment and
  1205. % introduce its alias.
  1206. <<flag(list car var, 'subscripted);
  1207. var:= car var .
  1208. foreach ie in cdr var collect
  1209. if not atom ie
  1210. then<<if assoc((ie:=ireval ie),defs)
  1211. then alias:= cadr assoc(ie,defs)
  1212. else
  1213. <<alias:=fnewsym();
  1214. res:= list('setq,alias,ie)
  1215. . res;
  1216. defs:=list(ie,alias) . defs;
  1217. currall:= alias . currall;
  1218. flag(list alias,'aliasnewsym);
  1219. %remflag(list alias,'newsym);
  1220. >>;
  1221. alias
  1222. >>
  1223. else ie;
  1224. alias:=introduce!-alias ireval var;
  1225. foreach a in currall
  1226. do put(a,'inalias,
  1227. alias . get(a,'inalias));
  1228. rplaca(cdr f,alias);
  1229. res:= f . res;
  1230. >>
  1231. >>
  1232. else res:= f . res
  1233. else restorecseinfo(cadr forms, caddr forms)
  1234. >>;
  1235. restoreall;
  1236. return reverse res;
  1237. end;
  1238. symbolic procedure introduce!-alias var;
  1239. % Introduce an alias for var;
  1240. begin
  1241. scalar alias,v2;
  1242. alias:=fnewsym();
  1243. remflag(list alias,'newsym);
  1244. flag(list alias, 'aliasnewsym);
  1245. v2:= if atom var then var else car var;
  1246. put(v2,'aliaslist,
  1247. alias . get(v2,'aliaslist));
  1248. if atom var
  1249. then put(var,'finalalias,alias)
  1250. else %-----------------------------------------------------------
  1251. % An subscripted var can have a finalalias for several
  1252. % entries.
  1253. %-----------------------------------------------------------
  1254. put(v2,'finalalias,
  1255. list(var,alias)
  1256. . delete(assoc(var, get(v2,'finalalias)),
  1257. get(v2,'finalalias)));
  1258. put(alias,'alias,var);
  1259. known:=alias . known;
  1260. return alias;
  1261. end;
  1262. symbolic procedure ssetvars1(varlst,opv);
  1263. % -------------------------------------------------------------------- ;
  1264. % eff : Zstrt's are completed via a double loop and association of ;
  1265. % column indices(if necessary for both the + and the * part of ;
  1266. % CODMAT) with the var's via storage on the var property lists. ;
  1267. % -------------------------------------------------------------------- ;
  1268. begin scalar z,zz,zzel;
  1269. %foreach var in lispeval(varlst) do
  1270. foreach var in eval(varlst) do
  1271. <<zz:=nil;
  1272. rowmin:=rowmin-1;
  1273. foreach el in get(var,varlst) do
  1274. <<z:=mkzel(rowmin,cdr el);
  1275. if null(zzel:=zstrt car el) or not(xind(car zzel)=rowmin)
  1276. % To deal with X*X OR X+X;
  1277. then setzstrt(car el,z.zzel);
  1278. zz:=inszzz(mkzel(car el,val z),zz)
  1279. >>;
  1280. put(var,varlst,rowmin); % Save column index for later use;
  1281. setrow(rowmin,opv,var,nil,zz)
  1282. >>;
  1283. end;
  1284. symbolic procedure prepmultmat(preprefixlist);
  1285. % -------------------------------------------------------------------- ;
  1286. % eff : The information concerning rational exponents and stored in the;
  1287. % Varlst!* lists is used to produce exact integer exponents,to be;
  1288. % stored in the Z-streets of the matrix Codmat: ;
  1289. % For all elements in Varlst!* the Least Common Multiplier (LCM) ;
  1290. % of their exponent-denominators is computed. ;
  1291. % If LCM > 1 the element has a rational exponent. The exponent of;
  1292. % each element is re-calculated to obtain LCM * the orig. exp. ;
  1293. % Modulo LCM arithmetic is used to spread information over 2 ;
  1294. % varlst!*'s, one for the original var(iable) and another for the;
  1295. % fraction-part left. ;
  1296. % Renaming is adequately introduced when necessary. ;
  1297. % -------------------------------------------------------------------- ;
  1298. begin scalar tlcm,var,varexp,kvl,kfound,pvl,pfound,tel,ratval,ratlst,
  1299. newvarlst,hvarlst;
  1300. hvarlst:= nil;
  1301. while not null (varlst!*) do
  1302. <<var := car varlst!*; varlst!* := cdr varlst!*;
  1303. if flagp(var,'ratexp)
  1304. then
  1305. <<tlcm:=1;
  1306. remflag(list var,'ratexp);
  1307. foreach elem in get(var,'varlst!*) do
  1308. if pairp cdr elem then tlcm := lcm2(tlcm,cddr elem);
  1309. varexp:=fnewsym();
  1310. tel:=(varexp.(if tlcm = 2
  1311. then list('sqrt,var)
  1312. else list('expt,var,
  1313. if onep cdr(tel:=simpquot list(1,tlcm)) then
  1314. car tel
  1315. else
  1316. list('quotient,car tel,cdr tel))));
  1317. if assoc(var,kvarlst)
  1318. then
  1319. <<kvl:=kfound:=nil;
  1320. while kvarlst and not(kfound) do
  1321. if caar(kvarlst) eq var
  1322. then
  1323. << kvl:=tel.kvl; kfound:=t;
  1324. pvl:=pfound:=nil; prevlst:=reverse(prevlst);
  1325. while prevlst and not(pfound) do
  1326. if cdar(prevlst) eq var
  1327. then << pvl:=cons(caar prevlst,varexp).pvl;
  1328. pfound:=t
  1329. >>
  1330. else << pvl:=car(prevlst).pvl;
  1331. prevlst:=cdr(prevlst)
  1332. >>;
  1333. if pvl then
  1334. if prevlst then prevlst:=append(reverse prevlst,pvl)
  1335. else prevlst:=pvl
  1336. >>
  1337. else
  1338. << kvl:=car(kvarlst).kvl; kvarlst:=cdr kvarlst>>;
  1339. if kvl then
  1340. if kvarlst then kvarlst:=append(reverse kvl,kvarlst)
  1341. else kvarlst:=reverse kvl
  1342. >>
  1343. else preprefixlist:=tel.preprefixlist;
  1344. ratlst:=newvarlst:=nil;
  1345. foreach elem in get(var,'varlst!*) do
  1346. if pairp cdr elem
  1347. then
  1348. << ratval:=divide((tlcm * cadr elem)/(cddr elem),tlcm);
  1349. ratlst:=cons(car elem,cdr ratval).ratlst;
  1350. if car(ratval)>0
  1351. then newvarlst:=cons(car elem,car ratval).newvarlst
  1352. >>
  1353. else newvarlst:=elem.newvarlst;
  1354. if ratlst
  1355. then << put(varexp,'varlst!*,reverse ratlst);
  1356. hvarlst:=varexp.hvarlst
  1357. >>;
  1358. if newvarlst
  1359. then << put(var,'varlst!*,reverse newvarlst);
  1360. hvarlst:=var.hvarlst
  1361. >>
  1362. else remprop(var,'varlst!*)
  1363. >>
  1364. else hvarlst:=var.hvarlst
  1365. >>;
  1366. varlst!* := hvarlst;
  1367. return preprefixlist
  1368. end;
  1369. symbolic procedure lcm2(a,b);
  1370. % ---
  1371. % Switch rounded off before calling lcm.
  1372. % lcm doesn't seem to work in rounded mode
  1373. % for lcm
  1374. % ---
  1375. begin scalar g, res;
  1376. g := gcd2(a,b);
  1377. res := a*b;
  1378. return res/g;
  1379. end;
  1380. % -------------------------------------------------------------------- ;
  1381. % ORDERING OF (SUB)EXPRESSIONS : ;
  1382. % -------------------------------------------------------------------- ;
  1383. % It is based op the presumption that the ordering of the input expres-;
  1384. % sions has to remain unchanged when attempting to optimize their des- ;
  1385. % cription. This ordering is stored in the list CodBexl!* via FFVAR ;
  1386. % and used in the procedure MAKEPREFIXL( via PRIRESULT and also given ;
  1387. % in CODCTL.RED) for managing output. Hence any subexpression found by ;
  1388. % whatever means has to be inserted in the latest version of the ;
  1389. % description of the set ahead of the first expression in which it ;
  1390. % occurs and assuming its occurences are replaced by a system selected ;
  1391. % name which is also used as subexpression recognizer(i.e., as assigned;
  1392. % var). We distinguish between different types of subexpressions: ;
  1393. % Some are directly recognizable : sin(x),a(1,1) and the like. Others ;
  1394. % need optimizer searches to be found: sin(a+2*b),f(a,c,d+g(a)),etc. ;
  1395. % Via FVAROP an expression like sin(x) is replaced by a system selected;
  1396. % name(g001,for instance),the pair (g001.sin(x)) is added to the ;
  1397. % Kvarlst, the pair (sin(x).g001) is added to the 'Kvarlst of sin,thus ;
  1398. % allowing a test to be able to uniquely use the name g001 for sin(x). ;
  1399. % Finally the pair (rowindex of father of this occurence of sin(x) . ;
  1400. % g001) is added to Prevlst. However if the argument of a sin applica- ;
  1401. % tion is not directly recognizable(a*b+a*c or a*(b+c),etc) the argu- ;
  1402. % ment is replaced by a system selected name(g002,for instance),which ;
  1403. % then needs incorporation in the administration. This is also done in ;
  1404. % FVAROP: The index of the CODMAT-row used to start the description of ;
  1405. % this argument is stored on the property list of g002 as value of the ;
  1406. % indicator Rowindex and the Prevlist is now extended with the pair ;
  1407. % (father indx. g002 indx).When storing nested expressions in CODMAT ;
  1408. % the father-child relations based on interchanges of + and * symbols ;
  1409. % are treated in a similar way.So the Prevlst consists of two types of ;
  1410. % pairs: (row number.row number) and (row number.subexpression name). ;
  1411. % The CODMAT-row, where the description of this subexpression starts ;
  1412. % can be found on the property list of the subexpression name as value ;
  1413. % of the indicator Rowindex. All function applications are stored uni- ;
  1414. % quely in Kvarlst. This list is consulted in CODPRI.RED when construc-;
  1415. % ting PREFIXLIST,which represents the result as a list of dotted pairs;
  1416. % of the form ((sub)expr.name . (sub)expr.value) as to guarantee a cor-;
  1417. % rect insertion of the function appl.,i.e. directly ahead of the first;
  1418. % (sub)expr. it is part of.After inserting the pair (subexpression name;
  1419. % . function application) the corresponding description is removed from;
  1420. % the Kvarlst,thus avoiding a multiple insertion. This demands for a ;
  1421. % tool to know when to consult the Kvarlst.This is provided by the ORDR;
  1422. % field of the CODMAT-rows.It contains a list of row indices and func- ;
  1423. % tion application recognizers, which is recursively built up when ;
  1424. % searching for subexpressions,after its initialization in SSETVARS, ;
  1425. % using the subexpression recognizers introduced during parsing. ;
  1426. % -------------------------------------------------------------------- ;
  1427. symbolic procedure setprev(x,y);
  1428. % -------------------------------------------------------------------- ;
  1429. % arg : Both X and Y are rowindices. ;
  1430. % eff : Y is the index of a row where the description of a subexpr. ;
  1431. % starts. If X is the index of the row where the description of a;
  1432. % toplevel expression starts( an input expression recognizable by;
  1433. % the father-field Farvar) Y is put on top of the list of indices;
  1434. % of subexpressions which have to be printed ahead of this top- ;
  1435. % level expression.Otherwise we continue searching for this top- ;
  1436. % level father via a recursive call of SetPrev. ;
  1437. % -------------------------------------------------------------------- ;
  1438. if numberp(farvar x)
  1439. then setprev(farvar x,y)
  1440. else setordr(x,y.ordr(x));
  1441. endmodule;
  1442. end;